1

I have a simple parser in PEGjs

start = val
ln = [\n\r]
float = digits:$[-0-9\.]+ { return parseFloat(digits, 10) }
str = str:$(!ln !"\"" .)+
val = float / str

and I try to match

-this

But instead of getting "str" it gives error on parsing "float"

Line 1, column 2: Expected [\-0-9.] or end of input but "t" found.
Kengur
  • 19
  • 4

2 Answers2

0

float = digits:$([-0-9.]+ !str) { return parseFloat(digits, 10) }

That fixed it. But this is extremely counterintuitive to what I used to learn during writing a 350ish line parser...

Kengur
  • 19
  • 4
  • I gave an answer above that I think actually solves the problem. I am pretty sure your parser shown here accepts strings that is isn't supposed to. By all means help me understand if I'm wrong about this. – Alan Mimms Oct 11 '16 at 20:58
0

The problem is that - is in what some parser folks call the "leading set" for float so the parser, having no idea that what follows isn't a float, merrily goes along and tries to parse one. The Parsing Expression Grammar style of parser implemented by PEGjs doesn't do backtracking within a symbol.

The only way to avoid this is to give the parser more information about what you're trying to do to avoid the leading set ambiguity you introduced by allowing - in the leading set of str and in float. You could fix this another way, by forcing the parser to require [0-9]+ after it sees -. In fact, I suspect your grammar is not accurately representing what you want to accomplish since it permits strings like 0123-456 or 123.456-789.987.123 as float as well. You need to force the - as the optional first character of a float and then require a string of digits to make it do floats right anyway.

I suggest you write your grammar like this:

start = val
ln = [\n\r]
float = digits:$('-'? [0-9]+ '.'? [0-9]*
               / '-'? '.' [0-9]+) { return parseFloat(digits, 10) }
str = str:$(!ln !"\"" .)+
val = float / str

The first part of float captures the case where there are digits before the decimal point or the decimal point is missing. The second part captures the case where there are no digits before the decimal point, but it is present, and it enforces the requirement of digits after the decimal point in this case.

The fact that you have val = float / str rather than val = str / float is critical also. You have to try to match a float before you try to match a str for this to work. I'm not really sure about that definition for str, but I don't know the language you're trying to parse.

Alan Mimms
  • 651
  • 9
  • 22