jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/000775 000000 000000 00000000000 12652507276 017360 5ustar00rootroot000000 000000 jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/.gitignore000664 000000 000000 00000000125 12652507276 021346 0ustar00rootroot000000 000000 .DS_Store node_modules # Editor backup files *.bak *~ web/content/assets/js/jison.jsjison-9f2f188419f7790a46a5e9a6c882834d0fa16314/.npmignore000664 000000 000000 00000000032 12652507276 021352 0ustar00rootroot000000 000000 src/ web/ examples/ ports/jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/.travis.yml000664 000000 000000 00000000044 12652507276 021467 0ustar00rootroot000000 000000 language: node_js node_js: - 0.10 jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/CONTRIBUTING.md000664 000000 000000 00000001017 12652507276 021610 0ustar00rootroot000000 000000 Contributing to Jison ======= Fork, make your changes, run tests and/or add tests then send a pull request. ## Running tests Prerequesites: `node` and `npm`. First run: npm install Then run tests with: make test ## Building the site To build the site, as well as the Browserified web version of Jison, run: make site Then you can also preview the site by doing: make preview Note that you will need `nanoc` and `adsf` in order to build/preview the site. `gem install` them if you haven't. jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/Makefile000664 000000 000000 00000000736 12652507276 021026 0ustar00rootroot000000 000000 all: test site: ./node_modules/.bin/browserify entry.js --exports require | ./node_modules/.bin/uglifyjs > web/content/assets/js/jison.js cd web/ && nanoc compile cp -r examples web/output/jison/ preview: cd web/ && nanoc view & open http://localhost:3000/jison/ deploy: rm -r ../pages/jison/* cp -r web/output/jison/* ../pages/jison/ cd ../pages/jison && git add . && git commit -m 'Deploy site updates' && git push origin gh-pages test: node tests/all-tests.js jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/README.md000664 000000 000000 00000011650 12652507276 020642 0ustar00rootroot000000 000000 Jison ===== * [issues](http://github.com/zaach/jison/issues) * [discuss](mailto:jison@librelist.com) [![build status](https://secure.travis-ci.org/zaach/jison.png)](http://travis-ci.org/zaach/jison) An API for creating parsers in JavaScript ----------------------------------------- Jison generates bottom-up parsers in JavaScript. Its API is similar to Bison's, hence the name. It supports many of Bison's major features, plus some of its own. If you are new to parser generators such as Bison, and Context-free Grammars in general, a [good introduction][1] is found in the Bison manual. If you already know Bison, Jison should be easy to pickup. Briefly, Jison takes a JSON encoded grammar or Bison style grammar and outputs a JavaScript file capable of parsing the language described by that grammar. You can then use the generated script to parse inputs and accept, reject, or perform actions based on the input. Installation ------------ Jison can be installed for [Node](http://nodejs.org) using [`npm`](http://github.com/isaacs/npm/) Using npm: npm install jison -g Usage from the command line ----------------------- Clone the github repository for examples: git clone git://github.com/zaach/jison.git cd jison/examples Now you're ready to generate some parsers: jison calculator.jison This will generate `calculator.js` in your current working directory. This file can be used to parse an input file, like so: echo "2^32 / 1024" > testcalc node calculator.js testcalc This will print out `4194304`. Full cli option list: Usage: jison [file] [lexfile] [options] file file containing a grammar lexfile file containing a lexical grammar Options: -j, --json force jison to expect a grammar in JSON format -o FILE, --outfile FILE Filename and base module name of the generated parser -t, --debug Debug mode -m TYPE, --module-type TYPE The type of module to generate (commonjs, amd, js) -p TYPE, --parser-type TYPE The type of algorithm to use for the parser (lr0, slr, lalr, lr) -V, --version print version and exit Usage from a CommonJS module -------------------------- You can generate parsers programatically from JavaScript as well. Assuming Jison is in your commonjs environment's load path: // mygenerator.js var Parser = require("jison").Parser; // a grammar in JSON var grammar = { "lex": { "rules": [ ["\\s+", "/* skip whitespace */"], ["[a-f0-9]+", "return 'HEX';"] ] }, "bnf": { "hex_strings" :[ "hex_strings HEX", "HEX" ] } }; // `grammar` can also be a string that uses jison's grammar format var parser = new Parser(grammar); // generate source, ready to be written to disk var parserSource = parser.generate(); // you can also use the parser directly from memory // returns true parser.parse("adfe34bc e82a"); // throws lexical error parser.parse("adfe34bc zxg"); More Documentation ------------------ For more information on creating grammars and using the generated parsers, read the [documentation](http://jison.org/docs). How to contribute ----------------- See [CONTRIBUTING.md](https://github.com/zaach/jison/blob/master/CONTRIBUTING.md) for contribution guidelines, how to run the tests, etc. Projects using Jison ------------------ View them on the [wiki](https://github.com/zaach/jison/wiki/ProjectsUsingJison), or add your own. Contributors ------------ [Githubbers](http://github.com/zaach/jison/contributors) Special thanks to Jarred Ligatti, Manuel E. Bermúdez License ------- > Copyright (c) 2009-2014 Zachary Carter > > Permission is hereby granted, free of > charge, to any person obtaining a > copy of this software and associated > documentation files (the "Software"), > to deal in the Software without > restriction, including without > limitation the rights to use, copy, > modify, merge, publish, distribute, > sublicense, and/or sell copies of the > Software, and to permit persons to > whom the Software is furnished to do > so, subject to the following > conditions: > > The above copyright notice and this > permission notice shall be included > in all copies or substantial portions > of the Software. > > THE SOFTWARE IS PROVIDED "AS IS", > WITHOUT WARRANTY OF ANY KIND, EXPRESS > OR IMPLIED, INCLUDING BUT NOT LIMITED > TO THE WARRANTIES OF MERCHANTABILITY, > FITNESS FOR A PARTICULAR PURPOSE AND > NONINFRINGEMENT. IN NO EVENT SHALL THE > AUTHORS OR COPYRIGHT HOLDERS BE > LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > LIABILITY, WHETHER IN AN ACTION OF > CONTRACT, TORT OR OTHERWISE, ARISING > FROM, OUT OF OR IN CONNECTION WITH THE > SOFTWARE OR THE USE OR OTHER DEALINGS > IN THE SOFTWARE. [1]: http://dinosaur.compilertools.net/bison/bison_4.html jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/entry.js000664 000000 000000 00000000102 12652507276 021050 0ustar00rootroot000000 000000 Jison = require('./lib/jison.js'); bnf = require('ebnf-parser'); jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/examples/000775 000000 000000 00000000000 12652507276 021176 5ustar00rootroot000000 000000 jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/examples/README000664 000000 000000 00000000136 12652507276 022056 0ustar00rootroot000000 000000 Use Jison to generate parsers from an example, e.g.: $ node ../lib/cli.js basic_lex.jison jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/examples/ansic.jison000664 000000 000000 00000017656 12652507276 023356 0ustar00rootroot000000 000000 %token IDENTIFIER CONSTANT STRING_LITERAL SIZEOF %token PTR_OP INC_OP DEC_OP LEFT_OP RIGHT_OP LE_OP GE_OP EQ_OP NE_OP %token AND_OP OR_OP MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN %token SUB_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN %token XOR_ASSIGN OR_ASSIGN TYPE_NAME %token TYPEDEF EXTERN STATIC AUTO REGISTER %token CHAR SHORT INT LONG SIGNED UNSIGNED FLOAT DOUBLE CONST VOLATILE VOID %token STRUCT UNION ENUM ELLIPSIS %token CASE DEFAULT IF ELSE SWITCH WHILE DO FOR GOTO CONTINUE BREAK RETURN %nonassoc IF_WITHOUT_ELSE %nonassoc ELSE %start translation_unit %% primary_expression : IDENTIFIER | CONSTANT | STRING_LITERAL | '(' expression ')' ; postfix_expression : primary_expression | postfix_expression '[' expression ']' | postfix_expression '(' ')' | postfix_expression '(' argument_expression_list ')' | postfix_expression '.' IDENTIFIER | postfix_expression PTR_OP IDENTIFIER | postfix_expression INC_OP | postfix_expression DEC_OP ; argument_expression_list : assignment_expression | argument_expression_list ',' assignment_expression ; unary_expression : postfix_expression | INC_OP unary_expression | DEC_OP unary_expression | unary_operator cast_expression | SIZEOF unary_expression | SIZEOF '(' type_name ')' ; unary_operator : '&' | '*' | '+' | '-' | '~' | '!' ; cast_expression : unary_expression | '(' type_name ')' cast_expression ; multiplicative_expression : cast_expression | multiplicative_expression '*' cast_expression | multiplicative_expression '/' cast_expression | multiplicative_expression '%' cast_expression ; additive_expression : multiplicative_expression | additive_expression '+' multiplicative_expression | additive_expression '-' multiplicative_expression ; shift_expression : additive_expression | shift_expression LEFT_OP additive_expression | shift_expression RIGHT_OP additive_expression ; relational_expression : shift_expression | relational_expression '<' shift_expression | relational_expression '>' shift_expression | relational_expression LE_OP shift_expression | relational_expression GE_OP shift_expression ; equality_expression : relational_expression | equality_expression EQ_OP relational_expression | equality_expression NE_OP relational_expression ; and_expression : equality_expression | and_expression '&' equality_expression ; exclusive_or_expression : and_expression | exclusive_or_expression '^' and_expression ; inclusive_or_expression : exclusive_or_expression | inclusive_or_expression '|' exclusive_or_expression ; logical_and_expression : inclusive_or_expression | logical_and_expression AND_OP inclusive_or_expression ; logical_or_expression : logical_and_expression | logical_or_expression OR_OP logical_and_expression ; conditional_expression : logical_or_expression | logical_or_expression '?' expression ':' conditional_expression ; assignment_expression : conditional_expression | unary_expression assignment_operator assignment_expression ; assignment_operator : '=' | MUL_ASSIGN | DIV_ASSIGN | MOD_ASSIGN | ADD_ASSIGN | SUB_ASSIGN | LEFT_ASSIGN | RIGHT_ASSIGN | AND_ASSIGN | XOR_ASSIGN | OR_ASSIGN ; expression : assignment_expression | expression ',' assignment_expression ; constant_expression : conditional_expression ; declaration : declaration_specifiers ';' | declaration_specifiers init_declarator_list ';' ; declaration_specifiers : storage_class_specifier | storage_class_specifier declaration_specifiers | type_specifier | type_specifier declaration_specifiers | type_qualifier | type_qualifier declaration_specifiers ; init_declarator_list : init_declarator | init_declarator_list ',' init_declarator ; init_declarator : declarator | declarator '=' initializer ; storage_class_specifier : TYPEDEF | EXTERN | STATIC | AUTO | REGISTER ; type_specifier : VOID | CHAR | SHORT | INT | LONG | FLOAT | DOUBLE | SIGNED | UNSIGNED | struct_or_union_specifier | enum_specifier | TYPE_NAME ; struct_or_union_specifier : struct_or_union IDENTIFIER '{' struct_declaration_list '}' | struct_or_union '{' struct_declaration_list '}' | struct_or_union IDENTIFIER ; struct_or_union : STRUCT | UNION ; struct_declaration_list : struct_declaration | struct_declaration_list struct_declaration ; struct_declaration : specifier_qualifier_list struct_declarator_list ';' ; specifier_qualifier_list : type_specifier specifier_qualifier_list | type_specifier | type_qualifier specifier_qualifier_list | type_qualifier ; struct_declarator_list : struct_declarator | struct_declarator_list ',' struct_declarator ; struct_declarator : declarator | ':' constant_expression | declarator ':' constant_expression ; enum_specifier : ENUM '{' enumerator_list '}' | ENUM IDENTIFIER '{' enumerator_list '}' | ENUM IDENTIFIER ; enumerator_list : enumerator | enumerator_list ',' enumerator ; enumerator : IDENTIFIER | IDENTIFIER '=' constant_expression ; type_qualifier : CONST | VOLATILE ; declarator : pointer direct_declarator | direct_declarator ; direct_declarator : IDENTIFIER | '(' declarator ')' | direct_declarator '[' constant_expression ']' | direct_declarator '[' ']' | direct_declarator '(' parameter_type_list ')' | direct_declarator '(' identifier_list ')' | direct_declarator '(' ')' ; pointer : '*' | '*' type_qualifier_list | '*' pointer | '*' type_qualifier_list pointer ; type_qualifier_list : type_qualifier | type_qualifier_list type_qualifier ; parameter_type_list : parameter_list | parameter_list ',' ELLIPSIS ; parameter_list : parameter_declaration | parameter_list ',' parameter_declaration ; parameter_declaration : declaration_specifiers declarator | declaration_specifiers abstract_declarator | declaration_specifiers ; identifier_list : IDENTIFIER | identifier_list ',' IDENTIFIER ; type_name : specifier_qualifier_list | specifier_qualifier_list abstract_declarator ; abstract_declarator : pointer | direct_abstract_declarator | pointer direct_abstract_declarator ; direct_abstract_declarator : '(' abstract_declarator ')' | '[' ']' | '[' constant_expression ']' | direct_abstract_declarator '[' ']' | direct_abstract_declarator '[' constant_expression ']' | '(' ')' | '(' parameter_type_list ')' | direct_abstract_declarator '(' ')' | direct_abstract_declarator '(' parameter_type_list ')' ; initializer : assignment_expression | '{' initializer_list '}' | '{' initializer_list ',' '}' ; initializer_list : initializer | initializer_list ',' initializer ; statement : labeled_statement | compound_statement | expression_statement | selection_statement | iteration_statement | jump_statement ; labeled_statement : IDENTIFIER ':' statement | CASE constant_expression ':' statement | DEFAULT ':' statement ; compound_statement : '{' '}' | '{' statement_list '}' | '{' declaration_list '}' | '{' declaration_list statement_list '}' ; declaration_list : declaration | declaration_list declaration ; statement_list : statement | statement_list statement ; expression_statement : ';' | expression ';' ; selection_statement : IF '(' expression ')' statement %prec IF_WITHOUT_ELSE | IF '(' expression ')' statement ELSE statement | SWITCH '(' expression ')' statement ; iteration_statement : WHILE '(' expression ')' statement | DO statement WHILE '(' expression ')' ';' | FOR '(' expression_statement expression_statement ')' statement | FOR '(' expression_statement expression_statement expression ')' statement ; jump_statement : GOTO IDENTIFIER ';' | CONTINUE ';' | BREAK ';' | RETURN ';' | RETURN expression ';' ; translation_unit : external_declaration | translation_unit external_declaration ; external_declaration : function_definition | declaration ; function_definition : declaration_specifiers declarator declaration_list compound_statement | declaration_specifiers declarator compound_statement | declarator declaration_list compound_statement | declarator compound_statement ; jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/examples/basic.jison000664 000000 000000 00000000070 12652507276 023320 0ustar00rootroot000000 000000 %% E : E PLUS T | T ; T : ZERO ; jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/examples/basic2.jison000664 000000 000000 00000000151 12652507276 023402 0ustar00rootroot000000 000000 /* description: Basic grammar that contains a nullable A nonterminal. */ %% A : A x | ; jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/examples/basic2_lex.jison000664 000000 000000 00000000267 12652507276 024262 0ustar00rootroot000000 000000 /* description: Basic grammar that contains a nullable A nonterminal. */ %lex %% \s+ {/* skip whitespace */} "x" {return 'x';} /lex %% A : A x | ; jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/examples/basic_lex.jison000664 000000 000000 00000000243 12652507276 024172 0ustar00rootroot000000 000000 %lex %% \s+ {/* skip whitespace */} [0-9]+ {return 'NAT';} "+" {return '+';} /lex %% E : E '+' T | T ; T : NAT ; jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/examples/calculator.jison000664 000000 000000 00000002651 12652507276 024377 0ustar00rootroot000000 000000 /* description: Parses and executes mathematical expressions. */ /* lexical grammar */ %lex %% \s+ /* skip whitespace */ [0-9]+("."[0-9]+)?\b return 'NUMBER' "*" return '*' "/" return '/' "-" return '-' "+" return '+' "^" return '^' "!" return '!' "%" return '%' "(" return '(' ")" return ')' "PI" return 'PI' "E" return 'E' <> return 'EOF' . return 'INVALID' /lex /* operator associations and precedence */ %left '+' '-' %left '*' '/' %left '^' %right '!' %right '%' %left UMINUS %start expressions %% /* language grammar */ expressions : e EOF { typeof console !== 'undefined' ? console.log($1) : print($1); return $1; } ; e : e '+' e {$$ = $1+$3;} | e '-' e {$$ = $1-$3;} | e '*' e {$$ = $1*$3;} | e '/' e {$$ = $1/$3;} | e '^' e {$$ = Math.pow($1, $3);} | e '!' {{ $$ = (function fact (n) { return n==0 ? 1 : fact(n-1) * n })($1); }} | e '%' {$$ = $1/100;} | '-' e %prec UMINUS {$$ = -$2;} | '(' e ')' {$$ = $2;} | NUMBER {$$ = Number(yytext);} | E {$$ = Math.E;} | PI {$$ = Math.PI;} ; jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/examples/calculator.json000664 000000 000000 00000003154 12652507276 024225 0ustar00rootroot000000 000000 { "comment": "JSON Math Parser", // JavaScript comments also work "lex": { "rules": [ ["\\s+", "/* skip whitespace */"], ["[0-9]+(?:\\.[0-9]+)?\\b", "return 'NUMBER'"], ["\\*", "return '*'"], ["\\/", "return '/'"], ["-", "return '-'"], ["\\+", "return '+'"], ["\\^", "return '^'"], ["!", "return '!'"], ["%", "return '%'"], ["\\(", "return '('"], ["\\)", "return ')'"], ["PI\\b", "return 'PI'"], ["E\\b", "return 'E'"], ["$", "return 'EOF'"] ] }, "operators": [ ["left", "+", "-"], ["left", "*", "/"], ["left", "^"], ["right", "!"], ["right", "%"], ["left", "UMINUS"] ], "bnf": { "expressions": [["e EOF", "return $1"]], "e" :[ ["e + e", "$$ = $1+$3"], ["e - e", "$$ = $1-$3"], ["e * e", "$$ = $1*$3"], ["e / e", "$$ = $1/$3"], ["e ^ e", "$$ = Math.pow($1, $3)"], ["e !", "$$ = (function(n) {if(n==0) return 1; return arguments.callee(n-1) * n})($1)"], ["e %", "$$ = $1/100"], ["- e", "$$ = -$2", {"prec": "UMINUS"}], ["( e )", "$$ = $2"], ["NUMBER", "$$ = Number(yytext)"], ["E", "$$ = Math.E"], ["PI", "$$ = Math.PI"] ] } } jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/examples/classy.jison000664 000000 000000 00000002174 12652507276 023544 0ustar00rootroot000000 000000 /* description: ClassyLang grammar. Very classy. */ /* To build parser: $ ./bin/jison examples/classy.jison examples/classy.jisonlex */ /* author: Zach Carter */ %right ASSIGN %left OR %nonassoc EQUALITY GREATER %left PLUS MINUS %left TIMES %right NOT %left DOT %% pgm : cdl MAIN LBRACE vdl el RBRACE ENDOFFILE ; cdl : c cdl | ; c : CLASS id EXTENDS id LBRACE vdl mdl RBRACE ; vdl : VAR t id SEMICOLON vdl | ; mdl : t id LPAREN t id RPAREN LBRACE vdl el RBRACE mdl | ; t : NATTYPE | id ; id : ID ; el : e SEMICOLON el | e SEMICOLON ; e : NATLITERAL | NUL | id | NEW id | THIS | IF LPAREN e RPAREN LBRACE el RBRACE ELSE LBRACE el RBRACE | FOR LPAREN e SEMICOLON e SEMICOLON e RPAREN LBRACE el RBRACE | READNAT LPAREN RPAREN | PRINTNAT LPAREN e RPAREN | e PLUS e | e MINUS e | e TIMES e | e EQUALITY e | e GREATER e | NOT e | e OR e | e DOT id | id ASSIGN e | e DOT id ASSIGN e | id LPAREN e RPAREN | e DOT id LPAREN e RPAREN | LPAREN e RPAREN ; jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/examples/classy.jisonlex000664 000000 000000 00000003042 12652507276 024250 0ustar00rootroot000000 000000 digit [0-9] id [a-zA-Z][a-zA-Z0-9]* %% "//".* /* ignore comment */ "main" return 'MAIN'; "class" return 'CLASS'; "extends" return 'EXTENDS'; "nat" return 'NATTYPE'; "if" return 'IF'; "else" return 'ELSE'; "for" return 'FOR'; "printNat" return 'PRINTNAT'; "readNat" return 'READNAT'; "this" return 'THIS'; "new" return 'NEW'; "var" return 'VAR'; "null" return 'NUL'; {digit}+ return 'NATLITERAL'; {id} return 'ID'; "==" return 'EQUALITY'; "=" return 'ASSIGN'; "+" return 'PLUS'; "-" return 'MINUS'; "*" return 'TIMES'; ">" return 'GREATER'; "||" return 'OR'; "!" return 'NOT'; "." return 'DOT'; "{" return 'LBRACE'; "}" return 'RBRACE'; "(" return 'LPAREN'; ")" return 'RPAREN'; ";" return 'SEMICOLON'; \s+ /* skip whitespace */ "." throw 'Illegal character'; <> return 'ENDOFFILE'; jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/examples/classy_ast.jison000664 000000 000000 00000005323 12652507276 024412 0ustar00rootroot000000 000000 /* description: ClassyLang grammar with AST-building actions. Very classy. */ /* To build parser: $ ./bin/jison examples/classy_ast.jison examples/classy.jisonlex */ /* author: Zach Carter */ %{ function prependChild(node, child){ node.splice(2,0,child); return node; } %} %right ASSIGN %left OR %nonassoc EQUALITY GREATER %left PLUS MINUS %left TIMES %right NOT %left DOT %% pgm : cdl MAIN LBRACE vdl el RBRACE ENDOFFILE {{$$ = ['PROGRAM',{},$1,$4,$5]; return $$;}} ; cdl : c cdl {$$ = prependChild($2, $1);} | {{$$ = ['CLASS_DECL_LIST',{}];}} ; c : CLASS id EXTENDS id LBRACE vdl mdl RBRACE {{$$ = ['CLASS_DECL',{},$2,$4,$6,$7];}} ; vdl : VAR t id SEMICOLON vdl {{$$ = prependChild($5, ['VAR_DECL',{},$2,$3]);}} | {{$$ = ['VAR_DECL_LIST',{}];}} ; mdl : t id LPAREN t id RPAREN LBRACE vdl el RBRACE mdl {{$$ = prependChild($11, ['METHOD_DECL',{},$1,$2,$4,$5,$8,$9]);}} | {{$$ = ['METHOD_DECL_LIST',{}];}} ; t : NATTYPE {{$$ = ['NAT_TYPE',{}];}} | id {$$ = $1} ; id : ID {{$$ = ['AST_ID',{val:yytext}]}} ; el : e SEMICOLON el {$$ = prependChild($3, $1);} | e SEMICOLON {{$$ = ['EXPR_LIST',{},$1];}} ; e : NATLITERAL {{$$ = ['NAT_LITERAL_EXPR',{val:parseInt(yytext)}];}} | NUL {{$$ = ['NULL_EXPR',{}];}} | id {{$$ = ['ID_EXPR',{},$1];}} | NEW id {{$$ = ['NEW_EXPR',{},$2];}} | THIS {{$$ = ['THIS_EXPR',{}];}} | IF LPAREN e RPAREN LBRACE el RBRACE ELSE LBRACE el RBRACE {{$$ = ['IF_THEN_ELSE_EXPR',{},$3,$6,$10];}} | FOR LPAREN e SEMICOLON e SEMICOLON e RPAREN LBRACE el RBRACE {{$$ = ['FOR_EXPR',{},$3,$5,$7,$10];}} | READNAT LPAREN RPAREN {{$$ = ['READ_EXPR',{}];}} | PRINTNAT LPAREN e RPAREN {{$$ = ['PRINT_EXPR',{},$3];}} | e PLUS e {{$$ = ['PLUS_EXPR',{},$1,$3];}} | e MINUS e {{$$ = ['MINUS_EXPR',{},$1,$3];}} | e TIMES e {{$$ = ['TIMES_EXPR',{},$1,$3];}} | e EQUALITY e {{$$ = ['EQUALITY_EXPR',{},$1,$3];}} | e GREATER e {{$$ = ['GREATER_THAN_EXPR',{},$1,$3];}} | NOT e {{$$ = ['NOT_EXPR',{},$2];}} | e OR e {{$$ = ['OR_EXPR',{},$1,$3];}} | e DOT id {{$$ = ['DOT_ID_EXPR',{},$1,$3];}} | id ASSIGN e {{$$ = ['ASSIGN_EXPR',{},$1,$3];}} | e DOT id ASSIGN e {{$$ = ['DOT_ASSIGN_EXPR',{},$1,$3,$5];}} | id LPAREN e RPAREN {{$$ = ['METHOD_CALL_EXPR',{},$1,$3];}} | e DOT id LPAREN e RPAREN {{$$ = ['DOT_METHOD_CALL_EXPR',{},$1,$3,$5];}} | LPAREN e RPAREN {$$ = $2;} ; jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/examples/classy_test.src000664 000000 000000 00000000114 12652507276 024240 0ustar00rootroot000000 000000 class Chris extends Person { } main { var string cool; printnat(cool); } jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/examples/dism.jison000664 000000 000000 00000000725 12652507276 023202 0ustar00rootroot000000 000000 /* author: Jay Ligatti */ %% pgm : instlist ; instlist : label COLON inst instlist | inst instlist | ; inst : ADD intt intt intt | SUB intt intt intt | MUL intt intt intt | MOV intt intt | LOD intt intt intt | STR intt intt intt | JMP intt intt intt | BEQ intt intt intt | BLT intt intt intt | RDN intt | PTN intt | HLT intt ; label : LABEL ; intt : INT | label ; jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/examples/dism_lr0.jison000664 000000 000000 00000000677 12652507276 023765 0ustar00rootroot000000 000000 /* author: Jay Ligatti */ %% instlist : instlist label COLON inst | instlist inst | inst ; inst : ADD intt intt intt | SUB intt intt intt | MUL intt intt intt | MOV intt intt | LOD intt intt intt | STR intt intt intt | JMP intt intt intt | BEQ intt intt intt | BLT intt intt intt | RDN intt | PTN intt | HLT intt ; label : LABEL ; intt : INT | label ; jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/examples/inherited.y000664 000000 000000 00000001273 12652507276 023346 0ustar00rootroot000000 000000 %lex %% \s+ {} (global|local|integer|float) { return yytext; } [a-zA-Z_]\w* { return 'id'; } . { return yytext; } /lex %% D : C T L ; C : global | local ; T : integer | float ; L : L ',' id { console.log("L -> L ',' id ("+yytext+")"); console.log($id + ' is of type ' + $0); console.log($1 + ' is of class ' + $-1); } | id { console.log("L -> id ("+yytext+")"); console.log($id + ' is of type ' + $0); console.log($1 + ' is of class ' + $-1); } ; %% jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/examples/jscore.jison000664 000000 000000 00000026151 12652507276 023534 0ustar00rootroot000000 000000 /* http://www.opensource.apple.com/source/JavaScriptCore/ */ %start Program %nonassoc IF_WITHOUT_ELSE %nonassoc ELSE %% Literal : NULLTOKEN | TRUETOKEN | FALSETOKEN | NUMBER | STRING | '/' | DIVEQUAL ; Property : IDENT ':' AssignmentExpr | STRING ':' AssignmentExpr | NUMBER ':' AssignmentExpr | IDENT IDENT '(' ')' OPENBRACE FunctionBody CLOSEBRACE | IDENT IDENT '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE ; PropertyList : Property | PropertyList ',' Property ; PrimaryExpr : PrimaryExprNoBrace | OPENBRACE CLOSEBRACE | OPENBRACE PropertyList CLOSEBRACE | OPENBRACE PropertyList ',' CLOSEBRACE ; PrimaryExprNoBrace : THISTOKEN | Literal | ArrayLiteral | IDENT | '(' Expr ')' ; ArrayLiteral : '[' ElisionOpt ']' | '[' ElementList ']' | '[' ElementList ',' ElisionOpt ']' ; ElementList : ElisionOpt AssignmentExpr | ElementList ',' ElisionOpt AssignmentExpr ; ElisionOpt : | Elision ; Elision : ',' | Elision ',' ; MemberExpr : PrimaryExpr | FunctionExpr | MemberExpr '[' Expr ']' | MemberExpr '.' IDENT | NEW MemberExpr Arguments ; MemberExprNoBF : PrimaryExprNoBrace | MemberExprNoBF '[' Expr ']' | MemberExprNoBF '.' IDENT | NEW MemberExpr Arguments ; NewExpr : MemberExpr | NEW NewExpr ; NewExprNoBF : MemberExprNoBF | NEW NewExpr ; CallExpr : MemberExpr Arguments | CallExpr Arguments | CallExpr '[' Expr ']' | CallExpr '.' IDENT ; CallExprNoBF : MemberExprNoBF Arguments | CallExprNoBF Arguments | CallExprNoBF '[' Expr ']' | CallExprNoBF '.' IDENT ; Arguments : '(' ')' | '(' ArgumentList ')' ; ArgumentList : AssignmentExpr | ArgumentList ',' AssignmentExpr ; LeftHandSideExpr : NewExpr | CallExpr ; LeftHandSideExprNoBF : NewExprNoBF | CallExprNoBF ; PostfixExpr : LeftHandSideExpr | LeftHandSideExpr PLUSPLUS | LeftHandSideExpr MINUSMINUS ; PostfixExprNoBF : LeftHandSideExprNoBF | LeftHandSideExprNoBF PLUSPLUS | LeftHandSideExprNoBF MINUSMINUS ; UnaryExprCommon : DELETETOKEN UnaryExpr | VOIDTOKEN UnaryExpr | TYPEOF UnaryExpr | PLUSPLUS UnaryExpr | AUTOPLUSPLUS UnaryExpr | MINUSMINUS UnaryExpr | AUTOMINUSMINUS UnaryExpr | '+' UnaryExpr | '-' UnaryExpr | '~' UnaryExpr | '!' UnaryExpr ; UnaryExpr : PostfixExpr | UnaryExprCommon ; UnaryExprNoBF : PostfixExprNoBF | UnaryExprCommon ; MultiplicativeExpr : UnaryExpr | MultiplicativeExpr '*' UnaryExpr | MultiplicativeExpr '/' UnaryExpr | MultiplicativeExpr '%' UnaryExpr ; MultiplicativeExprNoBF : UnaryExprNoBF | MultiplicativeExprNoBF '*' UnaryExpr | MultiplicativeExprNoBF '/' UnaryExpr | MultiplicativeExprNoBF '%' UnaryExpr ; AdditiveExpr : MultiplicativeExpr | AdditiveExpr '+' MultiplicativeExpr | AdditiveExpr '-' MultiplicativeExpr ; AdditiveExprNoBF : MultiplicativeExprNoBF | AdditiveExprNoBF '+' MultiplicativeExpr | AdditiveExprNoBF '-' MultiplicativeExpr ; ShiftExpr : AdditiveExpr | ShiftExpr LSHIFT AdditiveExpr | ShiftExpr RSHIFT AdditiveExpr | ShiftExpr URSHIFT AdditiveExpr ; ShiftExprNoBF : AdditiveExprNoBF | ShiftExprNoBF LSHIFT AdditiveExpr | ShiftExprNoBF RSHIFT AdditiveExpr | ShiftExprNoBF URSHIFT AdditiveExpr ; RelationalExpr : ShiftExpr | RelationalExpr '<' ShiftExpr | RelationalExpr '>' ShiftExpr | RelationalExpr LE ShiftExpr | RelationalExpr GE ShiftExpr | RelationalExpr INSTANCEOF ShiftExpr | RelationalExpr INTOKEN ShiftExpr ; RelationalExprNoIn : ShiftExpr | RelationalExprNoIn '<' ShiftExpr | RelationalExprNoIn '>' ShiftExpr | RelationalExprNoIn LE ShiftExpr | RelationalExprNoIn GE ShiftExpr | RelationalExprNoIn INSTANCEOF ShiftExpr ; RelationalExprNoBF : ShiftExprNoBF | RelationalExprNoBF '<' ShiftExpr | RelationalExprNoBF '>' ShiftExpr | RelationalExprNoBF LE ShiftExpr | RelationalExprNoBF GE ShiftExpr | RelationalExprNoBF INSTANCEOF ShiftExpr | RelationalExprNoBF INTOKEN ShiftExpr ; EqualityExpr : RelationalExpr | EqualityExpr EQEQ RelationalExpr | EqualityExpr NE RelationalExpr | EqualityExpr STREQ RelationalExpr | EqualityExpr STRNEQ RelationalExpr ; EqualityExprNoIn : RelationalExprNoIn | EqualityExprNoIn EQEQ RelationalExprNoIn | EqualityExprNoIn NE RelationalExprNoIn | EqualityExprNoIn STREQ RelationalExprNoIn | EqualityExprNoIn STRNEQ RelationalExprNoIn ; EqualityExprNoBF : RelationalExprNoBF | EqualityExprNoBF EQEQ RelationalExpr | EqualityExprNoBF NE RelationalExpr | EqualityExprNoBF STREQ RelationalExpr | EqualityExprNoBF STRNEQ RelationalExpr ; BitwiseANDExpr : EqualityExpr | BitwiseANDExpr '&' EqualityExpr ; BitwiseANDExprNoIn : EqualityExprNoIn | BitwiseANDExprNoIn '&' EqualityExprNoIn ; BitwiseANDExprNoBF : EqualityExprNoBF | BitwiseANDExprNoBF '&' EqualityExpr ; BitwiseXORExpr : BitwiseANDExpr | BitwiseXORExpr '^' BitwiseANDExpr ; BitwiseXORExprNoIn : BitwiseANDExprNoIn | BitwiseXORExprNoIn '^' BitwiseANDExprNoIn ; BitwiseXORExprNoBF : BitwiseANDExprNoBF | BitwiseXORExprNoBF '^' BitwiseANDExpr ; BitwiseORExpr : BitwiseXORExpr | BitwiseORExpr '|' BitwiseXORExpr ; BitwiseORExprNoIn : BitwiseXORExprNoIn | BitwiseORExprNoIn '|' BitwiseXORExprNoIn ; BitwiseORExprNoBF : BitwiseXORExprNoBF | BitwiseORExprNoBF '|' BitwiseXORExpr ; LogicalANDExpr : BitwiseORExpr | LogicalANDExpr AND BitwiseORExpr ; LogicalANDExprNoIn : BitwiseORExprNoIn | LogicalANDExprNoIn AND BitwiseORExprNoIn ; LogicalANDExprNoBF : BitwiseORExprNoBF | LogicalANDExprNoBF AND BitwiseORExpr ; LogicalORExpr : LogicalANDExpr | LogicalORExpr OR LogicalANDExpr ; LogicalORExprNoIn : LogicalANDExprNoIn | LogicalORExprNoIn OR LogicalANDExprNoIn ; LogicalORExprNoBF : LogicalANDExprNoBF | LogicalORExprNoBF OR LogicalANDExpr ; ConditionalExpr : LogicalORExpr | LogicalORExpr '?' AssignmentExpr ':' AssignmentExpr ; ConditionalExprNoIn : LogicalORExprNoIn | LogicalORExprNoIn '?' AssignmentExprNoIn ':' AssignmentExprNoIn ; ConditionalExprNoBF : LogicalORExprNoBF | LogicalORExprNoBF '?' AssignmentExpr ':' AssignmentExpr ; AssignmentExpr : ConditionalExpr | LeftHandSideExpr AssignmentOperator AssignmentExpr ; AssignmentExprNoIn : ConditionalExprNoIn | LeftHandSideExpr AssignmentOperator AssignmentExprNoIn ; AssignmentExprNoBF : ConditionalExprNoBF | LeftHandSideExprNoBF AssignmentOperator AssignmentExpr ; AssignmentOperator : '=' | PLUSEQUAL | MINUSEQUAL | MULTEQUAL | DIVEQUAL | LSHIFTEQUAL | RSHIFTEQUAL | URSHIFTEQUAL | ANDEQUAL | XOREQUAL | OREQUAL | MODEQUAL ; Expr : AssignmentExpr | Expr ',' AssignmentExpr ; ExprNoIn : AssignmentExprNoIn | ExprNoIn ',' AssignmentExprNoIn ; ExprNoBF : AssignmentExprNoBF | ExprNoBF ',' AssignmentExpr ; Statement : Block | VariableStatement | ConstStatement | FunctionDeclaration | EmptyStatement | ExprStatement | IfStatement | IterationStatement | ContinueStatement | BreakStatement | ReturnStatement | WithStatement | SwitchStatement | LabelledStatement | ThrowStatement | TryStatement | DebuggerStatement ; Block : OPENBRACE CLOSEBRACE | OPENBRACE SourceElements CLOSEBRACE ; VariableStatement : VAR VariableDeclarationList ';' | VAR VariableDeclarationList error ; VariableDeclarationList : IDENT | IDENT Initializer | VariableDeclarationList ',' IDENT | VariableDeclarationList ',' IDENT Initializer ; VariableDeclarationListNoIn : IDENT | IDENT InitializerNoIn | VariableDeclarationListNoIn ',' IDENT | VariableDeclarationListNoIn ',' IDENT InitializerNoIn ; ConstStatement : CONSTTOKEN ConstDeclarationList ';' | CONSTTOKEN ConstDeclarationList error ; ConstDeclarationList : ConstDeclaration | ConstDeclarationList ',' ConstDeclaration ; ConstDeclaration : IDENT | IDENT Initializer ; Initializer : '=' AssignmentExpr ; InitializerNoIn : '=' AssignmentExprNoIn ; EmptyStatement : ';' ; ExprStatement : ExprNoBF ';' | ExprNoBF error ; IfStatement : IF '(' Expr ')' Statement %prec IF_WITHOUT_ELSE | IF '(' Expr ')' Statement ELSE Statement ; IterationStatement : DO Statement WHILE '(' Expr ')' ';' | DO Statement WHILE '(' Expr ')' error | WHILE '(' Expr ')' Statement | FOR '(' ExprNoInOpt ';' ExprOpt ';' ExprOpt ')' Statement | FOR '(' VAR VariableDeclarationListNoIn ';' ExprOpt ';' ExprOpt ')' Statement | FOR '(' LeftHandSideExpr INTOKEN Expr ')' Statement | FOR '(' VAR IDENT INTOKEN Expr ')' Statement | FOR '(' VAR IDENT InitializerNoIn INTOKEN Expr ')' Statement ; ExprOpt : | Expr ; ExprNoInOpt : | ExprNoIn ; ContinueStatement : CONTINUE ';' | CONTINUE error | CONTINUE IDENT ';' | CONTINUE IDENT error ; BreakStatement : BREAK ';' | BREAK error | BREAK IDENT ';' | BREAK IDENT error ; ReturnStatement : RETURN ';' | RETURN error | RETURN Expr ';' | RETURN Expr error ; WithStatement : WITH '(' Expr ')' Statement ; SwitchStatement : SWITCH '(' Expr ')' CaseBlock ; CaseBlock : OPENBRACE CaseClausesOpt CLOSEBRACE | OPENBRACE CaseClausesOpt DefaultClause CaseClausesOpt CLOSEBRACE ; CaseClausesOpt : | CaseClauses ; CaseClauses : CaseClause | CaseClauses CaseClause ; CaseClause : CASE Expr ':' | CASE Expr ':' SourceElements ; DefaultClause : DEFAULT ':' | DEFAULT ':' SourceElements ; LabelledStatement : IDENT ':' Statement ; ThrowStatement : THROW Expr ';' | THROW Expr error ; TryStatement : TRY Block FINALLY Block | TRY Block CATCH '(' IDENT ')' Block | TRY Block CATCH '(' IDENT ')' Block FINALLY Block ; DebuggerStatement : DEBUGGER ';' | DEBUGGER error ; FunctionDeclaration : FUNCTION IDENT '(' ')' OPENBRACE FunctionBody CLOSEBRACE | FUNCTION IDENT '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE ; FunctionExpr : FUNCTION '(' ')' OPENBRACE FunctionBody CLOSEBRACE | FUNCTION '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE | FUNCTION IDENT '(' ')' OPENBRACE FunctionBody CLOSEBRACE | FUNCTION IDENT '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE ; FormalParameterList : IDENT | FormalParameterList ',' IDENT ; FunctionBody : | SourceElements ; Program : | SourceElements ; SourceElements : Statement | SourceElements Statement ; jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/examples/json.js000664 000000 000000 00000004300 12652507276 022502 0ustar00rootroot000000 000000 var Generator = require("../lib/jison").Generator; exports.grammar = { "comment": "ECMA-262 5th Edition, 15.12.1 The JSON Grammar.", "author": "Zach Carter", "lex": { "macros": { "digit": "[0-9]", "esc": "\\\\", "int": "-?(?:[0-9]|[1-9][0-9]+)", "exp": "(?:[eE][-+]?[0-9]+)", "frac": "(?:\\.[0-9]+)" }, "rules": [ ["\\s+", "/* skip whitespace */"], ["{int}{frac}?{exp}?\\b", "return 'NUMBER';"], ["\"(?:{esc}[\"bfnrt/{esc}]|{esc}u[a-fA-F0-9]{4}|[^\"{esc}])*\"", "yytext = yytext.substr(1,yyleng-2); return 'STRING';"], ["\\{", "return '{'"], ["\\}", "return '}'"], ["\\[", "return '['"], ["\\]", "return ']'"], [",", "return ','"], [":", "return ':'"], ["true\\b", "return 'TRUE'"], ["false\\b", "return 'FALSE'"], ["null\\b", "return 'NULL'"] ] }, "tokens": "STRING NUMBER { } [ ] , : TRUE FALSE NULL", "start": "JSONText", "bnf": { "JSONString": [ "STRING" ], "JSONNullLiteral": [ "NULL" ], "JSONNumber": [ "NUMBER" ], "JSONBooleanLiteral": [ "TRUE", "FALSE" ], "JSONText": [ "JSONValue" ], "JSONValue": [ "JSONNullLiteral", "JSONBooleanLiteral", "JSONString", "JSONNumber", "JSONObject", "JSONArray" ], "JSONObject": [ "{ }", "{ JSONMemberList }" ], "JSONMember": [ "JSONString : JSONValue" ], "JSONMemberList": [ "JSONMember", "JSONMemberList , JSONMember" ], "JSONArray": [ "[ ]", "[ JSONElementList ]" ], "JSONElementList": [ "JSONValue", "JSONElementList , JSONValue" ] } }; var options = {type: "slr", moduleType: "commonjs", moduleName: "jsoncheck"}; exports.main = function main () { var code = new Generator(exports.grammar, options).generate(); console.log(code); }; if (require.main === module) exports.main(); jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/examples/json_ast.js000664 000000 000000 00000005251 12652507276 023357 0ustar00rootroot000000 000000 var Generator = require("../lib/jison").Generator; exports.grammar = { "comment": "ECMA-262 5th Edition, 15.12.1 The JSON Grammar. Parses JSON strings into objects.", "author": "Zach Carter", "lex": { "macros": { "digit": "[0-9]", "esc": "\\\\", "int": "-?(?:[0-9]|[1-9][0-9]+)", "exp": "(?:[eE][-+]?[0-9]+)", "frac": "(?:\\.[0-9]+)" }, "rules": [ ["\\s+", "/* skip whitespace */"], ["{int}{frac}?{exp}?\\b", "return 'NUMBER';"], ["\"(?:{esc}[\"bfnrt/{esc}]|{esc}u[a-fA-F0-9]{4}|[^\"{esc}])*\"", "yytext = yytext.substr(1,yyleng-2); return 'STRING';"], ["\\{", "return '{'"], ["\\}", "return '}'"], ["\\[", "return '['"], ["\\]", "return ']'"], [",", "return ','"], [":", "return ':'"], ["true\\b", "return 'TRUE'"], ["false\\b", "return 'FALSE'"], ["null\\b", "return 'NULL'"] ] }, "tokens": "STRING NUMBER { } [ ] , : TRUE FALSE NULL", "start": "JSONText", "bnf": { "JSONString": [[ "STRING", "$$ = yytext;" ]], "JSONNumber": [[ "NUMBER", "$$ = Number(yytext);" ]], "JSONNullLiteral": [[ "NULL", "$$ = null;" ]], "JSONBooleanLiteral": [[ "TRUE", "$$ = true;" ], [ "FALSE", "$$ = false;" ]], "JSONText": [[ "JSONValue", "return $$ = $1;" ]], "JSONValue": [[ "JSONNullLiteral", "$$ = $1;" ], [ "JSONBooleanLiteral", "$$ = $1;" ], [ "JSONString", "$$ = $1;" ], [ "JSONNumber", "$$ = $1;" ], [ "JSONObject", "$$ = $1;" ], [ "JSONArray", "$$ = $1;" ]], "JSONObject": [[ "{ }", "$$ = {};" ], [ "{ JSONMemberList }", "$$ = $2;" ]], "JSONMember": [[ "JSONString : JSONValue", "$$ = [$1, $3];" ]], "JSONMemberList": [[ "JSONMember", "$$ = {}; $$[$1[0]] = $1[1];" ], [ "JSONMemberList , JSONMember", "$$ = $1; $1[$3[0]] = $3[1];" ]], "JSONArray": [[ "[ ]", "$$ = [];" ], [ "[ JSONElementList ]", "$$ = $2;" ]], "JSONElementList": [[ "JSONValue", "$$ = [$1];" ], [ "JSONElementList , JSONValue", "$$ = $1; $1.push($3);" ]] } }; var options = {type: "slr", moduleType: "commonjs", moduleName: "jsonparse"}; exports.main = function main (args) { var code = new Generator(exports.grammar, options).generate(); console.log(code); }; if (require.main === module) exports.main(); jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/examples/lambdacalc.jison000664 000000 000000 00000001523 12652507276 024306 0ustar00rootroot000000 000000 /* Lambda calculus grammar by Zach Carter */ %lex %% \s*\n\s* {/* ignore */} "(" { return '('; } ")" { return ')'; } "^"|"λ" { return 'LAMBDA'; } "."\s? { return '.'; } [a-zA-Z] { return 'VAR'; } \s+ { return 'SEP'; } <> { return 'EOF'; } /lex %right LAMBDA %left SEP %% file : expr EOF { return $expr; } ; expr : LAMBDA var_list '.' expr %{ var temp = ["LambdaExpr", $var_list.shift(), $expr]; $var_list.forEach(function (v) { temp = ["LambdaExpr", v, temp]; }); $$ = temp; %} | expr SEP expr { $$ = ["ApplyExpr", $expr1, $expr2]; } | var { $$ = ["VarExpr", $var]; } | '(' expr ')' { $$ = $expr; } ; var_list : var_list var { $$ = $var_list; $$.unshift($var); } | var { $$ = [$var]; } ; var : VAR { $$ = yytext; } ; jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/examples/nv_classy_ast.jison000664 000000 000000 00000005463 12652507276 025122 0ustar00rootroot000000 000000 /* description: ClassyLang grammar with AST-building actions. Very classy. */ /* To build parser: $ ./bin/jison examples/classy_ast.jison examples/classy.jisonlex */ /* author: Zach Carter */ %{ function prependChild(node, child){ node.splice(2,0,child); return node; } %} %ebnf %right ASSIGN %left OR %nonassoc EQUALITY GREATER %left PLUS MINUS %left TIMES %right NOT %left DOT %% pgm : cdl MAIN LBRACE vdl el RBRACE ENDOFFILE {{$$ = ['PROGRAM',{},$1,$4,$5]; console.log(JSON.stringify($$, null, 4)); return $$; }} ; cdl : c cdl {$$ = prependChild($2, $1);} | {{$$ = ['CLASS_DECL_LIST',{}];}} ; c : CLASS id[class_name] EXTENDS id[base_class] LBRACE vdl mdl RBRACE {{$$ = ['CLASS_DECL',{},$class_name,$base_class,$vdl,$mdl];}} ; vdl : VAR t id SEMICOLON vdl {{$$ = prependChild($5, ['VAR_DECL',{},$2,$3]);}} | {{$$ = ['VAR_DECL_LIST',{}];}} ; mdl : t id LPAREN t id RPAREN LBRACE vdl el RBRACE mdl {{$$ = prependChild($11, ['METHOD_DECL',{},$1,$2,$4,$5,$8,$9]);}} | {{$$ = ['METHOD_DECL_LIST',{}];}} ; t : NATTYPE {{$$ = ['NAT_TYPE',{}];}} | id {$$ = $1} ; id : ID {{$$ = ['AST_ID',{val:yytext}]}} ; el : e SEMICOLON el {$$ = prependChild($3, $1);} | e SEMICOLON {{$$ = ['EXPR_LIST',{},$1];}} ; e : NATLITERAL {{$$ = ['NAT_LITERAL_EXPR',{val:parseInt(yytext)}];}} | NUL {{$$ = ['NULL_EXPR',{}];}} | id {{$$ = ['ID_EXPR',{},$1];}} | NEW id {{$$ = ['NEW_EXPR',{},$2];}} | THIS {{$$ = ['THIS_EXPR',{}];}} | IF LPAREN e RPAREN LBRACE el RBRACE ELSE LBRACE el RBRACE {{$$ = ['IF_THEN_ELSE_EXPR',{},$3,$6,$10];}} | FOR LPAREN e SEMICOLON e SEMICOLON e RPAREN LBRACE el RBRACE {{$$ = ['FOR_EXPR',{},$3,$5,$7,$10];}} | READNAT LPAREN RPAREN {{$$ = ['READ_EXPR',{}];}} | PRINTNAT LPAREN e RPAREN {{$$ = ['PRINT_EXPR',{},$3];}} | e PLUS e {{$$ = ['PLUS_EXPR',{},$1,$3];}} | e MINUS e {{$$ = ['MINUS_EXPR',{},$1,$3];}} | e TIMES e {{$$ = ['TIMES_EXPR',{},$1,$3];}} | e EQUALITY e {{$$ = ['EQUALITY_EXPR',{},$1,$3];}} | e GREATER e {{$$ = ['GREATER_THAN_EXPR',{},$1,$3];}} | NOT e {{$$ = ['NOT_EXPR',{},$2];}} | e OR e {{$$ = ['OR_EXPR',{},$1,$3];}} | e DOT id {{$$ = ['DOT_ID_EXPR',{},$1,$3];}} | id ASSIGN e {{$$ = ['ASSIGN_EXPR',{},$1,$3];}} | e DOT id ASSIGN e {{$$ = ['DOT_ASSIGN_EXPR',{},$1,$3,$5];}} | id LPAREN e RPAREN {{$$ = ['METHOD_CALL_EXPR',{},$1,$3];}} | e DOT id LPAREN e RPAREN {{$$ = ['DOT_METHOD_CALL_EXPR',{},$1,$3,$5];}} | LPAREN e RPAREN {$$ = $2;} ; jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/examples/phraser.jison000664 000000 000000 00000001505 12652507276 023707 0ustar00rootroot000000 000000 /* description: Parses words out of html, ignoring html in the parse, but returning it in the end */ /* lexical grammar */ %lex %% "<"(.|\n)*?">" return 'TAG' [a-zA-Z0-9]+ return 'WORD' (.|\n) return 'CHAR' <> return 'EOF' /lex %start html %% /* language grammar */ html : contents EOF {return $1;} ; contents : content {$$ = $1;} | contents content {$$ = $1 + $2;} ; content : TAG { if (!yy.lexer.tagHandler) yy.lexer.tagHandler = function(tag) {return tag;}; $$ = yy.lexer.tagHandler(yytext); } | WORD { if (!yy.lexer.wordHandler) yy.lexer.wordHandler = function(word) {return word;}; $$ = yy.lexer.wordHandler(yytext); } | CHAR { if (!yy.lexer.charHandler) yy.lexer.charHandler = function(char) {return char;}; $$ = yy.lexer.charHandler(yytext); } ; jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/examples/precedence.jison000664 000000 000000 00000000704 12652507276 024340 0ustar00rootroot000000 000000 /* description: Grammar showing precedence operators and semantic actions. */ %lex %% \s+ {/* skip whitespace */} [0-9]+ {return 'NAT';} "+" {return '+';} "*" {return '*';} <> {return 'EOF';} /lex %left '+' %left '*' %% S : e EOF {return $1;} ; e : e '+' e {$$ = [$1,'+', $3];} | e '*' e {$$ = [$1, '*', $3];} | NAT {$$ = parseInt(yytext);} ; jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/examples/reduce_conflict.jison000664 000000 000000 00000000265 12652507276 025375 0ustar00rootroot000000 000000 /* description: Produces a reduce-reduce conflict unless using LR(1). */ %start S %% S : a A c | a B d | b A d | b B c ; A : z ; B : z ; jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/examples/semwhitespace.jison000664 000000 000000 00000002015 12652507276 025101 0ustar00rootroot000000 000000 /* Demonstrates use of semantic whitespace pseudo-tokens. */ %start prog %ebnf %options token-stack %% /* language grammar */ prog : proglist ENDOFFILE { console.log("AST: %j", $proglist); } ; proglist : proglist stmt { $proglist.push($stmt); $$ = $proglist; } | stmt { $$ = [$stmt]; } ; if_stmt : IF LPAREN expr RPAREN COLON stmt_block { $$ = [ "if", $expr, $stmt_block ]; } | IF LPAREN expr RPAREN COLON stmt_block ELSE COLON stmt_block { $$ = [ "if", $expr, $6, $9 ]; } ; print_stmt : PRINT STRING { $$ = ["print", $2]; } ; stmt : if_stmt | print_stmt ; stmt_list : stmt { $$ = ["stmt_list", $stmt]; } | stmt_list stmt { $stmt_list.push($stmt); $$ = $stmt_list; } ; stmt_block : INDENT stmt_list DEDENT { $$ = $stmt_list; } ; atom : ID { $$ = ["id", $1]; } | NATLITERAL { $$ = ["natlit", $1]; } | LPAREN expr RPAREN { $$ = ["expr", $2]; } ; expr : atom | expr PLUS atom { $expr.push(["plus", $atom]); $$ = $expr; } | expr MINUS atom { $expr.push(["minus", $atom]); $$ = $expr; } ; jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/examples/semwhitespace_ex.src000664 000000 000000 00000000426 12652507276 025246 0ustar00rootroot000000 000000 if (a+b): print "this line has trailing spaces" if (123-b): print "this one does not" else: print "will error until indentation corrected" print "correctly indented" print "another line, a couple trailing tabs" print "unexpected indent" print "end of program" jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/examples/semwhitespace_lex.jison000664 000000 000000 00000002705 12652507276 025757 0ustar00rootroot000000 000000 /* Demonstrates semantic whitespace pseudo-tokens, INDENT/DEDENT. */ id [a-zA-Z][a-zA-Z0-9]* spc [\t \u00a0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000] %s EXPR %% "if" return 'IF'; "else" return 'ELSE'; "print" return 'PRINT'; ":" return 'COLON'; "(" this.begin('EXPR'); return 'LPAREN'; ")" this.popState(); return 'RPAREN'; \"[^\"]*\"|\'[^\']*\' yytext = yytext.substr(1,yyleng-2); return 'STRING'; "+" return 'PLUS'; "-" return 'MINUS'; {id} return 'ID'; \d+ return 'NATLITERAL'; <> return "ENDOFFILE"; \s*<> %{ // remaining DEDENTs implied by EOF, regardless of tabs/spaces var tokens = []; while (0 < _iemitstack[0]) { this.popState(); tokens.unshift("DEDENT"); _iemitstack.shift(); } if (tokens.length) return tokens; %} [\n\r]+{spc}*/![^\n\r] /* eat blank lines */ [\n\r]{spc}* %{ var indentation = yytext.length - yytext.search(/\s/) - 1; if (indentation > _iemitstack[0]) { _iemitstack.unshift(indentation); return 'INDENT'; } var tokens = []; while (indentation < _iemitstack[0]) { this.popState(); tokens.unshift("DEDENT"); _iemitstack.shift(); } if (tokens.length) return tokens; %} {spc}+ /* ignore all other whitespace */ %% /* initialize the pseudo-token stack with 0 indents */ _iemitstack = [0]; jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/examples/tikiwikiparser.jison000775 000000 000000 00000016525 12652507276 025317 0ustar00rootroot000000 000000 %lex PLUGIN_ID [A-Z]+ INLINE_PLUGIN_ID [a-z]+ SMILE [a-z]+ %s bold box center colortext italic header6 header5 header4 header3 header2 header1 link strikethrough table titlebar underscore wikilink %% "{"{INLINE_PLUGIN_ID}.*?"}" %{ yytext = parserlib.inlinePlugin(yytext); return 'INLINE_PLUGIN'; %} "{"{PLUGIN_ID}"(".*?")}" %{ yy.pluginStack = parserlib.stackPlugin(yytext, yy.pluginStack); if (parserlib.size(yy.pluginStack) == 1) { return 'PLUGIN_START'; } else { return 'CONTENT'; } %} "{"{PLUGIN_ID}"}" %{ if (yy.pluginStack) { if ( parserlib.size(yy.pluginStack) > 0 && parserlib.substring(yytext, 1, -1) == yy.pluginStack[parserlib.size(yy.pluginStack) - 1].name ) { if (parserlib.size(yy.pluginStack) == 1) { yytext = yy.pluginStack[parserlib.size(yy.pluginStack) - 1]; yy.pluginStack = parserlib.pop(yy.pluginStack); return 'PLUGIN_END'; } else { yy.pluginStack = parserlib.pop(yy.pluginStack); return 'CONTENT'; } } } return 'CONTENT'; %} ("~np~") %{ yy.npStack = parserlib.push(yy.npStack, true); this.yy.npOn = true; return 'NP_START'; %} ("~/np~") %{ this.yy.npStack = parserlib.pop(yy.npStack); if (parserlib.size(yy.npStack) < 1) yy.npOn = false; return 'NP_END'; %} "---" %{ yytext = parserlib.hr(); return 'HORIZONTAL_BAR'; %} "(:"{SMILE}":)" %{ yytext = parserlib.substring(yytext, 2, -2); yytext = parserlib.smile(yytext); return 'SMILE'; %} "[[".*? %{ yytext = parserlib.substring(yytext, 2, -1); return 'CONTENT'; %} [_][_] %{ this.popState(); return parserlib.npState(this.yy.npOn, 'CONTENT', 'BOLD_END'); %} [_][_] %{ this.begin('bold'); return parserlib.npState(this.yy.npOn, 'CONTENT', 'BOLD_START'); %} [\^] %{ this.popState(); return parserlib.npState(this.yy.npOn, 'CONTENT', 'BOX_END'); %} [\^] %{ this.begin('box'); return parserlib.npState(this.yy.npOn, 'CONTENT', 'BOX_START'); %}
[:][:] %{ this.popState(); return parserlib.npState(this.yy.npOn, 'CONTENT', 'CENTER_END'); %} [:][:] %{ this.begin('center'); return parserlib.npState(this.yy.npOn, 'CONTENT', 'CENTER_START'); %} [\~][\~] %{ this.popState(); return parserlib.npState(this.yy.npOn, 'CONTENT', 'COLORTEXT_END'); %} [\~][\~][#] %{ this.begin('colortext'); return parserlib.npState(this.yy.npOn, 'CONTENT', 'COLORTEXT_START'); %} [\n] %{ this.popState(); return parserlib.npState(this.yy.npOn, 'CONTENT', 'HEADER6_END'); %} [\n]("!!!!!!") %{ this.begin('header6'); return parserlib.npState(this.yy.npOn, 'CONTENT', 'HEADER6_START'); %} [\n] %{ this.popState(); return parserlib.npState(this.yy.npOn, 'CONTENT', 'HEADER5_END'); %} [\n]("!!!!!") %{ this.begin('header5'); return parserlib.npState(this.yy.npOn, 'CONTENT', 'HEADER5_START'); %} [\n] %{ this.popState(); return parserlib.npState(this.yy.npOn, 'CONTENT', 'HEADER4_END'); %} [\n]("!!!!") %{ this.begin('header4'); return parserlib.npState(this.yy.npOn, 'CONTENT', 'HEADER4_START'); %} [\n] %{ this.popState(); return parserlib.npState(this.yy.npOn, 'CONTENT', 'HEADER3_END'); %} [\n]("!!!") %{ this.begin('header3'); return parserlib.npState(this.yy.npOn, 'CONTENT', 'HEADER3_START'); %} [\n] %{ this.popState(); return parserlib.npState(this.yy.npOn, 'CONTENT', 'HEADER2_END'); %} [\n]("!!") %{ this.begin('header2'); return parserlib.npState(this.yy.npOn, 'CONTENT', 'HEADER2_START'); %} [\n] %{ this.popState(); return parserlib.npState(this.yy.npOn, 'CONTENT', 'HEADER1_END'); %} [\n]("!") %{ this.begin('header1'); return parserlib.npState(this.yy.npOn, 'CONTENT', 'HEADER1_START'); %} [']['] %{ this.popState(); return parserlib.npState(this.yy.npOn, 'CONTENT', 'ITALIC_END'); %} [']['] %{ this.begin('italic'); return parserlib.npState(this.yy.npOn, 'CONTENT', 'ITALIC_START'); %} ("]") %{ this.popState(); return parserlib.npState(this.yy.npOn, 'CONTENT', 'LINK_END'); %} ("[") %{ this.begin('link'); return parserlib.npState(this.yy.npOn, 'CONTENT', 'LINK_START'); %} [-][-] %{ this.popState(); return parserlib.npState(this.yy.npOn, 'CONTENT', 'STRIKETHROUGH_END'); %} [-][-] %{ this.begin('strikethrough'); return parserlib.npState(this.yy.npOn, 'CONTENT', 'STRIKETHROUGH_START'); %} [|][|] %{ this.popState(); return parserlib.npState(this.yy.npOn, 'CONTENT', 'TABLE_END'); %} [|][|] %{ this.begin('table'); return parserlib.npState(this.yy.npOn, 'CONTENT', 'TABLE_START'); %} [=][-] %{ this.popState(); return parserlib.npState(this.yy.npOn, 'CONTENT', 'TITLEBAR_END'); %} [-][=] %{ this.begin('titlebar'); return parserlib.npState(this.yy.npOn, 'CONTENT', 'TITLEBAR_START'); %} [=][=][=] %{ this.popState(); return parserlib.npState(this.yy.npOn, 'CONTENT', 'UNDERSCORE_END'); %} [=][=][=] %{ this.begin('underscore'); return parserlib.npState(this.yy.npOn, 'CONTENT', 'UNDERSCORE_START'); %} [)][)] %{ this.popState(); return parserlib.npState(this.yy.npOn, 'CONTENT', 'WIKILINK_END'); %} [(][(] %{ this.begin('wikilink'); return parserlib.npState(this.yy.npOn, 'CONTENT', 'WIKILINK_START'); %} "<"(.|\n)*?">" return 'HTML' (.) return 'CONTENT' (\n) %{ if (parserlib.npState(this.yy.npOn, false, true) == true) { yytext = parserlib.formatContent(yytext); } return 'CONTENT'; %} <> return 'EOF' /lex %% wiki : wiki_contents EOF {return $1;} ; wiki_contents : | contents {$$ = $1;} | wiki_contents plugin {$$ = parserlib.join($1, $2);} | wiki_contents plugin contents {$$ = parserlib.join($1, $2, $3);} ; plugin : INLINE_PLUGIN {$$ = parserlib.plugin($1);} | PLUGIN_START wiki_contents PLUGIN_END { $3.body = $2; $$ = parserlib.plugin($3); } ; contents : content {$$ = $1;} | contents content {$$ = parserlib.join($1, $2);} ; content : CONTENT {$$ = $1;} | HTML {$$ = parserlib.html($1);} | HORIZONTAL_BAR {$$ = $1;} | SMILE {$$ = $1;} | BOLD_START wiki_contents BOLD_END {$$ = parserlib.bold($2);} | BOX_START wiki_contents BOX_END {$$ = parserlib.box($2);} | CENTER_START wiki_contents CENTER_END {$$ = parserlib.center($2);} | COLORTEXT_START wiki_contents COLORTEXT_END {$$ = parserlib.colortext($2);} | ITALIC_START wiki_contents ITALIC_END {$$ = parserlib.italics($2);} | HEADER6_START wiki_contents HEADER6_END {$$ = parserlib.header6($2);} | HEADER5_START wiki_contents HEADER5_END {$$ = parserlib.header5($2);} | HEADER4_START wiki_contents HEADER4_END {$$ = parserlib.header4($2);} | HEADER3_START wiki_contents HEADER3_END {$$ = parserlib.header3($2);} | HEADER2_START wiki_contents HEADER2_END {$$ = parserlib.header2($2);} | HEADER1_START wiki_contents HEADER1_END {$$ = parserlib.header1($2);} | LINK_START wiki_contents LINK_END {$$ = parserlib.link($2);} | NP_START wiki_contents NP_END {$$ = $2;} | STRIKETHROUGH_START wiki_contents STRIKETHROUGH_END {$$ = parserlib.strikethrough($2);} | TABLE_START wiki_contents TABLE_END {$$ = parserlib.table($2);} | TITLEBAR_START wiki_contents TITLEBAR_END {$$ = parserlib.titlebar($2);} | UNDERSCORE_START wiki_contents UNDERSCORE_END {$$ = parserlib.underscore($2);} | WIKILINK_START wiki_contents WIKILINK_END {$$ = parserlib.wikilink($2);} ; jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/lib/000775 000000 000000 00000000000 12652507276 020126 5ustar00rootroot000000 000000 jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/lib/cli.js000775 000000 000000 00000011615 12652507276 021242 0ustar00rootroot000000 000000 #!/usr/bin/env node function getCommandlineOptions () { "use strict"; var version = require('../package.json').version; var opts = require("nomnom") .script('jison') .option('file', { flag : true, position : 0, help : 'file containing a grammar' }) .option('lexfile', { flag : true, position : 1, help : 'file containing a lexical grammar' }) .option('json', { abbr : 'j', flag : true, help : 'force jison to expect a grammar in JSON format' }) .option('outfile', { abbr : 'o', metavar : 'FILE', help : 'Filename and base module name of the generated parser' }) .option('debug', { abbr : 't', flag : true, default: false, help : 'Debug mode' }) .option('module-type', { abbr : 'm', default: 'commonjs', metavar : 'TYPE', help : 'The type of module to generate (commonjs, amd, js)' }) .option('parser-type', { abbr : 'p', default: 'lalr', metavar : 'TYPE', help : 'The type of algorithm to use for the parser (lr0, slr,' + 'lalr, lr)' }) .option('version', { abbr : 'V', flag : true, help : 'print version and exit', callback : function () { return version; } }).parse(); return opts; } var cli = module.exports; cli.main = function cliMain(opts) { "use strict"; opts = opts || {}; function processGrammar(raw, lex, opts) { var grammar, parser; grammar = cli.processGrammars(raw, lex, opts.json); parser = cli.generateParserString(opts, grammar); return parser; } function processInputFile () { var fs = require('fs'); var path = require('path'); // getting raw files var lex; if (opts.lexfile) { lex = fs.readFileSync(path.normalize(opts.lexfile), 'utf8'); } var raw = fs.readFileSync(path.normalize(opts.file), 'utf8'); // making best guess at json mode opts.json = path.extname(opts.file) === '.json' || opts.json; // setting output file name and module name based on input file name // if they aren't specified. var name = path.basename((opts.outfile || opts.file)); name = name.replace(/\..*$/g, ''); opts.outfile = opts.outfile || (name + '.js'); if (!opts.moduleName && name) { opts.moduleName = name.replace(/-\w/g, function (match) { return match.charAt(1).toUpperCase(); }); } var parser = processGrammar(raw, lex, opts); fs.writeFileSync(opts.outfile, parser); } function readin(cb) { var stdin = process.openStdin(), data = ''; stdin.setEncoding('utf8'); stdin.addListener('data', function (chunk) { data += chunk; }); stdin.addListener('end', function () { cb(data); }); } function processStdin () { readin(function (raw) { console.log(processGrammar(raw, null, opts)); }); } // if an input file wasn't given, assume input on stdin if (opts.file) { processInputFile(); } else { processStdin(); } }; cli.generateParserString = function generateParserString(opts, grammar) { "use strict"; opts = opts || {}; var jison = require('./jison.js'); var settings = grammar.options || {}; if (opts['parser-type']) { settings.type = opts['parser-type']; } if (opts.moduleName) { settings.moduleName = opts.moduleName; } settings.debug = opts.debug; if (!settings.moduleType) { settings.moduleType = opts['module-type']; } var generator = new jison.Generator(grammar, settings); return generator.generate(settings); }; cli.processGrammars = function processGrammars(file, lexFile, jsonMode) { "use strict"; lexFile = lexFile || false; jsonMode = jsonMode || false; var ebnfParser = require('ebnf-parser'); var cjson = require('cjson'); var grammar; try { if (jsonMode) { grammar = cjson.parse(file); } else { grammar = ebnfParser.parse(file); } } catch (e) { throw new Error('Could not parse jison grammar'); } try { if (lexFile) { grammar.lex = require('lex-parser').parse(lexFile); } } catch (e) { throw new Error('Could not parse lex grammar'); } return grammar; }; if (require.main === module) { var opts = getCommandlineOptions(); cli.main(opts); } jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/lib/jison.js000775 000000 000000 00000201116 12652507276 021612 0ustar00rootroot000000 000000 // Jison, an LR(0), SLR(1), LARL(1), LR(1) Parser Generator // Zachary Carter // MIT X Licensed var typal = require('./util/typal').typal; var Set = require('./util/set').Set; var Lexer = require('jison-lex'); var ebnfParser = require('ebnf-parser'); var JSONSelect = require('JSONSelect'); var esprima = require('esprima'); var escodegen = require('escodegen'); var version = require('../package.json').version; var Jison = exports.Jison = exports; Jison.version = version; // detect print if (typeof console !== 'undefined' && console.log) { Jison.print = console.log; } else if (typeof puts !== 'undefined') { Jison.print = function print () { puts([].join.call(arguments, ' ')); }; } else if (typeof print !== 'undefined') { Jison.print = print; } else { Jison.print = function print () {}; } Jison.Parser = (function () { // iterator utility function each (obj, func) { if (obj.forEach) { obj.forEach(func); } else { var p; for (p in obj) { if (obj.hasOwnProperty(p)) { func.call(obj, obj[p], p, obj); } } } } var Nonterminal = typal.construct({ constructor: function Nonterminal (symbol) { this.symbol = symbol; this.productions = new Set(); this.first = []; this.follows = []; this.nullable = false; }, toString: function Nonterminal_toString () { var str = this.symbol+"\n"; str += (this.nullable ? 'nullable' : 'not nullable'); str += "\nFirsts: "+this.first.join(', '); str += "\nFollows: "+this.first.join(', '); str += "\nProductions:\n "+this.productions.join('\n '); return str; } }); var Production = typal.construct({ constructor: function Production (symbol, handle, id) { this.symbol = symbol; this.handle = handle; this.nullable = false; this.id = id; this.first = []; this.precedence = 0; }, toString: function Production_toString () { return this.symbol+" -> "+this.handle.join(' '); } }); var generator = typal.beget(); generator.constructor = function Jison_Generator (grammar, opt) { if (typeof grammar === 'string') { grammar = ebnfParser.parse(grammar); } var options = typal.mix.call({}, grammar.options, opt); this.terms = {}; this.operators = {}; this.productions = []; this.conflicts = 0; this.resolutions = []; this.options = options; this.parseParams = grammar.parseParams; this.yy = {}; // accessed as yy free variable in the parser/lexer actions // source included in semantic action execution scope if (grammar.actionInclude) { if (typeof grammar.actionInclude === 'function') { grammar.actionInclude = String(grammar.actionInclude).replace(/^\s*function \(\) \{/, '').replace(/\}\s*$/, ''); } this.actionInclude = grammar.actionInclude; } this.moduleInclude = grammar.moduleInclude || ''; this.DEBUG = options.debug || false; if (this.DEBUG) this.mix(generatorDebug); // mixin debug methods this.processGrammar(grammar); if (grammar.lex) { this.lexer = new Lexer(grammar.lex, null, this.terminals_); } }; generator.processGrammar = function processGrammarDef (grammar) { var bnf = grammar.bnf, tokens = grammar.tokens, nonterminals = this.nonterminals = {}, productions = this.productions, self = this; if (!grammar.bnf && grammar.ebnf) { bnf = grammar.bnf = ebnfParser.transform(grammar.ebnf); } if (tokens) { if (typeof tokens === 'string') { tokens = tokens.trim().split(' '); } else { tokens = tokens.slice(0); } } var symbols = this.symbols = []; // calculate precedence of operators var operators = this.operators = processOperators(grammar.operators); // build productions from cfg this.buildProductions(bnf, productions, nonterminals, symbols, operators); if (tokens && this.terminals.length !== tokens.length) { self.trace("Warning: declared tokens differ from tokens found in rules."); self.trace(this.terminals); self.trace(tokens); } // augment the grammar this.augmentGrammar(grammar); }; generator.augmentGrammar = function augmentGrammar (grammar) { if (this.productions.length === 0) { throw new Error("Grammar error: must have at least one rule."); } // use specified start symbol, or default to first user defined production this.startSymbol = grammar.start || grammar.startSymbol || this.productions[0].symbol; if (!this.nonterminals[this.startSymbol]) { throw new Error("Grammar error: startSymbol must be a non-terminal found in your grammar."); } this.EOF = "$end"; // augment the grammar var acceptProduction = new Production('$accept', [this.startSymbol, '$end'], 0); this.productions.unshift(acceptProduction); // prepend parser tokens this.symbols.unshift("$accept",this.EOF); this.symbols_.$accept = 0; this.symbols_[this.EOF] = 1; this.terminals.unshift(this.EOF); this.nonterminals.$accept = new Nonterminal("$accept"); this.nonterminals.$accept.productions.push(acceptProduction); // add follow $ to start symbol this.nonterminals[this.startSymbol].follows.push(this.EOF); }; // set precedence and associativity of operators function processOperators (ops) { if (!ops) return {}; var operators = {}; for (var i=0,k,prec;prec=ops[i]; i++) { for (k=1;k < prec.length;k++) { operators[prec[k]] = {precedence: i+1, assoc: prec[0]}; } } return operators; } generator.buildProductions = function buildProductions(bnf, productions, nonterminals, symbols, operators) { var actions = [ '/* this == yyval */', this.actionInclude || '', 'var $0 = $$.length - 1;', 'switch (yystate) {' ]; var actionGroups = {}; var prods, symbol; var productions_ = [0]; var symbolId = 1; var symbols_ = {}; var her = false; // has error recovery function addSymbol (s) { if (s && !symbols_[s]) { symbols_[s] = ++symbolId; symbols.push(s); } } // add error symbol; will be third symbol, or "2" ($accept, $end, error) addSymbol("error"); for (symbol in bnf) { if (!bnf.hasOwnProperty(symbol)) continue; addSymbol(symbol); nonterminals[symbol] = new Nonterminal(symbol); if (typeof bnf[symbol] === 'string') { prods = bnf[symbol].split(/\s*\|\s*/g); } else { prods = bnf[symbol].slice(0); } prods.forEach(buildProduction); } for (var action in actionGroups) actions.push(actionGroups[action].join(' '), action, 'break;'); var sym, terms = [], terms_ = {}; each(symbols_, function (id, sym) { if (!nonterminals[sym]) { terms.push(sym); terms_[id] = sym; } }); this.hasErrorRecovery = her; this.terminals = terms; this.terminals_ = terms_; this.symbols_ = symbols_; this.productions_ = productions_; actions.push('}'); actions = actions.join("\n") .replace(/YYABORT/g, 'return false') .replace(/YYACCEPT/g, 'return true'); var parameters = "yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */"; if (this.parseParams) parameters += ', ' + this.parseParams.join(', '); this.performAction = "function anonymous(" + parameters + ") {\n" + actions + "\n}"; function buildProduction (handle) { var r, rhs, i; if (handle.constructor === Array) { rhs = (typeof handle[0] === 'string') ? handle[0].trim().split(' ') : handle[0].slice(0); for (i=0; i don't care about aliases; strip them. rhs = rhs.map(function(e,i) { return e.replace(/\[[a-zA-Z_][a-zA-Z0-9_-]*\]/g, '') }); // only precedence specified r = new Production(symbol, rhs, productions.length+1); if (operators[handle[1].prec]) { r.precedence = operators[handle[1].prec].precedence; } } } else { // no action -> don't care about aliases; strip them. handle = handle.replace(/\[[a-zA-Z_][a-zA-Z0-9_-]*\]/g, ''); rhs = handle.trim().split(' '); for (i=0; i=0; i--) { if (!(r.handle[i] in nonterminals) && r.handle[i] in operators) { r.precedence = operators[r.handle[i]].precedence; } } } productions.push(r); productions_.push([symbols_[r.symbol], r.handle[0] === '' ? 0 : r.handle.length]); nonterminals[symbol].productions.push(r); } }; generator.createParser = function createParser () { throw new Error('Calling abstract method.'); }; // noop. implemented in debug mixin generator.trace = function trace () { }; generator.warn = function warn () { var args = Array.prototype.slice.call(arguments,0); Jison.print.call(null,args.join("")); }; generator.error = function error (msg) { throw new Error(msg); }; // Generator debug mixin var generatorDebug = { trace: function trace () { Jison.print.apply(null, arguments); }, beforeprocessGrammar: function () { this.trace("Processing grammar."); }, afteraugmentGrammar: function () { var trace = this.trace; each(this.symbols, function (sym, i) { trace(sym+"("+i+")"); }); } }; /* * Mixin for common behaviors of lookahead parsers * */ var lookaheadMixin = {}; lookaheadMixin.computeLookaheads = function computeLookaheads () { if (this.DEBUG) this.mix(lookaheadDebug); // mixin debug methods this.computeLookaheads = function () {}; this.nullableSets(); this.firstSets(); this.followSets(); }; // calculate follow sets typald on first and nullable lookaheadMixin.followSets = function followSets () { var productions = this.productions, nonterminals = this.nonterminals, self = this, cont = true; // loop until no further changes have been made while(cont) { cont = false; productions.forEach(function Follow_prod_forEach (production, k) { //self.trace(production.symbol,nonterminals[production.symbol].follows); // q is used in Simple LALR algorithm determine follows in context var q; var ctx = !!self.go_; var set = [],oldcount; for (var i=0,t;t=production.handle[i];++i) { if (!nonterminals[t]) continue; // for Simple LALR algorithm, self.go_ checks if if (ctx) q = self.go_(production.symbol, production.handle.slice(0, i)); var bool = !ctx || q === parseInt(self.nterms_[t], 10); if (i === production.handle.length+1 && bool) { set = nonterminals[production.symbol].follows; } else { var part = production.handle.slice(i+1); set = self.first(part); if (self.nullable(part) && bool) { set.push.apply(set, nonterminals[production.symbol].follows); } } oldcount = nonterminals[t].follows.length; Set.union(nonterminals[t].follows, set); if (oldcount !== nonterminals[t].follows.length) { cont = true; } } }); } }; // return the FIRST set of a symbol or series of symbols lookaheadMixin.first = function first (symbol) { // epsilon if (symbol === '') { return []; // RHS } else if (symbol instanceof Array) { var firsts = []; for (var i=0,t;t=symbol[i];++i) { if (!this.nonterminals[t]) { if (firsts.indexOf(t) === -1) firsts.push(t); } else { Set.union(firsts, this.nonterminals[t].first); } if (!this.nullable(t)) break; } return firsts; // terminal } else if (!this.nonterminals[symbol]) { return [symbol]; // nonterminal } else { return this.nonterminals[symbol].first; } }; // fixed-point calculation of FIRST sets lookaheadMixin.firstSets = function firstSets () { var productions = this.productions, nonterminals = this.nonterminals, self = this, cont = true, symbol,firsts; // loop until no further changes have been made while(cont) { cont = false; productions.forEach(function FirstSets_forEach (production, k) { var firsts = self.first(production.handle); if (firsts.length !== production.first.length) { production.first = firsts; cont=true; } }); for (symbol in nonterminals) { firsts = []; nonterminals[symbol].productions.forEach(function (production) { Set.union(firsts, production.first); }); if (firsts.length !== nonterminals[symbol].first.length) { nonterminals[symbol].first = firsts; cont=true; } } } }; // fixed-point calculation of NULLABLE lookaheadMixin.nullableSets = function nullableSets () { var firsts = this.firsts = {}, nonterminals = this.nonterminals, self = this, cont = true; // loop until no further changes have been made while(cont) { cont = false; // check if each production is nullable this.productions.forEach(function (production, k) { if (!production.nullable) { for (var i=0,n=0,t;t=production.handle[i];++i) { if (self.nullable(t)) n++; } if (n===i) { // production is nullable if all tokens are nullable production.nullable = cont = true; } } }); //check if each symbol is nullable for (var symbol in nonterminals) { if (!this.nullable(symbol)) { for (var i=0,production;production=nonterminals[symbol].productions.item(i);i++) { if (production.nullable) nonterminals[symbol].nullable = cont = true; } } } } }; // check if a token or series of tokens is nullable lookaheadMixin.nullable = function nullable (symbol) { // epsilon if (symbol === '') { return true; // RHS } else if (symbol instanceof Array) { for (var i=0,t;t=symbol[i];++i) { if (!this.nullable(t)) return false; } return true; // terminal } else if (!this.nonterminals[symbol]) { return false; // nonterminal } else { return this.nonterminals[symbol].nullable; } }; // lookahead debug mixin var lookaheadDebug = { beforenullableSets: function () { this.trace("Computing Nullable sets."); }, beforefirstSets: function () { this.trace("Computing First sets."); }, beforefollowSets: function () { this.trace("Computing Follow sets."); }, afterfollowSets: function () { var trace = this.trace; each(this.nonterminals, function (nt, t) { trace(nt, '\n'); }); } }; /* * Mixin for common LR parser behavior * */ var lrGeneratorMixin = {}; lrGeneratorMixin.buildTable = function buildTable () { if (this.DEBUG) this.mix(lrGeneratorDebug); // mixin debug methods this.states = this.canonicalCollection(); this.table = this.parseTable(this.states); this.defaultActions = findDefaults(this.table); }; lrGeneratorMixin.Item = typal.construct({ constructor: function Item(production, dot, f, predecessor) { this.production = production; this.dotPosition = dot || 0; this.follows = f || []; this.predecessor = predecessor; this.id = parseInt(production.id+'a'+this.dotPosition, 36); this.markedSymbol = this.production.handle[this.dotPosition]; }, remainingHandle: function () { return this.production.handle.slice(this.dotPosition+1); }, eq: function (e) { return e.id === this.id; }, handleToString: function () { var handle = this.production.handle.slice(0); handle[this.dotPosition] = '.'+(handle[this.dotPosition]||''); return handle.join(' '); }, toString: function () { var temp = this.production.handle.slice(0); temp[this.dotPosition] = '.'+(temp[this.dotPosition]||''); return this.production.symbol+" -> "+temp.join(' ') + (this.follows.length === 0 ? "" : " #lookaheads= "+this.follows.join(' ')); } }); lrGeneratorMixin.ItemSet = Set.prototype.construct({ afterconstructor: function () { this.reductions = []; this.goes = {}; this.edges = {}; this.shifts = false; this.inadequate = false; this.hash_ = {}; for (var i=this._items.length-1;i >=0;i--) { this.hash_[this._items[i].id] = true; //i; } }, concat: function concat (set) { var a = set._items || set; for (var i=a.length-1;i >=0;i--) { this.hash_[a[i].id] = true; //i; } this._items.push.apply(this._items, a); return this; }, push: function (item) { this.hash_[item.id] = true; return this._items.push(item); }, contains: function (item) { return this.hash_[item.id]; }, valueOf: function toValue () { var v = this._items.map(function (a) {return a.id;}).sort().join('|'); this.valueOf = function toValue_inner() {return v;}; return v; } }); lrGeneratorMixin.closureOperation = function closureOperation (itemSet /*, closureSet*/) { var closureSet = new this.ItemSet(); var self = this; var set = itemSet, itemQueue, syms = {}; do { itemQueue = new Set(); closureSet.concat(set); set.forEach(function CO_set_forEach (item) { var symbol = item.markedSymbol; // if token is a non-terminal, recursively add closures if (symbol && self.nonterminals[symbol]) { if(!syms[symbol]) { self.nonterminals[symbol].productions.forEach(function CO_nt_forEach (production) { var newItem = new self.Item(production, 0); if(!closureSet.contains(newItem)) itemQueue.push(newItem); }); syms[symbol] = true; } } else if (!symbol) { // reduction closureSet.reductions.push(item); closureSet.inadequate = closureSet.reductions.length > 1 || closureSet.shifts; } else { // shift closureSet.shifts = true; closureSet.inadequate = closureSet.reductions.length > 0; } }); set = itemQueue; } while (!itemQueue.isEmpty()); return closureSet; }; lrGeneratorMixin.gotoOperation = function gotoOperation (itemSet, symbol) { var gotoSet = new this.ItemSet(), self = this; itemSet.forEach(function goto_forEach(item, n) { if (item.markedSymbol === symbol) { gotoSet.push(new self.Item(item.production, item.dotPosition+1, item.follows, n)); } }); return gotoSet.isEmpty() ? gotoSet : this.closureOperation(gotoSet); }; /* Create unique set of item sets * */ lrGeneratorMixin.canonicalCollection = function canonicalCollection () { var item1 = new this.Item(this.productions[0], 0, [this.EOF]); var firstState = this.closureOperation(new this.ItemSet(item1)), states = new Set(firstState), marked = 0, self = this, itemSet; states.has = {}; states.has[firstState] = 0; while (marked !== states.size()) { itemSet = states.item(marked); marked++; itemSet.forEach(function CC_itemSet_forEach (item) { if (item.markedSymbol && item.markedSymbol !== self.EOF) self.canonicalCollectionInsert(item.markedSymbol, itemSet, states, marked-1); }); } return states; }; // Pushes a unique state into the que. Some parsing algorithms may perform additional operations lrGeneratorMixin.canonicalCollectionInsert = function canonicalCollectionInsert (symbol, itemSet, states, stateNum) { var g = this.gotoOperation(itemSet, symbol); if (!g.predecessors) g.predecessors = {}; // add g to que if not empty or duplicate if (!g.isEmpty()) { var gv = g.valueOf(), i = states.has[gv]; if (i === -1 || typeof i === 'undefined') { states.has[gv] = states.size(); itemSet.edges[symbol] = states.size(); // store goto transition for table states.push(g); g.predecessors[symbol] = [stateNum]; } else { itemSet.edges[symbol] = i; // store goto transition for table states.item(i).predecessors[symbol].push(stateNum); } } }; var NONASSOC = 0; lrGeneratorMixin.parseTable = function parseTable (itemSets) { var states = [], nonterminals = this.nonterminals, operators = this.operators, conflictedStates = {}, // array of [state, token] tuples self = this, s = 1, // shift r = 2, // reduce a = 3; // accept // for each item set itemSets.forEach(function (itemSet, k) { var state = states[k] = {}; var action, stackSymbol; // set shift and goto actions for (stackSymbol in itemSet.edges) { itemSet.forEach(function (item, j) { // find shift and goto actions if (item.markedSymbol == stackSymbol) { var gotoState = itemSet.edges[stackSymbol]; if (nonterminals[stackSymbol]) { // store state to go to after a reduce //self.trace(k, stackSymbol, 'g'+gotoState); state[self.symbols_[stackSymbol]] = gotoState; } else { //self.trace(k, stackSymbol, 's'+gotoState); state[self.symbols_[stackSymbol]] = [s,gotoState]; } } }); } // set accept action itemSet.forEach(function (item, j) { if (item.markedSymbol == self.EOF) { // accept state[self.symbols_[self.EOF]] = [a]; //self.trace(k, self.EOF, state[self.EOF]); } }); var allterms = self.lookAheads ? false : self.terminals; // set reductions and resolve potential conflicts itemSet.reductions.forEach(function (item, j) { // if parser uses lookahead, only enumerate those terminals var terminals = allterms || self.lookAheads(itemSet, item); terminals.forEach(function (stackSymbol) { action = state[self.symbols_[stackSymbol]]; var op = operators[stackSymbol]; // Reading a terminal and current position is at the end of a production, try to reduce if (action || action && action.length) { var sol = resolveConflict(item.production, op, [r,item.production.id], action[0] instanceof Array ? action[0] : action); self.resolutions.push([k,stackSymbol,sol]); if (sol.bydefault) { self.conflicts++; if (!self.DEBUG) { self.warn('Conflict in grammar: multiple actions possible when lookahead token is ',stackSymbol,' in state ',k, "\n- ", printAction(sol.r, self), "\n- ", printAction(sol.s, self)); conflictedStates[k] = true; } if (self.options.noDefaultResolve) { if (!(action[0] instanceof Array)) action = [action]; action.push(sol.r); } } else { action = sol.action; } } else { action = [r,item.production.id]; } if (action && action.length) { state[self.symbols_[stackSymbol]] = action; } else if (action === NONASSOC) { state[self.symbols_[stackSymbol]] = undefined; } }); }); }); if (!self.DEBUG && self.conflicts > 0) { self.warn("\nStates with conflicts:"); each(conflictedStates, function (val, state) { self.warn('State '+state); self.warn(' ',itemSets.item(state).join("\n ")); }); } return states; }; // find states with only one action, a reduction function findDefaults (states) { var defaults = {}; states.forEach(function (state, k) { var i = 0; for (var act in state) { if ({}.hasOwnProperty.call(state, act)) i++; } if (i === 1 && state[act][0] === 2) { // only one action in state and it's a reduction defaults[k] = state[act]; } }); return defaults; } // resolves shift-reduce and reduce-reduce conflicts function resolveConflict (production, op, reduce, shift) { var sln = {production: production, operator: op, r: reduce, s: shift}, s = 1, // shift r = 2, // reduce a = 3; // accept if (shift[0] === r) { sln.msg = "Resolve R/R conflict (use first production declared in grammar.)"; sln.action = shift[1] < reduce[1] ? shift : reduce; if (shift[1] !== reduce[1]) sln.bydefault = true; return sln; } if (production.precedence === 0 || !op) { sln.msg = "Resolve S/R conflict (shift by default.)"; sln.bydefault = true; sln.action = shift; } else if (production.precedence < op.precedence ) { sln.msg = "Resolve S/R conflict (shift for higher precedent operator.)"; sln.action = shift; } else if (production.precedence === op.precedence) { if (op.assoc === "right" ) { sln.msg = "Resolve S/R conflict (shift for right associative operator.)"; sln.action = shift; } else if (op.assoc === "left" ) { sln.msg = "Resolve S/R conflict (reduce for left associative operator.)"; sln.action = reduce; } else if (op.assoc === "nonassoc" ) { sln.msg = "Resolve S/R conflict (no action for non-associative operator.)"; sln.action = NONASSOC; } } else { sln.msg = "Resolve conflict (reduce for higher precedent production.)"; sln.action = reduce; } return sln; } lrGeneratorMixin.generate = function parser_generate (opt) { opt = typal.mix.call({}, this.options, opt); var code = ""; // check for illegal identifier if (!opt.moduleName || !opt.moduleName.match(/^[A-Za-z_$][A-Za-z0-9_$]*$/)) { opt.moduleName = "parser"; } switch (opt.moduleType) { case "js": code = this.generateModule(opt); break; case "amd": code = this.generateAMDModule(opt); break; default: code = this.generateCommonJSModule(opt); break; } return code; }; lrGeneratorMixin.generateAMDModule = function generateAMDModule(opt){ opt = typal.mix.call({}, this.options, opt); var module = this.generateModule_(); var out = '\n\ndefine(function(require){\n' + module.commonCode + '\nvar parser = '+ module.moduleCode + "\n"+this.moduleInclude + (this.lexer && this.lexer.generateModule ? '\n' + this.lexer.generateModule() + '\nparser.lexer = lexer;' : '') + '\nreturn parser;' + '\n});' return out; }; lrGeneratorMixin.generateCommonJSModule = function generateCommonJSModule (opt) { opt = typal.mix.call({}, this.options, opt); var moduleName = opt.moduleName || "parser"; var out = this.generateModule(opt) + "\n\n\nif (typeof require !== 'undefined' && typeof exports !== 'undefined') {" + "\nexports.parser = "+moduleName+";" + "\nexports.Parser = "+moduleName+".Parser;" + "\nexports.parse = function () { return "+moduleName+".parse.apply("+moduleName+", arguments); };" + "\nexports.main = "+ String(opt.moduleMain || commonjsMain) + ";" + "\nif (typeof module !== 'undefined' && require.main === module) {\n" + " exports.main(process.argv.slice(1));\n}" + "\n}"; return out; }; lrGeneratorMixin.generateModule = function generateModule (opt) { opt = typal.mix.call({}, this.options, opt); var moduleName = opt.moduleName || "parser"; var out = "/* parser generated by jison " + version + " */\n" + "/*\n" + " Returns a Parser object of the following structure:\n" + "\n" + " Parser: {\n" + " yy: {}\n" + " }\n" + "\n" + " Parser.prototype: {\n" + " yy: {},\n" + " trace: function(),\n" + " symbols_: {associative list: name ==> number},\n" + " terminals_: {associative list: number ==> name},\n" + " productions_: [...],\n" + " performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$),\n" + " table: [...],\n" + " defaultActions: {...},\n" + " parseError: function(str, hash),\n" + " parse: function(input),\n" + "\n" + " lexer: {\n" + " EOF: 1,\n" + " parseError: function(str, hash),\n" + " setInput: function(input),\n" + " input: function(),\n" + " unput: function(str),\n" + " more: function(),\n" + " less: function(n),\n" + " pastInput: function(),\n" + " upcomingInput: function(),\n" + " showPosition: function(),\n" + " test_match: function(regex_match_array, rule_index),\n" + " next: function(),\n" + " lex: function(),\n" + " begin: function(condition),\n" + " popState: function(),\n" + " _currentRules: function(),\n" + " topState: function(),\n" + " pushState: function(condition),\n" + "\n" + " options: {\n" + " ranges: boolean (optional: true ==> token location info will include a .range[] member)\n" + " flex: boolean (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match)\n" + " backtrack_lexer: boolean (optional: true ==> lexer regexes are tested in order and for each matching regex the action code is invoked; the lexer terminates the scan when a token is returned by the action code)\n" + " },\n" + "\n" + " performAction: function(yy, yy_, $avoiding_name_collisions, YY_START),\n" + " rules: [...],\n" + " conditions: {associative list: name ==> set},\n" + " }\n" + " }\n" + "\n" + "\n" + " token location info (@$, _$, etc.): {\n" + " first_line: n,\n" + " last_line: n,\n" + " first_column: n,\n" + " last_column: n,\n" + " range: [start_number, end_number] (where the numbers are indexes into the input string, regular zero-based)\n" + " }\n" + "\n" + "\n" + " the parseError function receives a 'hash' object with these members for lexer and parser errors: {\n" + " text: (matched text)\n" + " token: (the produced terminal token, if any)\n" + " line: (yylineno)\n" + " }\n" + " while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: {\n" + " loc: (yylloc)\n" + " expected: (string describing the set of expected tokens)\n" + " recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error)\n" + " }\n" + "*/\n"; out += (moduleName.match(/\./) ? moduleName : "var "+moduleName) + " = " + this.generateModuleExpr(); return out; }; lrGeneratorMixin.generateModuleExpr = function generateModuleExpr () { var out = ''; var module = this.generateModule_(); out += "(function(){\n"; out += module.commonCode; out += "\nvar parser = "+module.moduleCode; out += "\n"+this.moduleInclude; if (this.lexer && this.lexer.generateModule) { out += this.lexer.generateModule(); out += "\nparser.lexer = lexer;"; } out += "\nfunction Parser () {\n this.yy = {};\n}\n" + "Parser.prototype = parser;" + "parser.Parser = Parser;" + "\nreturn new Parser;\n})();"; return out; }; function addTokenStack (fn) { var parseFn = fn; try { var ast = esprima.parse(parseFn); var stackAst = esprima.parse(String(tokenStackLex)).body[0]; stackAst.id.name = 'lex'; var labeled = JSONSelect.match(':has(:root > .label > .name:val("_token_stack"))', ast); labeled[0].body = stackAst; return escodegen.generate(ast).replace(/_token_stack:\s?/,"").replace(/\\\\n/g,"\\n"); } catch (e) { return parseFn; } } // lex function that supports token stacks function tokenStackLex() { var token; token = tstack.pop() || lexer.lex() || EOF; // if token isn't its numeric value, convert if (typeof token !== 'number') { if (token instanceof Array) { tstack = token; token = tstack.pop(); } token = self.symbols_[token] || token; } return token; } // returns parse function without error recovery code function removeErrorRecovery (fn) { var parseFn = fn; try { var ast = esprima.parse(parseFn); var labeled = JSONSelect.match(':has(:root > .label > .name:val("_handle_error"))', ast); var reduced_code = labeled[0].body.consequent.body[3].consequent.body; reduced_code[0] = labeled[0].body.consequent.body[1]; // remove the line: error_rule_depth = locateNearestErrorRecoveryRule(state); reduced_code[4].expression.arguments[1].properties.pop(); // remove the line: 'recoverable: error_rule_depth !== false' labeled[0].body.consequent.body = reduced_code; return escodegen.generate(ast).replace(/_handle_error:\s?/,"").replace(/\\\\n/g,"\\n"); } catch (e) { return parseFn; } } // Generates the code of the parser module, which consists of two parts: // - module.commonCode: initialization code that should be placed before the module // - module.moduleCode: code that creates the module object lrGeneratorMixin.generateModule_ = function generateModule_ () { var parseFn = String(parser.parse); if (!this.hasErrorRecovery) { parseFn = removeErrorRecovery(parseFn); } if (this.options['token-stack']) { parseFn = addTokenStack(parseFn); } // Generate code with fresh variable names nextVariableId = 0; var tableCode = this.generateTableCode(this.table); // Generate the initialization code var commonCode = tableCode.commonCode; // Generate the module creation code var moduleCode = "{"; moduleCode += [ "trace: " + String(this.trace || parser.trace), "yy: {}", "symbols_: " + JSON.stringify(this.symbols_), "terminals_: " + JSON.stringify(this.terminals_).replace(/"([0-9]+)":/g,"$1:"), "productions_: " + JSON.stringify(this.productions_), "performAction: " + String(this.performAction), "table: " + tableCode.moduleCode, "defaultActions: " + JSON.stringify(this.defaultActions).replace(/"([0-9]+)":/g,"$1:"), "parseError: " + String(this.parseError || (this.hasErrorRecovery ? traceParseError : parser.parseError)), "parse: " + parseFn ].join(",\n"); moduleCode += "};"; return { commonCode: commonCode, moduleCode: moduleCode } }; // Generate code that represents the specified parser table lrGeneratorMixin.generateTableCode = function (table) { var moduleCode = JSON.stringify(table); var variables = [createObjectCode]; // Don't surround numerical property name numbers in quotes moduleCode = moduleCode.replace(/"([0-9]+)"(?=:)/g, "$1"); // Replace objects with several identical values by function calls // e.g., { 1: [6, 7]; 3: [6, 7], 4: [6, 7], 5: 8 } = o([1, 3, 4], [6, 7], { 5: 8 }) moduleCode = moduleCode.replace(/\{\d+:[^\}]+,\d+:[^\}]+\}/g, function (object) { // Find the value that occurs with the highest number of keys var value, frequentValue, key, keys = {}, keyCount, maxKeyCount = 0, keyValue, keyValues = [], keyValueMatcher = /(\d+):([^:]+)(?=,\d+:|\})/g; while ((keyValue = keyValueMatcher.exec(object))) { // For each value, store the keys where that value occurs key = keyValue[1]; value = keyValue[2]; keyCount = 1; if (!(value in keys)) { keys[value] = [key]; } else { keyCount = keys[value].push(key); } // Remember this value if it is the most frequent one if (keyCount > maxKeyCount) { maxKeyCount = keyCount; frequentValue = value; } } // Construct the object with a function call if the most frequent value occurs multiple times if (maxKeyCount > 1) { // Collect all non-frequent values into a remainder object for (value in keys) { if (value !== frequentValue) { for (var k = keys[value], i = 0, l = k.length; i < l; i++) { keyValues.push(k[i] + ':' + value); } } } keyValues = keyValues.length ? ',{' + keyValues.join(',') + '}' : ''; // Create the function call `o(keys, value, remainder)` object = 'o([' + keys[frequentValue].join(',') + '],' + frequentValue + keyValues + ')'; } return object; }); // Count occurrences of number lists var list; var lists = {}; var listMatcher = /\[[0-9,]+\]/g; while (list = listMatcher.exec(moduleCode)) { lists[list] = (lists[list] || 0) + 1; } // Replace frequently occurring number lists with variables moduleCode = moduleCode.replace(listMatcher, function (list) { var listId = lists[list]; // If listId is a number, it represents the list's occurrence frequency if (typeof listId === 'number') { // If the list does not occur frequently, represent it by the list if (listId === 1) { lists[list] = listId = list; // If the list occurs frequently, represent it by a newly assigned variable } else { lists[list] = listId = createVariable(); variables.push(listId + '=' + list); } } return listId; }); // Return the variable initialization code and the table code return { commonCode: 'var ' + variables.join(',') + ';', moduleCode: moduleCode }; }; // Function that extends an object with the given value for all given keys // e.g., o([1, 3, 4], [6, 7], { x: 1, y: 2 }) = { 1: [6, 7]; 3: [6, 7], 4: [6, 7], x: 1, y: 2 } var createObjectCode = 'o=function(k,v,o,l){' + 'for(o=o||{},l=k.length;l--;o[k[l]]=v);' + 'return o}'; // Creates a variable with a unique name function createVariable() { var id = nextVariableId++; var name = '$V'; do { name += variableTokens[id % variableTokensLength]; id = ~~(id / variableTokensLength); } while (id !== 0); return name; } var nextVariableId = 0; var variableTokens = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$'; var variableTokensLength = variableTokens.length; // default main method for generated commonjs modules function commonjsMain (args) { if (!args[1]) { console.log('Usage: '+args[0]+' FILE'); process.exit(1); } var source = require('fs').readFileSync(require('path').normalize(args[1]), "utf8"); return exports.parser.parse(source); } // debug mixin for LR parser generators function printAction (a, gen) { var s = a[0] == 1 ? 'shift token (then go to state '+a[1]+')' : a[0] == 2 ? 'reduce by rule: '+gen.productions[a[1]] : 'accept' ; return s; } var lrGeneratorDebug = { beforeparseTable: function () { this.trace("Building parse table."); }, afterparseTable: function () { var self = this; if (this.conflicts > 0) { this.resolutions.forEach(function (r, i) { if (r[2].bydefault) { self.warn('Conflict at state: ',r[0], ', token: ',r[1], "\n ", printAction(r[2].r, self), "\n ", printAction(r[2].s, self)); } }); this.trace("\n"+this.conflicts+" Conflict(s) found in grammar."); } this.trace("Done."); }, aftercanonicalCollection: function (states) { var trace = this.trace; trace("\nItem sets\n------"); states.forEach(function (state, i) { trace("\nitem set",i,"\n"+state.join("\n"), '\ntransitions -> ', JSON.stringify(state.edges)); }); } }; var parser = typal.beget(); lrGeneratorMixin.createParser = function createParser () { var p = eval(this.generateModuleExpr()); // for debugging p.productions = this.productions; var self = this; function bind(method) { return function() { self.lexer = p.lexer; return self[method].apply(self, arguments); }; } // backwards compatability p.lexer = this.lexer; p.generate = bind('generate'); p.generateAMDModule = bind('generateAMDModule'); p.generateModule = bind('generateModule'); p.generateCommonJSModule = bind('generateCommonJSModule'); return p; }; parser.trace = generator.trace; parser.warn = generator.warn; parser.error = generator.error; function traceParseError (err, hash) { this.trace(err); } function parseError (str, hash) { if (hash.recoverable) { this.trace(str); } else { function _parseError (msg, hash) { this.message = msg; this.hash = hash; } _parseError.prototype = Error; throw new _parseError(str, hash); } } parser.parseError = lrGeneratorMixin.parseError = parseError; parser.parse = function parse (input) { var self = this, stack = [0], tstack = [], // token stack vstack = [null], // semantic value stack lstack = [], // location stack table = this.table, yytext = '', yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1; var args = lstack.slice.call(arguments, 1); //this.reductionCount = this.shiftCount = 0; var lexer = Object.create(this.lexer); var sharedState = { yy: {} }; // copy state for (var k in this.yy) { if (Object.prototype.hasOwnProperty.call(this.yy, k)) { sharedState.yy[k] = this.yy[k]; } } lexer.setInput(input, sharedState.yy); sharedState.yy.lexer = lexer; sharedState.yy.parser = this; if (typeof lexer.yylloc == 'undefined') { lexer.yylloc = {}; } var yyloc = lexer.yylloc; lstack.push(yyloc); var ranges = lexer.options && lexer.options.ranges; if (typeof sharedState.yy.parseError === 'function') { this.parseError = sharedState.yy.parseError; } else { this.parseError = Object.getPrototypeOf(this).parseError; } function popStack (n) { stack.length = stack.length - 2 * n; vstack.length = vstack.length - n; lstack.length = lstack.length - n; } _token_stack: var lex = function () { var token; token = lexer.lex() || EOF; // if token isn't its numeric value, convert if (typeof token !== 'number') { token = self.symbols_[token] || token; } return token; } var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected; while (true) { // retreive state number from top of stack state = stack[stack.length - 1]; // use default actions if available if (this.defaultActions[state]) { action = this.defaultActions[state]; } else { if (symbol === null || typeof symbol == 'undefined') { symbol = lex(); } // read action for current state and first input action = table[state] && table[state][symbol]; } _handle_error: // handle parse error if (typeof action === 'undefined' || !action.length || !action[0]) { var error_rule_depth; var errStr = ''; // Return the rule stack depth where the nearest error rule can be found. // Return FALSE when no error recovery rule was found. function locateNearestErrorRecoveryRule(state) { var stack_probe = stack.length - 1; var depth = 0; // try to recover from error for(;;) { // check for error recovery rule in this state if ((TERROR.toString()) in table[state]) { return depth; } if (state === 0 || stack_probe < 2) { return false; // No suitable error recovery rule available. } stack_probe -= 2; // popStack(1): [symbol, action] state = stack[stack_probe]; ++depth; } } if (!recovering) { // first see if there's any chance at hitting an error recovery rule: error_rule_depth = locateNearestErrorRecoveryRule(state); // Report error expected = []; for (p in table[state]) { if (this.terminals_[p] && p > TERROR) { expected.push("'"+this.terminals_[p]+"'"); } } if (lexer.showPosition) { errStr = 'Parse error on line '+(yylineno+1)+":\n"+lexer.showPosition()+"\nExpecting "+expected.join(', ') + ", got '" + (this.terminals_[symbol] || symbol)+ "'"; } else { errStr = 'Parse error on line '+(yylineno+1)+": Unexpected " + (symbol == EOF ? "end of input" : ("'"+(this.terminals_[symbol] || symbol)+"'")); } this.parseError(errStr, { text: lexer.match, token: this.terminals_[symbol] || symbol, line: lexer.yylineno, loc: yyloc, expected: expected, recoverable: (error_rule_depth !== false) }); } else if (preErrorSymbol !== EOF) { error_rule_depth = locateNearestErrorRecoveryRule(state); } // just recovered from another error if (recovering == 3) { if (symbol === EOF || preErrorSymbol === EOF) { throw new Error(errStr || 'Parsing halted while starting to recover from another error.'); } // discard current lookahead and grab another yyleng = lexer.yyleng; yytext = lexer.yytext; yylineno = lexer.yylineno; yyloc = lexer.yylloc; symbol = lex(); } // try to recover from error if (error_rule_depth === false) { throw new Error(errStr || 'Parsing halted. No suitable error recovery rule available.'); } popStack(error_rule_depth); preErrorSymbol = (symbol == TERROR ? null : symbol); // save the lookahead token symbol = TERROR; // insert generic error symbol as new lookahead state = stack[stack.length-1]; action = table[state] && table[state][TERROR]; recovering = 3; // allow 3 real symbols to be shifted before reporting a new error } // this shouldn't happen, unless resolve defaults are off if (action[0] instanceof Array && action.length > 1) { throw new Error('Parse Error: multiple actions possible at state: '+state+', token: '+symbol); } switch (action[0]) { case 1: // shift //this.shiftCount++; stack.push(symbol); vstack.push(lexer.yytext); lstack.push(lexer.yylloc); stack.push(action[1]); // push state symbol = null; if (!preErrorSymbol) { // normal execution/no error yyleng = lexer.yyleng; yytext = lexer.yytext; yylineno = lexer.yylineno; yyloc = lexer.yylloc; if (recovering > 0) { recovering--; } } else { // error just occurred, resume old lookahead f/ before error symbol = preErrorSymbol; preErrorSymbol = null; } break; case 2: // reduce //this.reductionCount++; len = this.productions_[action[1]][1]; // perform semantic action yyval.$ = vstack[vstack.length-len]; // default to $$ = $1 // default location, uses first token for firsts, last for lasts yyval._$ = { first_line: lstack[lstack.length-(len||1)].first_line, last_line: lstack[lstack.length-1].last_line, first_column: lstack[lstack.length-(len||1)].first_column, last_column: lstack[lstack.length-1].last_column }; if (ranges) { yyval._$.range = [lstack[lstack.length-(len||1)].range[0], lstack[lstack.length-1].range[1]]; } r = this.performAction.apply(yyval, [yytext, yyleng, yylineno, sharedState.yy, action[1], vstack, lstack].concat(args)); if (typeof r !== 'undefined') { return r; } // pop off stack if (len) { stack = stack.slice(0,-1*len*2); vstack = vstack.slice(0, -1*len); lstack = lstack.slice(0, -1*len); } stack.push(this.productions_[action[1]][0]); // push nonterminal (reduce) vstack.push(yyval.$); lstack.push(yyval._$); // goto new state = table[STATE][NONTERMINAL] newState = table[stack[stack.length-2]][stack[stack.length-1]]; stack.push(newState); break; case 3: // accept return true; } } return true; }; parser.init = function parser_init (dict) { this.table = dict.table; this.defaultActions = dict.defaultActions; this.performAction = dict.performAction; this.productions_ = dict.productions_; this.symbols_ = dict.symbols_; this.terminals_ = dict.terminals_; }; /* * LR(0) Parser * */ var lr0 = generator.beget(lookaheadMixin, lrGeneratorMixin, { type: "LR(0)", afterconstructor: function lr0_afterconstructor () { this.buildTable(); } }); var LR0Generator = exports.LR0Generator = lr0.construct(); /* * Simple LALR(1) * */ var lalr = generator.beget(lookaheadMixin, lrGeneratorMixin, { type: "LALR(1)", afterconstructor: function (grammar, options) { if (this.DEBUG) this.mix(lrGeneratorDebug, lalrGeneratorDebug); // mixin debug methods options = options || {}; this.states = this.canonicalCollection(); this.terms_ = {}; var newg = this.newg = typal.beget(lookaheadMixin,{ oldg: this, trace: this.trace, nterms_: {}, DEBUG: false, go_: function (r, B) { r = r.split(":")[0]; // grab state # B = B.map(function (b) { return b.slice(b.indexOf(":")+1); }); return this.oldg.go(r, B); } }); newg.nonterminals = {}; newg.productions = []; this.inadequateStates = []; // if true, only lookaheads in inadequate states are computed (faster, larger table) // if false, lookaheads for all reductions will be computed (slower, smaller table) this.onDemandLookahead = options.onDemandLookahead || false; this.buildNewGrammar(); newg.computeLookaheads(); this.unionLookaheads(); this.table = this.parseTable(this.states); this.defaultActions = findDefaults(this.table); }, lookAheads: function LALR_lookaheads (state, item) { return (!!this.onDemandLookahead && !state.inadequate) ? this.terminals : item.follows; }, go: function LALR_go (p, w) { var q = parseInt(p, 10); for (var i=0;i=0;--k) { ar[a[k]] = true; } for (var i=b.length-1;i >= 0;--i) { if (!ar[b[i]]) { a.push(b[i]); } } return a; } }); if (typeof exports !== 'undefined') exports.Set = Set; jison-9f2f188419f7790a46a5e9a6c882834d0fa16314/lib/util/typal.js000664 000000 000000 00000005430 12652507276 022574 0ustar00rootroot000000 000000 /* * Introduces a typal object to make classical/prototypal patterns easier * Plus some AOP sugar * * By Zachary Carter * MIT Licensed * */ var typal = (function () { var create = Object.create || function (o) { function F(){} F.prototype = o; return new F(); }; var position = /^(before|after)/; // basic method layering // always returns original method's return value function layerMethod(k, fun) { var pos = k.match(position)[0], key = k.replace(position, ''), prop = this[key]; if (pos === 'after') { this[key] = function () { var ret = prop.apply(this, arguments); var args = [].slice.call(arguments); args.splice(0, 0, ret); fun.apply(this, args); return ret; }; } else if (pos === 'before') { this[key] = function () { fun.apply(this, arguments); var ret = prop.apply(this, arguments); return ret; }; } } // mixes each argument's own properties into calling object, // overwriting them or layering them. i.e. an object method 'meth' is // layered by mixin methods 'beforemeth' or 'aftermeth' function typal_mix() { var self = this; for(var i=0,o,k; i (http://zaa.ch)", "name": "jison", "description": "A parser generator with Bison's API", "version": "0.4.17", "license": "MIT", "keywords": [ "jison", "bison", "yacc", "parser", "generator", "lexer", "flex", "tokenizer", "compiler" ], "preferGlobal": true, "repository": { "type": "git", "url": "git://github.com/zaach/jison.git" }, "bugs": { "email": "jison@librelist.com", "url": "http://github.com/zaach/jison/issues" }, "main": "lib/jison", "bin": "lib/cli.js", "engines": { "node": ">=0.4" }, "dependencies": { "JSONSelect": "0.4.0", "esprima": "1.1.x", "escodegen": "1.3.x", "jison-lex": "0.3.x", "ebnf-parser": "0.1.10", "lex-parser": "~0.1.3", "nomnom": "1.5.2", "cjson": "0.3.0" }, "devDependencies": { "test": "0.6.x", "jison": "0.4.x", "uglify-js": "~2.4.0", "browserify": "2.x.x" }, "scripts": { "test": "node tests/all-tests.js" }, "homepage": "http://jison.org" }