Document : exprs? | document_with_tag document_with_tag : 'Document' '(' expr? ')' | decl document_with_tag | meta document_with_tag meta : '(*' iri expr '*)' | '(*' expr '*)' # in code: decide if it's really the iri decl : 'Base' '(' iri ')' | 'Import' '(' iri ')' | 'Import' '(' iri expr ')' | 'Include' '(' iri ')' | 'Prefix' '(' bare_word iri ')' | 'Alias' '(' bare_word iri ')' | 'Local' '(' bare_word* ')' expr : meta expr %prec META # highest precedence | decl expr %prec DECL # precedence doesnt matter | SPACE_LPAREN expr ')' | 'Group' '(' exprs? ')' | 'External' '(' frame ')' | 'External' '(' atomic ')' | 'Forall' new_scope new_var+ '(' expr ')' pop_scope | 'Exists' new_scope new_var+ '(' expr ')' pop_scope | declared_var | const | 'True' # stands for rif:And() | 'False' # stands for rif:Or() | expr 'And' expr # in code: gather into rif:And(...) | expr 'Or' expr # in code: gather into rif:Or(...) | 'And(' exprs ')' | 'Or(' exprs ')' | 'Neg' expr | 'Naf' expr | expr ':-' expr | expr '=>' expr | 'If' expr 'Then' expr | expr '=' expr | expr '<' expr | expr '<=' expr | expr '>' expr | expr '>=' expr | expr '#' expr | expr 'InstanceOf' expr | expr '##' expr | expr 'SubclassOf' expr | expr '+' expr | expr '-' expr | expr '*' expr | expr '/' expr | frame | atomic | n3block # we could do this if not for n3block, and the iri in meta # ... either as anon frame, or as in n3, or as in prolog # | '[' args? ']' iri : ANGLEBRACKIRI | BARE_IRI # in code: might really be a CURIE frame : expr '[' frame_args? ']' atomic : expr NOSPACE_LPAREN args? ')' | expr NOSPACE_LPAREN Name_arrow_expr+ ')' lparen : 'hack-space-lparen' | 'hack-nospace-lparen' ################################################################ # # n3/turtle embedded here... Mostly just to see if we can. # # I'm not sure this buys us anything, really; they're so close # to frames, and it's not exactly n3 anyway (no lists or [expr]s) # n3block : '{' triples? '}' triples : triple | triples "." triple triple : subject pvpairs pvpairs : property values | pvpairs ";" property values values : value | values "," value subject : expr property : expr value : expr ################################################################ # # Various sequences of expressions. This is where we could enforce that # expr's be delimited # exprs : expr | exprs ';' expr | exprs expr # no delimiter args : expr | args ',' expr | args expr # no delimiter frame_args : expr '->' expr | frame_args ',' expr '->' expr | frame_args expr '->' expr # no delimiter ################################################################ # # Constants # const : STRING_HAT_HAT iri | constshort constshort : STRING | INTEGER | DECIMAL | LOCAL | iri new_scope : EMPTY pop_scope : EMPTY new_var : bare_word # in code: add to declared variables declared_var : VARNAME # "bare_word" is a special token requiring a different state for the # lexer -- it matches words, even keywords, and just returns the text # of the word. # The logic here is designed to allow new keywords to be added to the # language later without breaking existing documents. Specifically, # we read a bare_word, then add it to the proper token list (vars, # aliases, prefixes, etc) and the lexer will recognize it as that # instead of as a keyword. You can't use the new keyword in such a # document without renaming the item, but at least the semantics # didn't change under you. # For details on this kind of lexer trick, see PLY documentation # example with new_scope, push_scope()/pop_scope() (or nearly any C # parser) bare_word : begin_accept_bare_word BARE_WORD end_accept_bare_word begin_accept_bare_word : EMPTY end_accept_bare_word : EMPTY # NAME_ARROW is a ... # # oh, we don't need this, just make arrow be an infix operator which makes # a "tagged expression", which is suitable for use as an argument... yes? # # ... except this way, the lexer knows not to do keyword recognition before # the left arrow. # Name_arrow_expr : NAME_ARROW expr | NAME_ARROW expr "," # BEGIN LEX PYTHON # END LEX PYTHON # BEGIN YACC PYTHON # END YACC PYTHON