I am trying to parse for loops having this type of syntax:
for(loop = 1:10) {
}
In my grammar I have the rules:
genericString %= lexeme[+(char_("a-zA-Z"))];
intRule %= int_;
commandString %= lexeme[+(char_ - '}')];
forLoop %= string("for")
>> '('
>> genericString // variable e.g. c
>> '='
>> (intRule | genericString) // variable e.g. i
>> ':'
>> (intRule | genericString) // variable e.g. j
>> ')' >> '{'
>> (forLoop | commandString)
>> '}';
While this works for the simple example above, it fails to parse the following nested example:
for(loop = 1:10) {
for(inner = 1:10) {
}
}
I am guessing it's due to the parser 'getting confused' with brace placement. I think I need to do something like that presented at http://boost-spirit.com/distrib/spirit_1_7_0/libs/spirit/example/fundamental/lazy_parser.cpp (alas, I found it difficult to follow).
Cheers,
Ben.
EDIT 1:
I am now thinking it would be better to handle the recursion from the commandString (called nestedBlock below) rather than within the forLoop, i.e., something like:
forLoop %= string("for")
>> '('
>> genericString // variable e.g. c
>> '='
>> (intRule | genericString) // variable e.g. i
>> ':'
>> (intRule | genericString) // variable e.g. j
>> ')'
>> nestedBlock;
nestedBlock %= lexeme['{' >> -(char_ - '}' - '{')
>> -nestedBlock
>> -(char_ - '}' - '{')
>> '}'];
which is failing with massive boost::spriti errors. The rules are defined as:
qi::rule<Iterator, std::string(), ascii::space_type> nestedBlock;
qi::rule<Iterator, Function(), ascii::space_type> forLoop;
Function is a struct of boost::variants
EDIT 2:
So this is what I now have (which is designed to work with or without nested structures):
commandCollection %= *start;
forLoop %= string("for")
>> '('
>> genericString // variable e.g. c
>> '='
>> (intRule | genericString) // variable e.g. i
>> ':'
>> (intRule | genericString) // variable e.g. j
>> ')'
>> '{'
>> commandCollection
>> '}';
start %= loadParams | restoreGenomeData | openGenomeData | initNeat | initEvo |
initAllPositions | initAllAgents | initCoreSimulationPointers |
resetSimulationKernel | writeStats | restoreSimState |
run | simulate | removeObjects | setGeneration |
setParam | getParam | pause | create | reset |
loadAgents | getAgent | setAgent | listParams | loadScript | forLoop
| wait | commentFunc | var | add | sub | mult | div | query;
And I declare the commandCollection rule as follows:
qi::rule<Iterator, boost::fusion::vector<Function>, ascii::space_type> commandCollection;
I assumed that this would do as I expect. The commandCollection is defined as 0 or more commands which should be stored in a boost::fusion::vector. However, when I come to extract the vector from the Function() struct (bearing in mind the start rule uses a Function() iterator), the type for some reason is not identified as a boost::fusion::vector so cannot be extracted. I'm not sure why...
However, if I were to just have
commandCollection %= start;
and decalre the rule as
qi::rule<Iterator, Function(), ascii::space_type> commandCollection;
and then try to extract the data as a single Function() struct, it works fine. But I would like it to store multiple commands (i.e. *start) in some kind of container. I also tried with a std::vector but this also failed.
fusion::vector<Function>()
withstd::vector<Function()>
) – sehe