2

I'm trying to create a grammar for a programming language in Jison, and have run into a problem with calls. Functions in my language is invoked with the following syntax:

functionName arg1 arg2 arg3

In order to do arguments that aren't just simple expressions, they need to be wrapped in parenthesizes like this:

functionName (1 + 2) (3 + 3) (otherFunction 5)

However, there is a bug in my grammar that causes my parser to interpret functionName arg1 arg2 arg3 as functionName(arg1(arg2(arg3))) instead of functionName(arg1, arg2, arg3).

The relevant part of my jison grammar file looks like this:

expr:
  | constantExpr         { $$ = $1; }
  | binaryExpr           { $$ = $1; }
  | callExpr             { $$ = $1; }
  | tupleExpr            { $$ = $1; }
  | parenExpr            { $$ = $1; }
  | identExpr            { $$ = $1; }
  | blockExpr            { $$ = $1; }
  ;

callArgs:
  | callArgs expr { $$ = $1.concat($2); }
  | expr                     { $$ = [$1]; }
  ;

callExpr:
  | path callArgs { $$ = ast.Expr.Call($1, $2); }
  ;

identExpr:
  | path                 { $$ = ast.Expr.Ident($1); }
  ;

How can I make Jison prefer the callArgs rather than the expr?

Alxandr
  • 12,345
  • 10
  • 59
  • 95

2 Answers2

1

You might be able to do this by playing games with precedence relations, but I think the most straightforward solution is to be clear.

What you want to say is that callArgs cannot directly contain a callExpr. As in your example, if you want to pass a callExpr as an argument, you need to enclose it in parentheses, in which case it will match some other production (presumably parenExpr).

So you can write that directly:

callArgExpr
  : constantExpr
  | binaryExpr
  | tupleExpr
  | parenExpr
  | identExpr
  | blockExpr
  ;

expr
  : callArgExpr
  | callExpr
  ;

callArgs
  : callArgs callArgExpr   { $$ = $1.concat($2); }
  | callArgExpr            { $$ = [$1]; }
  ;

callExpr
  : path callArgs          { $$ = ast.Expr.Call($1, $2); }
  ;

In fact, it's likely that you want to restrict callArgs even further, since (if I understand correctly) func a + b does not mean "apply a+b to func", which would have been written func (a + b). So you might want to also remove binaryExpr from callArgExpr, and possibly some other. I hope the model above shows how to do that.

By the way, I removed all the empty productions, assuming that they were unintentional (unless jison has some exception for that syntax; I'm not really a jison expert). And I removed { $$ = $1; }, which I believe is as unnecessary in jison as in the classic yacc/bison/etc., since it is the default action.

rici
  • 234,347
  • 28
  • 237
  • 341
0

It is important to review other parts of your grammar to give a precise answer. I do not know if what I think is right, but from what I saw in your code, you could create a rule explicitly for the arguments in the order that you want without nesting one inside the other:

args:
    |    "(" simple_expression ")" args { /*Do something with $2*/ }
    |    "\n"
    ;

I hope this has helped you a little. Greetings.

Tomás Juárez
  • 1,517
  • 3
  • 21
  • 51
  • I think you misunderstood the question. I do not want to wrap arguments in parenthesizes. Only compound arguments. `a b c d` in my grammar should mean `a(b, c, d)` in traditional C like languages. – Alxandr Jan 19 '15 at 13:58