You can have an anonymous sequence of symbols or set of alternatives, simply by enclosing them in parentheses. The implementation declares a dummy nonterminal for such groups, and replaces the group with the name of the dummy non-terminal.
You can also apply the postfix operators "*", "+" and "?" to any symbol or group. Curly brackets "{" .. "}" can also be used and are equivalent to ( .. ) *. Note you can't use [..] notation for optional constructions, since this conflicts with the use of [] for type subscripts.
Note: although it makes sense, at present anonymous nonterminal specifications can't contain names or client code.
Note: restriction: at present each dummy is distinct, so any anonymous expression occuring more than once will lead to a reduce/reduce conflict.
Note: restriction: all the anonymous symbols must have attributes.
1: #line 5578 "./lpsrc/flx_tutorial.pak" 2: //Check parser generator 3: #import <flx.flxh> 4: 5: // the input string 6: data := "1+22+33$"; 7: 8: // a type for tokens 9: union token_t = 10: | TOK_EOF 11: | TOK_PLUS 12: | TOK_INT of int 13: ; 14: 15: // a token stream generator 16: var i = 0; 17: fun get_token():token_t = 18: { 19: ch := data.[i to i+1]; 20: ++i; 21: tok := 22: match ch with 23: | "$" => TOK_EOF 24: | "+" => TOK_PLUS 25: | "1" => TOK_INT 1 26: | "2" => TOK_INT 2 27: | "3" => TOK_INT 3 28: endmatch 29: ; 30: return tok; 31: } 32: 33: // a type for expression terms 34: union expr_t = 35: | Integr of int 36: ; 37: 38: // a grammar for expressions 39: nonterm eexpr : expr_t = 40: | xx:eexpr TOK_PLUS y:TOK_INT+ => 41: match xx with 42: | Integr ?i => let case 1 (?j,_) = y in Integr (i+j) 43: endmatch 44: 45: | y:TOK_INT => Integr y 46: ; 47: 48: // a parser for our example 49: var z : 1 + int = 50: parse (the get_token) with 51: | e: eexpr => match e with | Integr ?i => i endmatch 52: endmatch 53: ; 54: 55: // print the result 56: match z with 57: | case 0 => { print "Error"; } 58: | case 1 (?i) => { print i; } 59: endmatch; 60: endl;
1: 6