Skip to content

Commit

Permalink
Merge pull request #185 from cdibbs/namedvals
Browse files Browse the repository at this point in the history
Named values enhancement (#184).
  • Loading branch information
zaach committed Sep 1, 2013
2 parents 2d5e4f7 + f905490 commit ef26476
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 5 deletions.
7 changes: 7 additions & 0 deletions examples/classy_test.src
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class Chris extends Person {
}

main {
var string cool;
printnat(cool);
}
126 changes: 126 additions & 0 deletions examples/nv_classy_ast.jison
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/* 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;}
;

25 changes: 20 additions & 5 deletions lib/jison.js
Original file line number Diff line number Diff line change
Expand Up @@ -284,12 +284,21 @@ generator.buildProductions = function buildProductions(bnf, productions, nonterm
var count = {},
names = {};
for (i=0;i<rhs.length;i++) {
if (names[rhs[i]]) {
names[rhs[i]+(++count[rhs[i]])] = i+1;
// check for aliased names, e.g., id[alias]
var rhs_i = rhs[i].match(/\[[a-zA-Z][a-zA-Z0-9_-]*\]/);
if (rhs_i) {
rhs_i = rhs_i[0].substr(1, rhs_i[0].length-2);
rhs[i] = rhs[i].substr(0, rhs[i].indexOf('['));
} else {
names[rhs[i]] = i+1;
names[rhs[i]+"1"] = i+1;
count[rhs[i]] = 1;
rhs_i = rhs[i];
}

if (names[rhs_i]) {
names[rhs_i + (++count[rhs_i])] = i+1;
} else {
names[rhs_i] = i+1;
names[rhs_i + "1"] = i+1;
count[rhs_i] = 1;
}
}
action = action.replace(/\$([a-zA-Z][a-zA-Z0-9_]*)/g, function (str, pl) {
Expand All @@ -312,19 +321,25 @@ generator.buildProductions = function buildProductions(bnf, productions, nonterm
});
actions.push(action);

// done with aliases; strip them.
rhs = rhs.map(function(e,i) { return e.replace(/\[[a-zA-Z_][a-zA-Z0-9_-]*\]/g, '') });
r = new Production(symbol, rhs, productions.length+1);
// precedence specified also
if (handle[2] && operators[handle[2].prec]) {
r.precedence = operators[handle[2].prec].precedence;
}
} else {
// no action -> 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<rhs.length; i++) {
if (rhs[i] === 'error') her = true;
Expand Down
44 changes: 44 additions & 0 deletions tests/parser/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -460,3 +460,47 @@ exports["test parse params"] = function() {

assert.equal(parser.parse('y', "foo", "bar"), "foobar", "semantic action");
};

exports["test symbol aliases"] = function() {
var lexData = {
rules: [
["a", "return 'a';"],
["b", "return 'b';"],
["c", "return 'c';"]
]
};
var grammar = {
bnf: {
"pgm" :[ ["expr[alice] expr[bob] expr[carol]", "return $alice+$bob+$carol;"] ],
"expr" :[ ["a", "$$ = 'a';"],
["b", "$$ = 'b';"],
["c", "$$ = 'c';"] ]
}
};

var parser = new Jison.Parser(grammar);
parser.lexer = new RegExpLexer(lexData);
assert.equal(parser.parse('abc'), "abc", "should return original string");
};

exports["test symbol aliases in ebnf"] = function() {
var lexData = {
rules: [
["a", "return 'a';"],
["b", "return 'b';"],
["c", "return 'c';"]
]
};
var grammar = {
ebnf: {
"pgm" :[ ["expr[alice] (expr[bob] expr[carol])+", "return $alice+$2;"] ],
"expr" :[ ["a", "$$ = 'a';"],
["b", "$$ = 'b';"],
["c", "$$ = 'c';"] ]
}
};

var parser = new Jison.Parser(grammar);
parser.lexer = new RegExpLexer(lexData);
assert.equal(parser.parse('abc'), "ab", "should tolerate aliases in subexpression");
};

0 comments on commit ef26476

Please sign in to comment.