PEG.js users, help me to decide what the right semantics is

191 views
Skip to first unread message

David Majda

unread,
Jun 17, 2012, 8:08:14 AM6/17/12
to pegjs
Hi,

I have a simple question for all PEG.js users. Given the following
grammar, what output (final value of "n") would you expect for input
"ac" and why?

{ var n = 0; }
start = (a "b") / (a "c") { return n; }
a = "a" { n++; }

I am especially interested to hear answers from people who are not
that familiar with PEG.js. Answering this question will help me
resolve issue #77 (https://github.com/dmajda/pegjs/issues/77) the
right way.

Thanks,
--
David Majda
Entropy fighter
http://majda.cz/

Guilherme Vieira

unread,
Jun 17, 2012, 8:22:28 AM6/17/12
to da...@majda.cz, pegjs
I'd say the most "correct" answer would be 1, because even though the "a" is matched twice, we're only interested in its computation of the "valid syntax path for the given input 'ac'". I could understand and (I think) tolerate, though, that since "a" is in fact matched twice, its action block would also be executed twice. However I see no reason for doing this (you could just match it but ignore the action block unless it is part of a valid syntax parse). Or, ideally, you would leave that option to the grammar writers somehow, on a per-rule basis.

Just my two cents.

Excellent work, as usual, with PEG.js. Please keep it up; this project is extremely useful for a lot of people.

-- 
Atenciosamente / Sincerely,
Guilherme Prá Vieira (a.k.a. "n2liquid")

Guilherme Vieira

unread,
Jun 17, 2012, 8:25:36 AM6/17/12
to da...@majda.cz, pegjs
Oh, and I also feel it's a little counterintuitive that an action block whose return value is essentially discarded has its side-effects sustained, even though that might be helpful in some cases (hence me saying it could be a good idea to be able to "flip a switch" to enable this behavior on a per-rule basis).


-- 
Atenciosamente / Sincerely,
Guilherme Prá Vieira (a.k.a. "n2liquid")



Ivan Žužak

unread,
Jun 17, 2012, 11:19:20 AM6/17/12
to da...@majda.cz, pegjs
Hi,

I would expect that the final value of "n" is 2. Here's why -- since
the code block within curly braces constitutes an action and that
action returns a value which determines whether the rule containing
the action is a match or not, the action *must* be executed.
Otherwise, how would you determine if the rule containing the action
is a match? That action of rule a in your example could have contained
code that returns null in some cases, and should therefore be executed
in order to determine whether rule a matches.

So, the way actions and predicates are defined now in PEGjs
(http://pegjs.majda.cz/documentation) - I think that actions should be
executed as the parser reaches them i.e. I don't think it is OK to
delay execution of actions for later. I would suggest that, if such
behavior is needed, that another type of code blocks is defined, let's
call it "delayed action". This "delayed action" would be defined with
a special syntax. Example:

{ var n = 0; }
start = (a "b") / (a "c") { return n; }
a = "a" ${ n++; }

In this case, the action in rule a ( {n++; } ) is defined as a
"delayed action" ($) and is therefore never executed when the parser
arrives upon it. Rather, the parser assumes that the action will
return a non-null value, stores the action and resumes parsing. If an
alternative of a rule is not matched, the actions stored for that
alternative (and all nested rules that were parsed) are discarded and
the other alternative of the rule is used for parsing, and the actions
for that alternative are stored in the same way. However, if the
parser successfully parses the whole input - it goes back and runs the
stored actions in the right sequence.

In the example -- the parser will try to match the first alternative
of rule start ("ab"), it will successfully match rule a and it will
store (not execute) the action in rule a. However, the parser will
discard the stored action once it detects that there is no "b" to
match the alternative. Next, the parser will try to match the second
alternative of rule start ("ac"), the action of rule a will be stored
again, the whole alternative "ac" will successfully match, and
therefore the stored action will be executed and n will be 1.

Best,
Ivan

Guilherme Vieira

unread,
Jun 17, 2012, 11:31:56 PM6/17/12
to izu...@gmail.com, da...@majda.cz, pegjs
I guess Ivan is right. I forgot about the effects of returning null in an action block.

-- 
Atenciosamente / Sincerely,
Guilherme Prá Vieira (a.k.a. "n2liquid")


David Majda

unread,
Jul 29, 2012, 9:51:06 AM7/29/12
to pegjs
2012/6/17 David Majda <da...@majda.cz>:
> I have a simple question for all PEG.js users. Given the following
> grammar, what output (final value of "n") would you expect for input
> "ac" and why?
>
> { var n = 0; }
> start = (a "b") / (a "c") { return n; }
> a = "a" { n++; }

Thanks everyone for their answers. It may not be obvious but you
helped me a lot!
Reply all
Reply to author
Forward
0 new messages