4

I am looking at the calc source here http://epaperpress.com/lexandyacc/

I see theses lines in calc.y

| expr '+' expr         { $$ = opr('+', 2, $1, $3); }
| expr '-' expr         { $$ = opr('-', 2, $1, $3); }
| expr '*' expr         { $$ = opr('*', 2, $1, $3); }
| expr '/' expr         { $$ = opr('/', 2, $1, $3); }
| expr '<' expr         { $$ = opr('<', 2, $1, $3); }
| expr '>' expr         { $$ = opr('>', 2, $1, $3); }

Is there a way to group them? so i can write something like the below instead?

| expr mathOp expr         { $$ = opr(mathOp, 2, $1, $3); }
| expr cmpOp  expr         { $$ = opr(cmpOp, 2, $1, $3); }

NOTE: I am using bison.

  • Why wouldn't you go all the way and combine mathOp/cmpOp as well? – paxdiablo Sep 11 '09 at 13:49
  • @pax: cmp ops return bools, math returns the same type it is (think C#. 0!=false). I assume its easier to separate. –  Sep 11 '09 at 15:15
  • Why think C#? You're using Bison, and therefore C/C++. It's far easier to combine, especially if you're going to be calling the same function anyway. – Chris Lutz Sep 22 '09 at 03:11

2 Answers2

6

The problem with grouping them like that is that you lose the precedences on the rules -- you only have one rule that has different precedence depending on which mathop it is, which bison/yacc cannot handle. That said, you CAN group ops of the same precedence level together

expr: expr mulOp expr { $$ = opr($2, 2, $1, $3); } %prec '*'
    | expr addOp expr { $$ = opr($2, 2, $1, $3); } %prec '+'
    | expr relOp expr { $$ = opr($2, 2, $1, $3); } %prec '<'
             :

mulOp: '*' { $$ = '*'; }
     | '/' { $$ = '/'; }
;
Chris Dodd
  • 119,907
  • 13
  • 134
  • 226
  • +1 for mentioning precedence! But why not group * and / at the lexer stage? – Chris Lutz Sep 22 '09 at 03:16
  • You could group at the lexer stage, but that might introduce problems if you use these character tokens in other contexts (eg, unary '*' for pointer dereference) – Chris Dodd Sep 23 '09 at 17:11
1

You can do it in 2 ways:

  • At lex stage define recognition of operators and provide terminal symbol (in you syntax mathOp) with value of operator '+', '-' ...
  • Using mathOp as nonterminal you can return some associated value:

    mathOp : '+' { $$ = '+'; } | '-' { $$ = '-'; } ...

Then usage will look like (pay attention to $2):

| expr mathOp expr         { $$ = opr($2, 2, $1, $3); }

may be you would like to define more complicated mathOp then use %type

Dewfy
  • 23,277
  • 13
  • 73
  • 121