-
Notifications
You must be signed in to change notification settings - Fork 4
Description
For context, this problem showed up in ableC, where we are trying to use the C preprocessor tags to control the disambiguation of identifiers, based on whether we are currently parsing a system header file. These preprocessor tags are recognized as a layout terminal, with a semantic action that sets a parser attribute which is later referenced in a disambiguation function.
The following is a simple example in Silver:
grammar layoutactions;
parser attribute isMarked :: Boolean action { isMarked = false; };
ignore terminal Marker_t '#'
action {
print "Shifted Marker";
isMarked = true;
};
terminal Id1_t /[a-zA-Z]+/ action { print "Shifted Id1"; };
terminal Id2_t /[a-zA-Z]+/ action { print "Shifted Id2"; };
disambiguate Id1_t, Id2_t {
print "Disambiguating Id";
pluck if isMarked then Id1_t else Id2_t;
}
nonterminal Foo;
concrete productions top::Foo
| Id1_t {} action { print "Reduced 1"; }
| Id2_t {} action { print "Reduced 2"; }
parser parse :: Foo { layoutactions; }
function main
IOVal<Integer> ::= args::[String] ioin::IO
{
local result::ParseResult<Foo> = parse(head(args), "test");
return
if null(args) then ioval(print("no argument\n", ioin), 1)
else if !result.parseSuccess then ioval(print(result.parseErrors ++ "\n", ioin), 0)
else ioval(ioin, 0);
}
When run on the input #a, this prints
Disambiguating Id
Shifted Marker
Shifted Id2
Reduced 2
The disambiguation function is being called before the semantic action for '#' has been run, thus giving the wrong result.
As a (very hacky) workaround, one can introduce a second, ambiguous layout terminal and use a disambiguation function to update the parser attribute in the disambiguation function:
ignore terminal Marker2_t '#';
disambiguate Marker_t, Marker2_t {
print "Disambiguating Marker";
isMarked = true;
pluck Marker_t;
}
This gives the desired output of
Disambiguating Marker
Disambiguating Id
Shifted Marker
Shifted Id1
Reduced 1
This workaround does work in the context of ableC but is something that we would greatly wish to avoid.
Since we evidently know which layout terminal is going to be shifted as soon as the disambiguation function is run, why aren't the semantic actions executed immediately, before attempting to disambiguate the next terminal? I vaguely remember there being a reason for this, but I don't remember what it was.