/// <summary> /// Parses a rule, one rule per line, from the lexer. /// Adds to the existing hashmap if there's already a rule there. /// </summary> GrammarRuleNode ParseRule(IEvolutionState state, IGELexer lexer, GPFunctionSet gpfs) { GrammarRuleNode retResult = null; string token = lexer.NextToken(); if (lexer.MatchingIndex == COMMENT) { return(null); //ignore the comment } if (lexer.MatchingIndex == RULE) //rule head, good, as expected... { lexer.NextToken(); if (lexer.MatchingIndex != EQUALS) { state.Output.Fatal("GE Grammar Error: Expecting equal sign after rule head: " + token); } retResult = GetRule(_rules, token); ParseProductions(state, retResult, lexer, gpfs); } else { state.Output.Fatal("GE Grammar Error - Unexpected token: Expecting rule head.: " + token); } return(retResult); // IMPLEMENTED // Need to parse the rule using a recursive descent parser // If there was an error, then try to call state.output.error(...). // // Don't merge into any existing rule -- I do that in parseRules below. Instead, just pull out // rules and hang them into your "new rule" as necessary. // Use getRule(rules, "<rulename>") to extract the rule representing the current rule name which you // can hang inside there as necessary. // // If you have to you can call state.output.fatal(...) which will terminate the program, // but piling up some errors might be useful. I'll handle the exitIfErors() in parseRules below // // Return null if there was no rule to parse (blank line or all comments) but no errors. // Also return null if you called state.output.error(...). }
/// <summary> /// Parses each of a rule's production choices. /// </summary> void ParseProductions(IEvolutionState state, GrammarRuleNode retResult, IGELexer lexer, GPFunctionSet gpfs) { do { var token = lexer.NextToken(); if (lexer.MatchingIndex == RULE) { retResult.AddChoice(GetRule(_rules, token)); token = lexer.NextToken(); } else { if (lexer.MatchingIndex != LPAREN) //first expect '(' { state.Output.Fatal("GE Grammar Error - Unexpected token for rule: " + retResult.Head + "Expecting '('."); } token = lexer.NextToken(); if (lexer.MatchingIndex != FUNCTION) //now expecting function { state.Output.Fatal("GE Grammar Error - Expecting a function name after first '(' for rule: " + retResult.Head + " Error: " + token); } else { if (!gpfs.NodesByName.ContainsKey(token)) { state.Output.Fatal("GPNode " + token + " is not defined in the function set."); } var grammarfuncnode = new GrammarFunctionNode(gpfs, token); token = lexer.NextToken(); while (lexer.MatchingIndex != RPAREN) { if (lexer.MatchingIndex != RULE) //this better be the name of a rule node { state.Output.Fatal( "GE Grammar Error - Expecting a rule name as argument for function definition: " + grammarfuncnode.Head + " Error on : " + token); } grammarfuncnode.AddArgument(GetRule(_rules, token)); token = lexer.NextToken(); } retResult.AddChoice(grammarfuncnode); } //after right paren, should see either '|' or newline token = lexer.NextToken(); if (lexer.MatchingIndex != PIPE && lexer.MatchingIndex != Constants.GE_LEXER_FAILURE) { state.Output.Fatal("GE Grammar Error - Expecting either '|' delimiter or newline. Error on : " + token); } } } while (lexer.MatchingIndex == PIPE); }