5

I have had a look at the PEG.js parser generator for JavaScript. It looks pretty nice!

I don't have much experience with specifying grammars. I am searching for help to extend the example grammar at 1 a bit to allow for

  1. Decimal numbers
  2. Operator ^
  3. Predefined functions (not function declarations, only to call some functions that I specify beforehand), where arguments themselves are first order expressions, e.g. f(g(2+4) + 3)
  4. Variables A-Z (not declarations, only usage definitions -- these are meant to point to a input box that also contains a program, letters A to Z are sufficient)

Can you help me with where to find help to do that?

mikldk
  • 194
  • 1
  • 4

2 Answers2

5

Here's quick demo:

{
  variables = { 
    PI : Math.PI, 
    E  : Math.E 
  };
  functions = {
    squared : function(n) { return n * n; },
    incr    : function(n) { return n + 1; }
  }
}

start
 = additive

additive
 = left:multiplicative "+" right:additive { return left + right; }
 / multiplicative

multiplicative
 = left:power "*" right:additive { return left * right; }
 / power

// evaluated left to right!
power
 = left:primary "^" right:additive { return Math.pow(left, right); }
 / primary

primary
 = integer
 / "(" e:additive ")"      { return e; }
 / i:id "(" e:additive ")" { return functions[i.join("")](e); }
 / i:id                    { return variables[i.join("")]; }

integer
  = digits:[0-9]+ { return parseInt(digits.join(""), 10); }

id
 = [a-zA-Z]+

If you now test the parser (online) with the input:

PI+incr(squared(3))^2

you will see it being evaluated as:

103.1415926535898
Bart Kiers
  • 166,582
  • 36
  • 299
  • 288
  • Thanks! To add decimal numbers, I added the shippet from [here](http://nathansuniversity.com/turtle1.html) containing `number` and `number_frac` together with putting it in first priority in `primary` rule. Please see my answer for the updated grammar. Does that look right? – mikldk Nov 06 '14 at 08:02
  • Though it looks like to me that integer rule would never be used. Is that correct? – mikldk Nov 06 '14 at 08:10
  • @mikldk, why would it not be used? If it wouldn't, there would never be any correctly evaluated expression (which there *are*). – Bart Kiers Nov 06 '14 at 10:33
  • Sorry, I should have been more precise: In the updated grammer including (decimal) numbers, it seems like to me that integer cannot be reached: number is before integer in primary rule, and number has the regex `frac:number_frac?`. Hence, it seems like number would also catch integers. And integer rule can be removed. Or have I missed/misunderstood something? The downside would of course be that all numbers would be floats, integers would not exists. – mikldk Nov 07 '14 at 11:44
  • is it possible to inject runtime variables or functions instead of predefined in pegjs grammar file? – Simon J. Liu Jun 29 '18 at 00:13
  • @SimonJ.Liu I dont know, feel free to ask a new question. – Bart Kiers Jun 29 '18 at 04:53
-1
{
  variables = { 
    PI : Math.PI, 
    E  : Math.E 
  };
  functions = {
    squared : function(n) { return n * n; },
    incr    : function(n) { return n + 1; }
  }
}

start
 = additive

additive
 = left:multiplicative "+" right:additive { return left + right; }
 / multiplicative

multiplicative
 = left:power "*" right:power { return left * right; }
 / power

// evaluated left to right!
power
 = left:primary "^" right:primary { return Math.pow(left, right); }
 / primary

primary
 = number
 / integer
 / "(" e:additive ")"      { return e; }
 / i:id "(" e:additive ")" { return functions[i.join("")](e); }
 / i:id                    { return variables[i.join("")]; }

number_frac
    = "." chars:[0-9]* { return "." + chars.join(''); }

number
    = chars:[0-9]+ frac:number_frac? { return parseFloat(chars.join('') + frac); }

integer
  = digits:[0-9]+ { return parseInt(digits.join(""), 10); }

id
 = [a-zA-Z]+
mikldk
  • 194
  • 1
  • 4