%include { /** @brief Lemon parser grammar for Turtle. * * The `lemon' parser generator executable must be in your PATH: * https://sqlite.org/src/doc/trunk/doc/lemon.html * * TTL EBNF: https://www.w3.org/TeamSubmission/turtle/#sec-grammar-grammar */ #include "volksdata/codec.h" } %name TTLParse %stack_overflow { log_error ("Stack oveflow in TTL parsing."); state->rc = VOLK_MEM_ERR; } %parse_failure { log_error ("TTL parse error. Cannot continue."); state->rc = VOLK_PARSE_ERR; } %syntax_error { // Fail immediately on first error. yy_parse_failed (yypParser); } //%stack_size 1024 %token_prefix "T_" %token_type { char * } %token_destructor { (void) state; free ($$); } %default_type { char * } %extra_argument { VOLK_TTLParserState *state } // Low- to high-priority. %left PERIOD . %left SEMICOLON . %left COMMA . %left STRING INTEGER DOUBLE DECIMAL BOOLEAN QNAME BNODE_ID IRIREF . %nonassoc LANGTAG PREFIX . %nonassoc COLON . /* * Rules. */ turtleDoc ::= statements EOF . statements ::= statements statement . statements ::= . statement ::= prefixID . statement ::= base . statement ::= triples . statement ::= WS . prefixID ::= PREFIX(P) WS IRIREF(N) PERIOD . { VOLK_nsmap_add (P, N); free (P); free (N); } base ::= BASE WS IRIREF(D) PERIOD . { VOLK_term_free (state->base); state->base = VOLK_iriref_new (D); free (D); } triples ::= subject(S) ows predObjList(L) PERIOD . { size_t ct = VOLK_graph_add_link_map (state->it, L); state->ct += ct; state->rc = VOLK_OK; LOG_TRACE("Added %lu triples.", ct); VOLK_term_free (S); VOLK_link_map_free (L); } triples ::= subject(S) ows predObjList(L) SEMICOLON PERIOD . [PERIOD] { size_t ct = VOLK_graph_add_link_map (state->it, L); state->ct += ct; state->rc = VOLK_OK; LOG_TRACE("Added %lu triples.", ct); VOLK_term_free (S); VOLK_link_map_free (L); } %type predObjList { VOLK_LinkMap * } %destructor predObjList { VOLK_link_map_free ($$); } predObjList(A) ::= predicate(P) ows objectList(O) . [SEMICOLON] { A = VOLK_link_map_new (state->lms, VOLK_LINK_OUTBOUND); VOLK_link_map_add (A, P, O); } predObjList(A) ::= predObjList(L) SEMICOLON predicate(P) ows objectList(O) . { VOLK_link_map_add (L, P, O); A = L; } %type objectList { VOLK_TermSet * } %destructor objectList { VOLK_term_set_free ($$); } objectList(A) ::= objectList(L) COMMA object(O) . { if (VOLK_term_set_add (L, O, NULL) == VOLK_NOACTION) VOLK_term_free (O); A = L; } objectList(A) ::= object(O) . [IRIREF] { A = VOLK_term_set_new(); VOLK_term_set_add (A, O, NULL); } %type subject { VOLK_Term * } %destructor subject { VOLK_term_free ($$); } subject ::= resource(D) . { state->lms = D; } subject ::= blank(D) . { state->lms = D; } %type predicate { VOLK_Term * } %destructor predicate { VOLK_term_free ($$); } predicate ::= resource . predicate(A)::= RDF_TYPE . { A = VOLK_iriref_new_ns ("rdf:type"); } %type object { VOLK_Term * } %destructor object { VOLK_term_free ($$); } object ::= resource . object ::= blank . object ::= literal . %type literal { VOLK_Term * } %destructor literal { VOLK_term_free ($$); } literal(A) ::= STRING(D) . { A = VOLK_literal_new (D, NULL); LOG_TRACE("Created plain literal: \"%s\"", A->data); free (D); } literal(A) ::= STRING(D) LANGTAG(L) . { A = VOLK_lt_literal_new (D, L); LOG_TRACE("Created LT-literal: \"%s\"@%s", A->data, A->lang); free (D); free (L); } literal(A) ::= STRING(D) DTYPE_MARKER resource(M) . { A = VOLK_literal_new (D, M); LOG_TRACE( "Created DT-literal: \"%s\"^^%s", A->data, A->datatype); free (D); } literal(A) ::= INTEGER(D) . { A = VOLK_literal_new (D, VOLK_iriref_new_ns ("xsd:integer")); free (D); } literal(A) ::= DOUBLE(D) . { A = VOLK_literal_new (D, VOLK_iriref_new_ns ("xsd:double")); free (D); } literal(A) ::= DECIMAL(D) . { A = VOLK_literal_new (D, VOLK_iriref_new_ns ("xsd:decimal")); free (D); } literal(A) ::= BOOLEAN(D) . { A = VOLK_literal_new (D, VOLK_iriref_new_ns ("xsd:boolean")); free (D); } %type blank { VOLK_Term * } %destructor blank { VOLK_term_free ($$); } blank(A) ::= BNODE_ID(D) . { A = VOLK_bnode_new (D); LOG_TRACE("Created blank node: _:%s", A->data); free (D); } blank(A) ::= LBRACKET RBRACKET . [BNODE_ID] { A = VOLK_bnode_new (NULL); LOG_TRACE("Created empty list BN: _:%s", A->data); } blank(A) ::= LBRACKET predObjList(L) RBRACKET . [BNODE_ID] { A = VOLK_bnode_new (NULL); state->lms = A; state->ct += VOLK_graph_add_link_map (state->it, L); LOG_TRACE("Created list BN: _:%s", A->data); VOLK_link_map_free (L); } blank ::= collection . [BNODE_ID] blank(A) ::= LPAREN RPAREN . [BNODE_ID] { A = VOLK_iriref_new_ns ("rdf:nil"); LOG_TRACE("Created list terminator: %s", A->data); } // "collection" is the subject of the first collection item. %type collection { VOLK_Term * } %destructor collection { VOLK_term_free ($$); } // Collection triples are added here to the graph. collection(A) ::= LPAREN itemList(L) RPAREN . { A = VOLK_bnode_add_collection (state->it, L); VOLK_term_set_free (L); } %type itemList { VOLK_TermSet * } %destructor itemList { VOLK_term_set_free ($$); } itemList(A) ::= itemList(L) ows object(O) . { if (VOLK_term_set_add (L, O, NULL) == VOLK_NOACTION) VOLK_term_free (O); A = L; } itemList(A) ::= object(O) . { A = VOLK_term_set_new (); VOLK_term_set_add (A, O, NULL); } %type resource { VOLK_Term * } %destructor resource { VOLK_term_free ($$); } resource(A) ::= IRIREF(D) . { VOLK_Term *rel_iri = VOLK_iriref_new (D); free (D); if (state->base) { A = VOLK_iriref_new_abs (rel_iri, state->base); VOLK_term_free (rel_iri); } else { A = rel_iri; } LOG_TRACE("Created IRI: <%s>", A->data); } resource(A) ::= QNAME(D) . { A = VOLK_iriref_new_ns (D); LOG_TRACE("Created IRI: %s", A->data); free (D); } ows ::= WS . ows ::= .