# Rustlr Grammar for parsing .y source files, converts grammar to Rust form auto lifetime 'lt # symbol table keeps trackof terminals and nonterminals not # defined in the yacc_decl section. $pub use std::collections::{HashSet,BTreeSet}; $#[derive(Default,Debug)] $pub struct symbol_table<'t> { $ pub lexterminals : HashSet<&'t str>, $ pub nonterminals : BTreeSet<&'t str>, $ pub topsym : &'t str, $ pub skip: bool, $} externtype symbol_table<'lt> #lexattribute skip_set("%%","EOF") lexconditional self.shared_state.borrow().skip ~ self.stk.skip_set("","$_RREOF_$"); lexattribute add_custom("literal",r"^'.'") lexattribute add_custom("%type",r"^%type") lexattribute add_custom("%token",r"^%token") lexattribute add_custom("%left",r"^%left") lexattribute add_custom("%right",r"^%right") lexattribute add_custom("%nonassoc",r"^%nonassoc") lexattribute add_custom("%start",r"^%start") #lexattribute add_custom("decls",r"^(?m)^%\{(?s).*%\}$") lexattribute add_custom("decls",r"^(?m)^%\{(?s)[^%\}]*%\}") lexattribute add_custom("action",r"^\{[^\}]*\}") valueterminal ACTION ~ &'lt str ~ Custom("action",d) ~ d valueterminal ADDITIONALS ~ &'lt str~ Skipto(d) ~ d valueterminal RAWDECL ~ &'lt str ~ Custom("decls",d) ~ &d.trim()[2..d.len()-2] valueterminal ID ~ &'lt str ~ Alphanum(n) ~ n valueterminal LEXCHAR ~ &'lt str ~ Custom("literal",d)~ d[1..d.len()-1].trim() valueterminal LEXSTR ~ &'lt str ~ Strlit(d)~ d[1..d.len()-1].trim() valueterminal NUMBER ~ u32 ~ Num(n) ~ n as u32 valueterminal PERTYPE ~ () ~ Custom("%type",_) ~ () valueterminal PERTOKEN ~ () ~ Custom("%token",_) ~ () valueterminal PERLEFT ~ () ~ Custom("%left",_) ~ () valueterminal PERRIGHT ~ () ~ Custom("%right",_) ~ () valueterminal PERNONASSOC ~ () ~ Custom("%nonassoc",_) ~ () valueterminal PERSTART ~ () ~ Custom("%start",_) ~ () lexterminal PERPERCENT %% #lexterminal LBRACE { #lexterminal RBRACE } lexterminal LPAREN ( lexterminal RPAREN ) lexterminal LBRACK [ lexterminal RBRACK ] lexterminal LANGLE < lexterminal RANGLE > lexterminal PERCENT % lexterminal COLON : lexterminal SEMICOLON ; lexterminal COMMA , lexterminal BAR | lexterminal STAR * lexterminal PLUS + lexterminal QUEST ? lexterminal PERLBRACK %{ lexterminal PERRBRACK %} lexterminal AT @ lexterminal DOLLAR $ lexterminal TWODOLLARS $$ lexterminal DASH - terminals union nonterminals yacc_decl Yacc grammar_rules rhs_symbol rhs label tag idnum nonterminal primary nonterminal rhsunit flatten tag resynch SEMICOLON BAR topsym Yacc primary ==> RAWDECL?:raw_declarations yacc_decl+:yacc_declarations PERPERCENT grammar_rules+:rules { parser.shared_state.borrow_mut().skip = true; ... } <== Yacc --> (PERCENT ID DASH ID)? primary PERPERCENT? ADDITIONALS? #rawdecls --> RAWDECL yacc_decl:terminals --> PERTOKEN idnum+ yacc_decl:lexterminal --> PERTOKEN ID LEXSTR yacc_decl:topsym --> PERSTART ID:s { parser.shared_state.borrow_mut().topsym=s; ... } yacc_decl:left --> PERLEFT idnum+:vs yacc_decl:right --> PERRIGHT idnum+:vs yacc_decl:nonassoc --> PERNONASSOC idnum+:vs yacc_decl:uniondec --> PERCENT union ACTION yacc_decl:nonterminal --> PERTYPE tag ID+ tag --> (LANGLE ID RANGLE)? idnum --> ID NUMBER? rhs_symbol:ID --> ID (COLON label)? rhs_symbol:LEXCHAR ==> LEXCHAR:t { parser.shared_state.borrow_mut().lexterminals.insert(t); ... } <== rhs_symbol:LEXSTR ==> LEXSTR:t { parser.shared_state.borrow_mut().lexterminals.insert(t); ... } <== label:simple --> ID label:boxed --> LBRACK ID RBRACK label:parened --> LPAREN ID COMMA? RPAREN rhsunit --> ACTION? rhs_symbol rhs --> rhsunit* ACTION? # represents one set of rules separated by |: grammar_rules ==> ID:lhs COLON rhs:rhsides SEMICOLON { let mut symtable =parser.shared_state.borrow_mut(); symtable.nonterminals.insert(lhs); if symtable.topsym.len()==0 {symtable.topsym=lhs;} ... } <== EOF #valueterminal declarations~ &'lt str~ Custom("decls",d) &d[2..d.len()-2] println!("SHARED STATE: {}",*self.shared_state.borrow()); println!("GOT TOKEN: {:?}",&token);