public void Action(Expansion e) { if (e is Sequence) { if (e.Parent is Choice || e.Parent is ZeroOrMore || e.Parent is OneOrMore || e.Parent is ZeroOrOne) { return; } Sequence seq = (Sequence)e; Lookahead la = (Lookahead)(seq.Units[0]); if (!la.IsExplicit) { return; } // Create a singleton choice with an empty action. Choice ch = new Choice(); ch.Line = la.Line; ch.Column = la.Column; ch.Parent = seq; Sequence seq1 = new Sequence(); seq1.Line = la.Line; seq1.Column = la.Column; seq1.Parent = ch; seq1.Units.Add(la); la.Parent = seq1; Action act = new Action(); act.Line = la.Line; act.Column = la.Column; act.Parent = seq1; seq1.Units.Add(act); ch.Choices.Add(seq1); if (la.Amount != 0) { if (la.ActionTokens.Count != 0) { CSharpCCErrors.Warning(la, "Encountered LOOKAHEAD(...) at a non-choice location. " + "Only semantic lookahead will be considered here."); } else { CSharpCCErrors.Warning(la, "Encountered LOOKAHEAD(...) at a non-choice location. This will be ignored."); } } // Now we have moved the lookahead into the singleton choice. Now create // a new dummy lookahead node to replace this one at its original location. Lookahead la1 = new Lookahead(); la1.IsExplicit = false; la1.Line = la.Line; la1.Column = la.Column; la1.Parent = seq; // Now set the la_expansion field of la and la1 with a dummy expansion (we use EOF). la.Expansion = new REndOfFile(); la1.Expansion = new REndOfFile(); seq.Units[0] = la1; seq.Units[1] = ch; } }
public void CheckUnmatchability() { RegularExpression curRE; int numStrings = 0; for (int i = 0; i < choices.Count; i++) { if (!(curRE = choices[i]).IsPrivate && //curRE instanceof RJustName && curRE.Ordinal > 0 && curRE.Ordinal < Ordinal && LexGen.lexStates[curRE.Ordinal] == LexGen.lexStates[Ordinal]) { if (Label != null) { CSharpCCErrors.Warning(this, "Regular Expression choice : " + curRE.Label + " can never be matched as : " + Label); } else { CSharpCCErrors.Warning(this, "Regular Expression choice : " + curRE.Label + " can never be matched as token of kind : " + Ordinal); } } if (!curRE.IsPrivate && curRE is RStringLiteral) { numStrings++; } } }
public static void ebnfCalc(Expansion exp, Expansion nested) { // exp is one of OneOrMore, ZeroOrMore, ZeroOrOne MatchInfo m, m1 = null; IList <MatchInfo> v, first, follow; int la; for (la = 1; la <= Options.getOtherAmbiguityCheck(); la++) { MatchInfo.laLimit = la; LookaheadWalk.sizeLimitedMatches = new List <MatchInfo>(); m = new MatchInfo(); m.firstFreeLoc = 0; v = new List <MatchInfo>(); v.Add(m); LookaheadWalk.considerSemanticLA = !Options.getForceLaCheck(); LookaheadWalk.genFirstSet(v, nested); first = LookaheadWalk.sizeLimitedMatches; LookaheadWalk.sizeLimitedMatches = new List <MatchInfo>(); LookaheadWalk.considerSemanticLA = false; LookaheadWalk.genFollowSet(v, exp, Expansion.NextGenerationIndex++); follow = LookaheadWalk.sizeLimitedMatches; if (la == 1) { if (CodeCheck(first)) { CSharpCCErrors.Warning(nested, "CSHARPCODE non-terminal within " + image(exp) + " construct will force this construct to be entered in favor of " + "expansions occurring after construct."); } } if ((m = overlap(first, follow)) == null) { break; } m1 = m; } if (la > Options.getOtherAmbiguityCheck()) { CSharpCCErrors.Warning("Choice conflict in " + image(exp) + " construct " + "at line " + exp.Line + ", column " + exp.Column + "."); Console.Error.WriteLine(" Expansion nested within construct and expansion following construct"); Console.Error.WriteLine(" have common prefixes, one of which is: " + image(m1)); Console.Error.WriteLine(" Consider using a lookahead of " + la + " or more for nested expansion."); } else if (la > 1) { CSharpCCErrors.Warning("Choice conflict in " + image(exp) + " construct " + "at line " + exp.Line + ", column " + exp.Column + "."); Console.Error.WriteLine(" Expansion nested within construct and expansion following construct"); Console.Error.WriteLine(" have common prefixes, one of which is: " + image(m1)); Console.Error.WriteLine(" Consider using a lookahead of " + la + " for nested expansion."); } }
public static void add_token_manager_decls(Token t, IList <Token> decls) { if (CSharpCCGlobals.token_mgr_decls != null) { CSharpCCErrors.ParseError(t, "Multiple occurrence of \"TOKEN_MGR_DECLS\"."); } else { CSharpCCGlobals.token_mgr_decls = decls; if (Options.getUserTokenManager()) { CSharpCCErrors.Warning(t, "Ignoring declarations in \"TOKEN_MGR_DECLS\" since option " + "USER_TOKEN_MANAGER has been set to true."); } } }
public static void Normalize() { if (getDebugLookahead() && !getDebugParser()) { if (cmdLineSetting.Contains("DEBUG_PARSER") || inputFileSetting.Contains("DEBUG_PARSER")) { CSharpCCErrors.Warning("True setting of option DEBUG_LOOKAHEAD overrides " + "false setting of option DEBUG_PARSER."); } optionValues.Add("DEBUG_PARSER", true); } // Now set the "GENERATE" options from the supplied (or default) JDK version. optionValues["GENERATE_CHAINED_EXCEPTION"] = clrVersionAtLeast(1.1); optionValues["GENERATE_GENERICS"] = clrVersionAtLeast(2.0); optionValues["GENERATE_STRING_BUILDER"] = clrVersionAtLeast(1.1); }
public static void SetInputFileOption(object nameloc, object valueloc, string name, object value) { string s = name.ToUpper(); if (!optionValues.ContainsKey(s)) { CSharpCCErrors.Warning(nameloc, "Bad option name \"" + name + "\". Option setting will be ignored."); return; } object existingValue; value = UpgradeValue(name, value); if (optionValues.TryGetValue(s, out existingValue)) { if ((existingValue.GetType() != value.GetType()) || (value is int && ((int)value) <= 0)) { CSharpCCErrors.Warning(valueloc, "Bad option value \"" + value + "\" for \"" + name + "\". Option setting will be ignored."); return; } if (inputFileSetting.Contains(s)) { CSharpCCErrors.Warning(nameloc, "Duplicate option setting for \"" + name + "\" will be ignored."); return; } if (cmdLineSetting.Contains(s)) { if (!existingValue.Equals(value)) { CSharpCCErrors.Warning(nameloc, "Command line setting of \"" + name + "\" modifies option value in file."); } return; } } optionValues[s] = value; inputFileSetting.Add(s); }
public static void CreateOutputDir(string outputDir) { if (!Directory.Exists(outputDir)) { CSharpCCErrors.Warning("Output directory \"" + outputDir + "\" does not exist. Creating the directory."); if (Directory.CreateDirectory(outputDir) == null) { CSharpCCErrors.SemanticError("Cannot create the output directory : " + outputDir); return; } } /* * TODO: * if (!outputDir.canWrite()) * { * CSharpCCErrors.SemanticError("Cannot write to the output output directory : \"" + outputDir + "\""); * return; * } */ }
public static void addregexpr(TokenProduction p) { int ii; CSharpCCGlobals.rexprlist.Add(p); if (Options.getUserTokenManager()) { if (p.LexStates == null || p.LexStates.Length != 1 || !p.LexStates[0].Equals("DEFAULT")) { CSharpCCErrors.Warning(p, "Ignoring lexical state specifications since option " + "USER_TOKEN_MANAGER has been set to true."); } } if (p.LexStates == null) { return; } for (int i = 0; i < p.LexStates.Length; i++) { for (int j = 0; j < i; j++) { if (p.LexStates[i].Equals(p.LexStates[j])) { CSharpCCErrors.ParseError(p, "Multiple occurrence of \"" + p.LexStates[i] + "\" in lexical state list."); } } if (!CSharpCCGlobals.lexstate_S2I.ContainsKey(p.LexStates[i])) { ii = nextFreeLexState++; CSharpCCGlobals.lexstate_S2I[p.LexStates[i]] = ii; CSharpCCGlobals.lexstate_I2S[ii] = p.LexStates[i]; CSharpCCGlobals.simple_tokens_table[p.LexStates[i]] = new Dictionary <string, IDictionary <string, RegularExpression> >(); } } }
public static void choiceCalc(Choice choice) { int first = firstChoice(choice); // dbl[i] and dbr[i] are lists of size limited matches for choice i // of choice. dbl ignores matches with semantic lookaheads (when force_la_check // is false), while dbr ignores semantic lookahead. IList <MatchInfo>[] dbl = new IList <MatchInfo> [choice.Choices.Count]; IList <MatchInfo>[] dbr = new IList <MatchInfo> [choice.Choices.Count]; int[] minLA = new int[choice.Choices.Count - 1]; MatchInfo[] overlapInfo = new MatchInfo[choice.Choices.Count - 1]; int[] other = new int[choice.Choices.Count - 1]; MatchInfo m; IList <MatchInfo> v; bool overlapDetected; for (int la = 1; la <= Options.getChoiceAmbiguityCheck(); la++) { MatchInfo.laLimit = la; LookaheadWalk.considerSemanticLA = !Options.getForceLaCheck(); for (int i = first; i < choice.Choices.Count - 1; i++) { LookaheadWalk.sizeLimitedMatches = new List <MatchInfo>(); m = new MatchInfo(); m.firstFreeLoc = 0; v = new List <MatchInfo>(); v.Add(m); LookaheadWalk.genFirstSet(v, (Expansion)choice.Choices[i]); dbl[i] = LookaheadWalk.sizeLimitedMatches; } LookaheadWalk.considerSemanticLA = false; for (int i = first + 1; i < choice.Choices.Count; i++) { LookaheadWalk.sizeLimitedMatches = new List <MatchInfo>(); m = new MatchInfo(); m.firstFreeLoc = 0; v = new List <MatchInfo>(); v.Add(m); LookaheadWalk.genFirstSet(v, (Expansion)choice.Choices[i]); dbr[i] = LookaheadWalk.sizeLimitedMatches; } if (la == 1) { for (int i = first; i < choice.Choices.Count - 1; i++) { Expansion exp = (Expansion)choice.Choices[i]; if (Semanticize.EmptyExpansionExists(exp)) { CSharpCCErrors.Warning(exp, "This choice can expand to the empty token sequence " + "and will therefore always be taken in favor of the choices appearing later."); break; } else if (CodeCheck(dbl[i])) { CSharpCCErrors.Warning(exp, "CSHARPCODE non-terminal will force this choice to be taken " + "in favor of the choices appearing later."); break; } } } overlapDetected = false; for (int i = first; i < choice.Choices.Count - 1; i++) { for (int j = i + 1; j < choice.Choices.Count; j++) { if ((m = overlap(dbl[i], dbr[j])) != null) { minLA[i] = la + 1; overlapInfo[i] = m; other[i] = j; overlapDetected = true; break; } } } if (!overlapDetected) { break; } } for (int i = first; i < choice.Choices.Count - 1; i++) { if (explicitLA((Expansion)choice.Choices[i]) && !Options.getForceLaCheck()) { continue; } if (minLA[i] > Options.getChoiceAmbiguityCheck()) { CSharpCCErrors.Warning("Choice conflict involving two expansions at"); Console.Error.Write(" line " + ((Expansion)choice.Choices[i]).Line); Console.Error.Write(", column " + ((Expansion)choice.Choices[i]).Column); Console.Error.Write(" and line " + ((Expansion)choice.Choices[other[i]]).Line); Console.Error.Write(", column " + ((Expansion)choice.Choices[other[i]]).Column); Console.Error.WriteLine(" respectively."); Console.Error.WriteLine(" A common prefix is: " + image(overlapInfo[i])); Console.Error.WriteLine(" Consider using a lookahead of " + minLA[i] + " or more for earlier expansion."); } else if (minLA[i] > 1) { CSharpCCErrors.Warning("Choice conflict involving two expansions at"); Console.Error.Write(" line " + ((Expansion)choice.Choices[i]).Line); Console.Error.Write(", column " + ((Expansion)choice.Choices[i]).Column); Console.Error.Write(" and line " + ((Expansion)choice.Choices[other[i]]).Line); Console.Error.Write(", column " + ((Expansion)choice.Choices[other[i]]).Column); Console.Error.WriteLine(" respectively."); Console.Error.WriteLine(" A common prefix is: " + image(overlapInfo[i])); Console.Error.WriteLine(" Consider using a lookahead of " + minLA[i] + " for earlier expansion."); } } }
public static void start() { Token t = null; keepLineCol = Options.getKeepLineColumn(); if (CSharpCCErrors.ErrorCount != 0) { throw new MetaParseException(); } CSharpFiles.GenerateTokenManagerError(); CSharpFiles.GenerateParseException(); CSharpFiles.GenerateToken(); if (Options.getUserTokenManager()) { CSharpFiles.GenerateITokenManager(); } else if (Options.getUserCharStream()) { CSharpFiles.GenerateICharStream(); } else { if (Options.getUnicodeEscape()) { CSharpFiles.GenerateUnicodeCharStream(); } else { CSharpFiles.GenerateSimpleCharStream(); } } try { ostr = new StreamWriter( new BufferedStream( new FileStream(Path.Combine(Options.getOutputDirectory().FullName, CSharpCCGlobals.cu_name + "Constants.cs"), FileMode.OpenOrCreate, FileAccess.Write), 8192)); } catch (IOException) { CSharpCCErrors.SemanticError("Could not open file " + CSharpCCGlobals.cu_name + "Constants.cs for writing."); throw new InvalidOperationException(); } List <string> tn = new List <string>(CSharpCCGlobals.ToolNames); tn.Add(CSharpCCGlobals.ToolName); ostr.WriteLine("/* " + CSharpCCGlobals.GetIdString(tn, CSharpCCGlobals.cu_name + "Constants.cs") + " */"); bool namespaceInserted = false; if (CSharpCCGlobals.cu_to_insertion_point_1.Count != 0 && CSharpCCGlobals.cu_to_insertion_point_1[0].kind == CSharpCCParserConstants.NAMESPACE) { namespaceInserted = true; for (int i = 1; i < CSharpCCGlobals.cu_to_insertion_point_1.Count; i++) { if (CSharpCCGlobals.cu_to_insertion_point_1[i].kind == CSharpCCParserConstants.SEMICOLON) { CSharpCCGlobals.PrintTokenSetup(CSharpCCGlobals.cu_to_insertion_point_1[0]); for (int j = 0; j <= i; j++) { t = (CSharpCCGlobals.cu_to_insertion_point_1[j]); if (t.kind != CSharpCCParserConstants.SEMICOLON) { CSharpCCGlobals.PrintToken(t, ostr); } } CSharpCCGlobals.PrintTrailingComments(t, ostr); break; } } ostr.WriteLine("{"); } ostr.WriteLine(""); ostr.WriteLine("/// <summary>"); ostr.WriteLine("/// Token literal values and constants."); ostr.WriteLine("/// <summary>"); if (Options.getSupportClassVisibilityPublic()) { ostr.Write("public "); } ostr.WriteLine("class " + CSharpCCGlobals.cu_name + "Constants {"); ostr.WriteLine(""); ostr.WriteLine(" /// <summary> End of File</summary>"); ostr.WriteLine(" public const int EOF = 0;"); foreach (RegularExpression re in CSharpCCGlobals.ordered_named_tokens) { ostr.WriteLine(" /// <summary>RegularExpression Id.</summary>"); ostr.WriteLine(" public const int " + re.Label + " = " + re.Ordinal + ";"); } ostr.WriteLine(""); if (!Options.getUserTokenManager() && Options.getBuildTokenManager()) { for (int i = 0; i < LexGen.lexStateName.Length; i++) { ostr.WriteLine(" /// <summary>Lexical state.</summary>"); ostr.WriteLine(" public const int " + LexGen.lexStateName[i] + " = " + i + ";"); } ostr.WriteLine(""); } ostr.WriteLine(" /// <summary>Literal token values.</summary>"); ostr.WriteLine(" public static readonly string[] TokenImage = {"); ostr.WriteLine(" \"<EOF>\","); foreach (TokenProduction tp in CSharpCCGlobals.rexprlist) { IList <RegExprSpec> respecs = tp.RegexSpecs; foreach (RegExprSpec res in respecs) { RegularExpression re = res.RegularExpression; if (re is RStringLiteral) { ostr.WriteLine(" \"\\\"" + CSharpCCGlobals.AddEscapes(CSharpCCGlobals.AddEscapes(((RStringLiteral)re).Image)) + "\\\"\","); } else if (!re.Label.Equals("")) { ostr.WriteLine(" \"<" + re.Label + ">\","); } else { if (re.TokenProductionContext.Kind == TokenProduction.TOKEN) { CSharpCCErrors.Warning(re, "Consider giving this non-string token a label for better error reporting."); } ostr.WriteLine(" \"<token of kind " + re.Ordinal + ">\","); } } } ostr.WriteLine(" };"); ostr.WriteLine(""); ostr.WriteLine("}"); if (namespaceInserted) { ostr.WriteLine("}"); } ostr.Close(); }
public static void start() { if (CSharpCCErrors.ErrorCount != 0) { throw new MetaParseException(); } if (Options.getLookahead() > 1 && !Options.getForceLaCheck() && Options.getSanityCheck()) { CSharpCCErrors.Warning("Lookahead adequacy checking not being performed since option LOOKAHEAD " + "is more than 1. Set option FORCE_LA_CHECK to true to force checking."); } /* * The following walks the entire parse tree to convert all LOOKAHEAD's * that are not at choice points (but at beginning of sequences) and converts * them to trivial choices. This way, their semantic lookahead specification * can be evaluated during other lookahead evaluations. */ foreach (var production in CSharpCCGlobals.bnfproductions) { ExpansionTreeWalker.PostOrderWalk(production.Expansion, new LookaheadFixer()); } /* * The following loop populates "production_table" */ foreach (var p in CSharpCCGlobals.bnfproductions) { if (CSharpCCGlobals.production_table.ContainsKey(p.Lhs)) { CSharpCCErrors.SemanticError(p, p.Lhs + " occurs on the left hand side of more than one production."); } else { CSharpCCGlobals.production_table[p.Lhs] = p; } } /* * The following walks the entire parse tree to make sure that all * non-terminals on RHS's are defined on the LHS. */ foreach (var production in CSharpCCGlobals.bnfproductions) { ExpansionTreeWalker.PreOrderWalk(production.Expansion, new ProductionDefinedChecker()); } /* * The following loop ensures that all target lexical states are * defined. Also piggybacking on this loop is the detection of * <EOF> and <name> in token productions. After reporting an * error, these entries are removed. Also checked are definitions * on inline private regular expressions. * This loop works slightly differently when USER_TOKEN_MANAGER * is set to true. In this case, <name> occurrences are OK, while * regular expression specs generate a warning. */ foreach (var tp in CSharpCCGlobals.rexprlist) { IList <RegExprSpec> respecs = tp.RegexSpecs; foreach (var res in respecs) { if (res.NextState != null) { if (!CSharpCCGlobals.lexstate_S2I.ContainsKey(res.NextState)) { CSharpCCErrors.SemanticError(res.NextStateToken, "Lexical state \"" + res.NextState + "\" has not been defined."); } } if (res.RegularExpression is REndOfFile) { //CSharpCCErrors.SemanticError(res.RegularExpression, "Badly placed <EOF>."); if (tp.LexStates != null) { CSharpCCErrors.SemanticError(res.RegularExpression, "EOF action/state change must be specified for all states, " + "i.e., <*>TOKEN:."); } if (tp.Kind != TokenProduction.TOKEN) { CSharpCCErrors.SemanticError(res.RegularExpression, "EOF action/state change can be specified only in a " + "TOKEN specification."); } if (CSharpCCGlobals.nextStateForEof != null || CSharpCCGlobals.actForEof != null) { CSharpCCErrors.SemanticError(res.RegularExpression, "Duplicate action/state change specification for <EOF>."); } CSharpCCGlobals.actForEof = res.Action; CSharpCCGlobals.nextStateForEof = res.NextState; prepareToRemove(respecs, res); } else if (tp.IsExplicit && Options.getUserTokenManager()) { CSharpCCErrors.Warning(res.RegularExpression, "Ignoring regular expression specification since " + "option USER_TOKEN_MANAGER has been set to true."); } else if (tp.IsExplicit && !Options.getUserTokenManager() && res.RegularExpression is RJustName) { CSharpCCErrors.Warning(res.RegularExpression, "Ignoring free-standing regular expression reference. " + "If you really want this, you must give it a different label as <NEWLABEL:<" + res.RegularExpression.Label + ">>."); prepareToRemove(respecs, res); } else if (!tp.IsExplicit && res.RegularExpression.IsPrivate) { CSharpCCErrors.SemanticError(res.RegularExpression, "Private (#) regular expression cannot be defined within " + "grammar productions."); } } } removePreparedItems(); /* * The following loop inserts all names of regular expressions into * "named_tokens_table" and "ordered_named_tokens". * Duplications are flagged as errors. */ foreach (var tp in CSharpCCGlobals.rexprlist) { IList <RegExprSpec> respecs = tp.RegexSpecs; foreach (var res in respecs) { if (!(res.RegularExpression is RJustName) && !String.IsNullOrEmpty(res.RegularExpression.Label)) { string s = res.RegularExpression.Label; if (CSharpCCGlobals.named_tokens_table.ContainsKey(s)) { CSharpCCErrors.SemanticError(res.RegularExpression, "Multiply defined lexical token name \"" + s + "\"."); } else { CSharpCCGlobals.named_tokens_table[s] = res.RegularExpression; CSharpCCGlobals.ordered_named_tokens.Add(res.RegularExpression); } if (CSharpCCGlobals.lexstate_S2I.ContainsKey(s)) { CSharpCCErrors.SemanticError(res.RegularExpression, "Lexical token name \"" + s + "\" is the same as " + "that of a lexical state."); } } } } /* * The following code merges multiple uses of the same string in the same * lexical state and produces error messages when there are multiple * explicit occurrences (outside the BNF) of the string in the same * lexical state, or when within BNF occurrences of a string are duplicates * of those that occur as non-TOKEN's (SKIP, MORE, SPECIAL_TOKEN) or private * regular expressions. While doing this, this code also numbers all * regular expressions (by setting their ordinal values), and populates the * table "names_of_tokens". */ CSharpCCGlobals.tokenCount = 1; foreach (var tp in CSharpCCGlobals.rexprlist) { IList <RegExprSpec> respecs = tp.RegexSpecs; if (tp.LexStates == null) { tp.LexStates = new String[CSharpCCGlobals.lexstate_I2S.Count]; int i = 0; foreach (var value in CSharpCCGlobals.lexstate_I2S.Values) { tp.LexStates[i++] = value; } } var table = new IDictionary <string, IDictionary <string, RegularExpression> > [tp.LexStates.Length]; for (int i = 0; i < tp.LexStates.Length; i++) { IDictionary <string, IDictionary <string, RegularExpression> > toSet; if (CSharpCCGlobals.simple_tokens_table.TryGetValue(tp.LexStates[i], out toSet)) { table[i] = toSet; } else { table[i] = null; } } foreach (var res in respecs) { if (res.RegularExpression is RStringLiteral) { RStringLiteral sl = (RStringLiteral)res.RegularExpression; // This loop performs the checks and actions with respect to each lexical state. for (int i = 0; i < table.Length; i++) { // Get table of all case variants of "sl.Image" into table2. IDictionary <string, RegularExpression> table2; if (!table[i].TryGetValue(sl.Image.ToUpper(), out table2)) { // There are no case variants of "sl.Image" earlier than the current one. // So go ahead and insert this item. if (sl.Ordinal == 0) { sl.Ordinal = CSharpCCGlobals.tokenCount++; } table2 = new Dictionary <string, RegularExpression>(); table2[sl.Image] = sl; table[i][sl.Image.ToUpper()] = table2; } else if (hasIgnoreCase(table2, sl.Image)) { // hasIgnoreCase sets "other" if it is found. // Since IGNORE_CASE version exists, current one is useless and bad. if (!sl.TokenProductionContext.IsExplicit) { // inline BNF string is used earlier with an IGNORE_CASE. CSharpCCErrors.SemanticError(sl, "String \"" + sl.Image + "\" can never be matched " + "due to presence of more general (IGNORE_CASE) regular expression " + "at line " + other.Line + ", column " + other.Column + "."); } else { // give the standard error message. CSharpCCErrors.SemanticError(sl, "Duplicate definition of string token \"" + sl.Image + "\" " + "can never be matched."); } } else if (sl.TokenProductionContext.IgnoreCase) { // This has to be explicit. A warning needs to be given with respect // to all previous strings. String pos = ""; int count = 0; foreach (var rexp in table2.Values) { if (count != 0) { pos += ","; } pos += " line " + rexp.Line; count++; } if (count == 1) { CSharpCCErrors.Warning(sl, "String with IGNORE_CASE is partially superceded by string at" + pos + "."); } else { CSharpCCErrors.Warning(sl, "String with IGNORE_CASE is partially superceded by strings at" + pos + "."); } // This entry is legitimate. So insert it. if (sl.Ordinal == 0) { sl.Ordinal = CSharpCCGlobals.tokenCount++; } table2[sl.Image] = sl; // The above "put" may override an existing entry (that is not IGNORE_CASE) and that's // the desired behavior. } else { // The rest of the cases do not involve IGNORE_CASE. RegularExpression re; if (!table2.TryGetValue(sl.Image, out re)) { if (sl.Ordinal == 0) { sl.Ordinal = CSharpCCGlobals.tokenCount++; } table2[sl.Image] = sl; } else if (tp.IsExplicit) { // This is an error even if the first occurrence was implicit. if (tp.LexStates[i].Equals("DEFAULT")) { CSharpCCErrors.SemanticError(sl, "Duplicate definition of string token \"" + sl.Image + "\"."); } else { CSharpCCErrors.SemanticError(sl, "Duplicate definition of string token \"" + sl.Image + "\" in lexical state \"" + tp.LexStates[i] + "\"."); } } else if (re.TokenProductionContext.Kind != TokenProduction.TOKEN) { CSharpCCErrors.SemanticError(sl, "String token \"" + sl.Image + "\" has been defined as a \"" + TokenProduction.kindImage[re.TokenProductionContext.Kind] + "\" token."); } else if (re.IsPrivate) { CSharpCCErrors.SemanticError(sl, "String token \"" + sl.Image + "\" has been defined as a private regular expression."); } else { // This is now a legitimate reference to an existing RStringLiteral. // So we assign it a number and take it out of "rexprlist". // Therefore, if all is OK (no errors), then there will be only unequal // string literals in each lexical state. Note that the only way // this can be legal is if this is a string declared inline within the // BNF. Hence, it belongs to only one lexical state - namely "DEFAULT". sl.Ordinal = re.Ordinal; prepareToRemove(respecs, res); } } } } else if (!(res.RegularExpression is RJustName)) { res.RegularExpression.Ordinal = CSharpCCGlobals.tokenCount++; } if (!(res.RegularExpression is RJustName) && !String.IsNullOrEmpty(res.RegularExpression.Label)) { CSharpCCGlobals.names_of_tokens[res.RegularExpression.Ordinal] = res.RegularExpression.Label; } if (!(res.RegularExpression is RJustName)) { CSharpCCGlobals.rexps_of_tokens[res.RegularExpression.Ordinal] = res.RegularExpression; } } } removePreparedItems(); /* * The following code performs a tree walk on all regular expressions * attaching links to "RJustName"s. Error messages are given if * undeclared names are used, or if "RJustNames" refer to private * regular expressions or to regular expressions of any kind other * than TOKEN. In addition, this loop also removes top level * "RJustName"s from "rexprlist". * This code is not executed if Options.getUserTokenManager() is set to * true. Instead the following block of code is executed. */ if (!Options.getUserTokenManager()) { FixRJustNames frjn = new FixRJustNames(); foreach (var tp in CSharpCCGlobals.rexprlist) { IList <RegExprSpec> respecs = tp.RegexSpecs; foreach (var res in respecs) { frjn.root = res.RegularExpression; ExpansionTreeWalker.PreOrderWalk(res.RegularExpression, frjn); if (res.RegularExpression is RJustName) { prepareToRemove(respecs, res); } } } } removePreparedItems(); /* * The following code is executed only if Options.getUserTokenManager() is * set to true. This code visits all top-level "RJustName"s (ignores * "RJustName"s nested within regular expressions). Since regular expressions * are optional in this case, "RJustName"s without corresponding regular * expressions are given ordinal values here. If "RJustName"s refer to * a named regular expression, their ordinal values are set to reflect this. * All but one "RJustName" node is removed from the lists by the end of * execution of this code. */ if (Options.getUserTokenManager()) { foreach (var tp in CSharpCCGlobals.rexprlist) { IList <RegExprSpec> respecs = tp.RegexSpecs; foreach (var res in respecs) { if (res.RegularExpression is RJustName) { RJustName jn = (RJustName)res.RegularExpression; RegularExpression rexp; if (!CSharpCCGlobals.named_tokens_table.TryGetValue(jn.Label, out rexp)) { jn.Ordinal = CSharpCCGlobals.tokenCount++; CSharpCCGlobals.named_tokens_table[jn.Label] = jn; CSharpCCGlobals.ordered_named_tokens.Add(jn); CSharpCCGlobals.names_of_tokens[jn.Ordinal] = jn.Label; } else { jn.Ordinal = rexp.Ordinal; prepareToRemove(respecs, res); } } } } } removePreparedItems(); /* * The following code is executed only if Options.getUserTokenManager() is * set to true. This loop labels any unlabeled regular expression and * prints a warning that it is doing so. These labels are added to * "ordered_named_tokens" so that they may be generated into the ...Constants * file. */ if (Options.getUserTokenManager()) { foreach (var tp in CSharpCCGlobals.rexprlist) { IList <RegExprSpec> respecs = tp.RegexSpecs; foreach (var res in respecs) { int ii = res.RegularExpression.Ordinal; if (!CSharpCCGlobals.names_of_tokens.ContainsKey(ii)) { CSharpCCErrors.Warning(res.RegularExpression, "Unlabeled regular expression cannot be referred to by " + "user generated token manager."); } } } } if (CSharpCCErrors.ErrorCount != 0) { throw new MetaParseException(); } // The following code sets the value of the "emptyPossible" field of NormalProduction // nodes. This field is initialized to false, and then the entire list of // productions is processed. This is repeated as long as at least one item // got updated from false to true in the pass. bool emptyUpdate = true; while (emptyUpdate) { emptyUpdate = false; foreach (var prod in CSharpCCGlobals.bnfproductions) { if (EmptyExpansionExists(prod.Expansion)) { if (!prod.IsEmptyPossible) { emptyUpdate = prod.IsEmptyPossible = true; } } } } if (Options.getSanityCheck() && CSharpCCErrors.ErrorCount == 0) { // The following code checks that all ZeroOrMore, ZeroOrOne, and OneOrMore nodes // do not contain expansions that can expand to the empty token list. foreach (var prod in CSharpCCGlobals.bnfproductions) { ExpansionTreeWalker.PreOrderWalk(prod.Expansion, new EmptyChecker()); } // The following code goes through the productions and adds pointers to other // productions that it can expand to without consuming any tokens. Once this is // done, a left-recursion check can be performed. foreach (var prod in CSharpCCGlobals.bnfproductions) { addLeftMost(prod, prod.Expansion); } // Now the following loop calls a recursive walk routine that searches for // actual left recursions. The way the algorithm is coded, once a node has // been determined to participate in a left recursive loop, it is not tried // in any other loop. foreach (var prod in CSharpCCGlobals.bnfproductions) { if (prod.WalkStatus == 0) { prodWalk(prod); } } // Now we do a similar, but much simpler walk for the regular expression part of // the grammar. Here we are looking for any kind of loop, not just left recursions, // so we only need to do the equivalent of the above walk. // This is not done if option USER_TOKEN_MANAGER is set to true. if (!Options.getUserTokenManager()) { foreach (var tp in CSharpCCGlobals.rexprlist) { IList <RegExprSpec> respecs = tp.RegexSpecs; foreach (var res in respecs) { RegularExpression rexp = res.RegularExpression; if (rexp.WalkStatus == 0) { rexp.WalkStatus = -1; if (rexpWalk(rexp)) { loopString = "..." + rexp.Label + "... --> " + loopString; CSharpCCErrors.SemanticError(rexp, "Loop in regular expression detected: \"" + loopString + "\""); } rexp.WalkStatus = 1; } } } } /* * The following code performs the lookahead ambiguity checking. */ if (CSharpCCErrors.ErrorCount == 0) { foreach (var prod in CSharpCCGlobals.bnfproductions) { ExpansionTreeWalker.PreOrderWalk(prod.Expansion, new LookaheadChecker()); } } } // matches "if (Options.getSanityCheck()) {" if (CSharpCCErrors.ErrorCount != 0) { throw new MetaParseException(); } }