From e92384f424bf95b9888f04872cbfe7e6c4745cfb Mon Sep 17 00:00:00 2001 From: lichx Date: Tue, 24 Dec 2024 16:17:20 +0800 Subject: [PATCH] =?UTF-8?q?[Feature]=20=E5=86=99=E5=AE=8C=E4=BA=86=20?= =?UTF-8?q?=E6=89=93=E6=AD=BB=E4=B8=8D=E6=94=B9=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CompilerDesignIflr1/LR1Creator.cs | 22 +- CompilerDesignIflr1/LR1Unit.cs | 18 +- CompilerDesignIflr1/LexicalAnalysis.cs | 36 +- CompilerDesignIflr1/Program.cs | 4 +- CompilerDesignIflr1/SemanticAnalysis.cs | 1032 ++++++++++++++++++ CompilerDesignIflr1/StateMachine.cs | 19 +- CompilerDesignIflr1/files/code | 21 +- CompilerDesignIflr1/files/if-grammar.grammar | 26 +- CompilerDesignIflr1/files/newGrammar | 88 ++ CompilerDesignIflr1/files/oldGrammar | 90 ++ 10 files changed, 1308 insertions(+), 48 deletions(-) create mode 100644 CompilerDesignIflr1/SemanticAnalysis.cs create mode 100644 CompilerDesignIflr1/files/newGrammar create mode 100644 CompilerDesignIflr1/files/oldGrammar diff --git a/CompilerDesignIflr1/LR1Creator.cs b/CompilerDesignIflr1/LR1Creator.cs index 396a293..1a89247 100644 --- a/CompilerDesignIflr1/LR1Creator.cs +++ b/CompilerDesignIflr1/LR1Creator.cs @@ -229,16 +229,18 @@ namespace CompilerDesignIFlr1 { string subValue = value.Substring(last, i - last); last = i + 1; - if (GrammarUnit.ContainsKey(subValue.Trim())) - grammar.Add(subValue.Trim()); - else if (TokenUnit.ContainsKey(subValue.Trim())) - grammar.Add(subValue.Trim()); - else - { - if (subValue.Trim().Length == 0) - break; - throw new Exception("Grammar can't be recognized. " + subValue); - } + if (GrammarUnit.ContainsKey(subValue.Trim())) + grammar.Add(subValue.Trim()); + else if (TokenUnit.ContainsKey(subValue.Trim())) + grammar.Add(subValue.Trim()); + else if (subValue.StartsWith('(') && subValue.EndsWith(')')) + grammar.Add(GrammarUnitCreate(subValue.Substring(1, subValue.Length - 2))); + else + { + if (subValue.Trim().Length == 0) + break; + throw new Exception("Grammar can't be recognized. " + subValue); + } break; } case '|': diff --git a/CompilerDesignIflr1/LR1Unit.cs b/CompilerDesignIflr1/LR1Unit.cs index d17249b..56b7c97 100644 --- a/CompilerDesignIflr1/LR1Unit.cs +++ b/CompilerDesignIflr1/LR1Unit.cs @@ -49,9 +49,24 @@ namespace CompilerDesignIFlr1 Grammar = grammar; } + public LR1Unit(int id, string type, string name, int quadrupleIndex, string value, HashSet prospect, int pointPosition, List grammar) + { + Id = id; + Type = type; + Name = name; + QuadrupleIndex = quadrupleIndex; + Value = value; + Prospect = prospect; + PointPosition = pointPosition; + Grammar = grammar; + } + + internal LR1Unit Clone() => + new LR1Unit(Id, Type, Name, 0, Value,new HashSet(Prospect), PointPosition, [.. Grammar]); internal int Id { get; set; } = -1; internal string Type { get; set; } = ""; internal string Name { get; set; } = ""; + internal int QuadrupleIndex { get; set; } = 0; internal string Value { get; set; } = ""; internal HashSet Prospect { get; set; } = []; internal int PointPosition { get; set; } = 0; @@ -93,9 +108,6 @@ namespace CompilerDesignIFlr1 return sb.ToString(); } - internal LR1Unit Clone() => - new LR1Unit(Id, Type, Name, new HashSet(Prospect), PointPosition, [.. Grammar]); - public override bool Equals(object? obj) { if (obj is not LR1Unit other) diff --git a/CompilerDesignIflr1/LexicalAnalysis.cs b/CompilerDesignIflr1/LexicalAnalysis.cs index 8525370..e16ab21 100644 --- a/CompilerDesignIflr1/LexicalAnalysis.cs +++ b/CompilerDesignIflr1/LexicalAnalysis.cs @@ -78,17 +78,17 @@ namespace CompilerDesignIflr1 temp.Value = s; ans.Add(temp); } - else if (Symbol.TryGetValue(s, out var symbol)) + else if(i + 1 < list.Count && Symbol.TryGetValue(s + list[i + 1], out var symbol)) { var temp = symbol.Clone(); - if (i + 1 < list.Count && Symbol.TryGetValue(s + list[i + 1], out symbol)) - { - temp = symbol.Clone(); - temp.Value = s + list[i + 1]; - i++; - } - else - temp.Value = s; + temp.Value = s + list[i + 1]; + i++; + ans.Add(temp); + } + else if (Symbol.TryGetValue(s, out symbol)) + { + var temp = symbol.Clone(); + temp.Value = s; ans.Add(temp); } else @@ -96,7 +96,8 @@ namespace CompilerDesignIflr1 bool noAnswer = true; foreach (var (pattern, ut) in Patterns) { - if (Regex.IsMatch(s, pattern)) + + if (Regex.IsMatch(s, '^' + pattern + '$')) { var temp = ut.Clone(); temp.Value = s; @@ -118,7 +119,7 @@ namespace CompilerDesignIflr1 { List lt = new List(); int l = 0; - int r = 1; + int r = 0; while (r < s.Length) { @@ -130,9 +131,20 @@ namespace CompilerDesignIflr1 lt.Add(k); } k = s[r].ToString().Trim(); + if (k.Length != 0) { - lt.Add(k); + if(k is "\'" or "\"") + { + l = r; + int temp = r + 1; + while (temp < s.Length && s[temp].ToString().Trim() != k) + temp++; + lt.Add(s.Substring(l, temp - l + 1)); + r = temp; + } + else + lt.Add(k); } l = r + 1; r = l; diff --git a/CompilerDesignIflr1/Program.cs b/CompilerDesignIflr1/Program.cs index 5fb481c..7473cc7 100644 --- a/CompilerDesignIflr1/Program.cs +++ b/CompilerDesignIflr1/Program.cs @@ -7,4 +7,6 @@ var grammarReader = new GrammarReader("./files/if-grammar.grammar"); var lr1Creator = new LR1Creator(grammarReader); var lr1Table = new LR1Table(lr1Creator); var lexicalAnalysis = new LexicalAnalysis(lr1Creator, "./files/code"); -var stateMachine = new StateMachine(lr1Table, lexicalAnalysis, lr1Creator); +var semanticAnalysis = new SemanticAnalysis(); +var stateMachine = new StateMachine(lr1Table, lexicalAnalysis, lr1Creator, semanticAnalysis); +semanticAnalysis.PrintQuadruples(); diff --git a/CompilerDesignIflr1/SemanticAnalysis.cs b/CompilerDesignIflr1/SemanticAnalysis.cs new file mode 100644 index 0000000..facc419 --- /dev/null +++ b/CompilerDesignIflr1/SemanticAnalysis.cs @@ -0,0 +1,1032 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Runtime.InteropServices.Marshalling; +using System.Text; +using System.Threading.Tasks; +using static System.Runtime.InteropServices.JavaScript.JSType; + +namespace CompilerDesignIFlr1 +{ + internal class SemanticAnalysis + { + List Quadruples = []; + internal List IdentifierTables = [new IdentifierTable("Global")]; + internal int QuadrupleIndex = 0; + internal int TempNameCounter = 0; + internal Stack ElseIndex = []; + + public void ShiftAnalysis(LR1Unit unit) + { + switch (unit.Name) + { + case "LBrace": + IdentifierTables.Add(new IdentifierTable("LBrace")); + break; + case "RBrace": + IdentifierTables.RemoveAt(IdentifierTables.Count - 1); + break; + case "If": + IdentifierTables.Add(new IdentifierTable("If")); + break; + case "Else": + ElseIndex.Push(QuadrupleIndex); + IdentifierTables.RemoveAt(IdentifierTables.Count - 1); + IdentifierTables.Add(new IdentifierTable("Else")); + break; + case "Type": + IdentifierTables.Add(new IdentifierTable("Type")); + break; + case "Const": + IdentifierTables.Add(new IdentifierTable("Const")); + break; + } + } + + public LR1Unit Analysis(List units, LR1Unit unit) + { + switch (unit.Id) + { + case 0: + case 1: + break; + case 2: + { + Assert( + units.Count == 5 + && Quadruples[units[1].QuadrupleIndex].To.Type == IdentifierType.Address + && ElseIndex.Count > 0 + ); + IdentifierTables.RemoveAt(IdentifierTables.Count - 1); + var identifier = Quadruples[units[1].QuadrupleIndex].To; + identifier.Value = ElseIndex.Pop() + ""; + break; + } + case 3: + { + Assert( + units.Count == 3 + && Quadruples[units[1].QuadrupleIndex].To.Type == IdentifierType.Address + ); + IdentifierTables.RemoveAt(IdentifierTables.Count - 1); + var identifier = Quadruples[units[1].QuadrupleIndex].To; + identifier.Value = QuadrupleIndex + ""; + break; + } + case 4: + { + Assert( + units.Count == 5 + && Quadruples[units[1].QuadrupleIndex].To.Type == IdentifierType.Address + && ElseIndex.Count > 0 + ); + IdentifierTables.RemoveAt(IdentifierTables.Count - 1); + var identifier = Quadruples[units[1].QuadrupleIndex].To; + identifier.Value = ElseIndex.Pop() + ""; + break; + } + case 5: + Assert(units.Count == 1); + //IdentifierTables.RemoveAt(IdentifierTables.Count - 1); + break; + case 6: + { + Assert(units.Count == 3 && units[1].Value.StartsWith('@')); + string tempName = GetTempName(); + Identifier oldIdentifier = GetIdentifier(units[1].Value); + var valueIdentifier = GetFinalIdentifier(units[1].Value); + Assert(valueIdentifier.Type == IdentifierType.Int); + var value = + int.Parse(GetFinalValue(valueIdentifier.Value)) == 0 ? "True" : "False"; + Identifier identifier = Identifier.Address(tempName, value); + AddToIdentifierTable(identifier); + Assert(unit.QuadrupleIndex == 0); + unit.QuadrupleIndex = QuadrupleIndex; + unit.Value = tempName; + Quadruples.Add( + new Quadruple( + "j==", + QuadrupleIndex++, + oldIdentifier, + Identifier.Literal("0"), + identifier + ) + ); + break; + } + case 7: + { + string tempName = GetTempName(); + Assert(units.Count == 2); + if (units[1].Value == "None") + { + unit.Value = units[0].Value; + break; + } + Assert(units[0].Value.StartsWith("@")); + Identifier identifier1 = GetFinalIdentifier(units[0].Value); + string @operator = units[1].Value.Split()[0].Trim(); + Identifier identifier2 = GetFinalIdentifier(units[1].Value.Split()[1].Trim()); + Assert( + identifier1.Type is IdentifierType.Int + && identifier2.Type is IdentifierType.Int + ); + int value1 = int.Parse(GetFinalValue(identifier1.Value)); + int value2 = int.Parse(GetFinalValue(identifier2.Value)); + var value = @operator switch + { + "||" => value1 | value2, + "&&" => value1 & value2, + _ => throw new Exception("Type is not supported") + }; + Identifier tempIdentifier = new(IdentifierType.Int, tempName, value + ""); + AddToIdentifierTable(tempIdentifier); + Assert(unit.QuadrupleIndex == 0); + unit.Value = tempName; + unit.QuadrupleIndex = QuadrupleIndex; + Quadruples.Add( + new Quadruple( + @operator, + QuadrupleIndex++, + identifier1, + identifier2, + tempIdentifier + ) + ); + break; + } + case 8: + { + string tempName = GetTempName(); + Assert(units.Count == 3); + Assert(units[0].Value.StartsWith('@') && units[2].Value.StartsWith('@')); + var value = OperatorCalculator(units[0].Value, units[1].Value, units[2].Value); + Identifier identifier = new Identifier( + IdentifierType.Int, + tempName, + value + "" + ); + unit.Value = tempName; + unit.QuadrupleIndex = QuadrupleIndex; + Quadruples.Add( + new Quadruple( + units[1].Value, + QuadrupleIndex++, + GetIdentifier(units[0].Value), + GetIdentifier(units[2].Value), + identifier + ) + ); + AddToIdentifierTable(identifier); + break; + } + case 9: + { + string tempName = GetTempName(); + Assert(units.Count == 1 && units[0].Value.StartsWith('@')); + var oldIdentifier = GetFinalIdentifier(units[0].Value); + Assert(oldIdentifier.Type == IdentifierType.Int); + var value = int.Parse(GetFinalValue(oldIdentifier.Value)) != 0 ? 1 : 0; + Identifier identifier = new Identifier( + IdentifierType.Int, + tempName, + value + "" + ); + unit.Value = tempName; + unit.QuadrupleIndex = QuadrupleIndex; + Quadruples.Add( + new Quadruple( + "!=", + QuadrupleIndex++, + GetIdentifier(units[0].Value), + Identifier.Literal("0"), + identifier + ) + ); + AddToIdentifierTable(identifier); + break; + } + case 10: + { + string tempName = GetTempName(); + Assert(units.Count == 2); + if (units[1].Value == "None") + { + unit.Value = units[0].Value; + break; + } + Assert(units[0].Value.StartsWith("@")); + Identifier identifier1 = GetIdentifier(units[0].Value); + string @operator = units[1].Value.Split()[0].Trim(); + Identifier identifier2 = GetIdentifier(units[1].Value.Split()[1].Trim()); + Assert( + identifier1.Type is IdentifierType.Int + && identifier2.Type is IdentifierType.Int + ); + int value1 = int.Parse(GetFinalValue(identifier1.Value)); + int value2 = int.Parse(GetFinalValue(identifier2.Value)); + var value = @operator switch + { + "+" => value1 + value2, + "-" => value1 - value2, + _ => throw new Exception("Type is not supported") + }; + Identifier tempIdentifier = new(IdentifierType.Int, tempName, value + ""); + AddToIdentifierTable(tempIdentifier); + Assert(unit.QuadrupleIndex == 0); + unit.Value = tempName; + unit.QuadrupleIndex = QuadrupleIndex; + Quadruples.Add( + new Quadruple( + @operator, + QuadrupleIndex++, + identifier1, + identifier2, + tempIdentifier + ) + ); + break; + } + case 11: + case 12: + break; + case 13: + case 14: + case 15: + case 16: + case 17: + break; + case 18: + { + Assert(units.Count == 3 && units[2].Value.StartsWith('@')); + Identifier oldIdentifier = GetIdentifier(units[2].Value); + var identifierValue = GetFinalIdentifier(units[2].Value).Value; + Identifier identifier = new Identifier( + oldIdentifier.Type, + units[0].Value, + identifierValue + ); + unit.Value = units[0].Value; + unit.QuadrupleIndex = QuadrupleIndex; + if (IdentifierTables[^1].Value == "Type") + AddToIdentifierTable(identifier); + else + UpdateIdentifier(identifier); + Quadruples.Add( + new Quadruple("=", QuadrupleIndex++, oldIdentifier, null, identifier) + ); + break; + } + case 19: + { + string tempName = GetTempName(); + Assert(units.Count == 2); + if (units[1].Value == "None") + { + unit.Value = units[0].Value; + break; + } + Assert(units[0].Value.StartsWith("@")); + Identifier identifier1 = GetIdentifier(units[0].Value); + string @operator = units[1].Value.Split()[0].Trim(); + Identifier identifier2 = GetIdentifier(units[1].Value.Split()[1].Trim()); + Assert( + identifier1.Type is IdentifierType.Int + && identifier2.Type is IdentifierType.Int + ); + double value1 = int.Parse(GetFinalValue(identifier1.Value)); + double value2 = int.Parse(GetFinalValue(identifier2.Value)); + int value = (int)( + @operator switch + { + "*" => value1 * value2, + "/" => value1 / value2, + "%" => value1 % value2, + _ => throw new Exception("Type is not supported") + } + ); + Identifier tempIdentifier = new(IdentifierType.Int, tempName, value + ""); + AddToIdentifierTable(tempIdentifier); + Assert(unit.QuadrupleIndex == 0); + unit.Value = tempName; + unit.QuadrupleIndex = QuadrupleIndex; + Quadruples.Add( + new Quadruple( + @operator, + QuadrupleIndex++, + identifier1, + identifier2, + tempIdentifier + ) + ); + break; + } + case 20: + { + Assert(units.Count == 2); + foreach (var (name, identifier) in IdentifierTables[^1].Table) + { + if (name.StartsWith("@")) + continue; + if ( + identifier.Type == IdentifierType.Int + || identifier.Type == IdentifierType.Char + ) + { + identifier.Type = identifier.Type switch + { + IdentifierType.Int => IdentifierType.ConstInt, + IdentifierType.Char => IdentifierType.ConstChar, + _ => throw new Exception("Type is not supported.") + }; + IdentifierTables[^2].Table.Add(name, identifier); + } + else + throw new InvalidOperationException("Wrong type"); + } + IdentifierTables.RemoveAt(IdentifierTables.Count - 1); + break; + } + case 21: + { + Assert(units.Count == 3); + IdentifierType type = units[0].Value switch + { + "int" => IdentifierType.Int, + "char" => IdentifierType.Char, + _ => throw new Exception("Type is not supported.") + }; + foreach (var (name, identifier) in IdentifierTables[^1].Table) + { + if (name.StartsWith("@")) + continue; + if (identifier.Type == IdentifierType.Unknown || identifier.Type == type) + { + identifier.Type = type; + IdentifierTables[^2].Table.Add(name, identifier); + } + else + throw new InvalidOperationException("Wrong type"); + } + IdentifierTables.RemoveAt(IdentifierTables.Count - 1); + break; + } + case 22: + case 23: + Assert(units.Count == 1); + unit.Value = units[0].Value; + break; + case 24: + { + Assert(units.Count == 1); + string tempName = GetTempName(); + Identifier identifier = GetIdentifier(units[0].Value); + Assert(identifier.Type != IdentifierType.Literal); + Identifier tempIdentifier = + identifier.Type == IdentifierType.Int + ? Identifier.Int(tempName, identifier.Value) + : Identifier.Char(tempName, identifier.Value); + Assert(unit.QuadrupleIndex == 0); + unit.Value = tempName; + unit.QuadrupleIndex = QuadrupleIndex; + Quadruples.Add( + new Quadruple("=", QuadrupleIndex++, identifier, null, tempIdentifier) + ); + AddToIdentifierTable(tempIdentifier); + + break; + } + case 25: + { + Assert(units.Count == 1); + string tempName = GetTempName(); + Identifier tempIdentifier = Identifier.Int(tempName, units[0].Value); + Quadruples.Add( + new Quadruple( + "=", + QuadrupleIndex++, + Identifier.Literal(units[0].Value), + null, + tempIdentifier + ) + ); + Assert(unit.QuadrupleIndex == 0); + unit.Value = tempName; + unit.QuadrupleIndex = QuadrupleIndex; + AddToIdentifierTable(tempIdentifier); + break; + } + case 26: + { + Assert(units.Count == 1); + string tempName = GetTempName(); + Identifier tempIdentifier = Identifier.Char(tempName, units[0].Value); + Quadruples.Add( + new Quadruple( + "=", + QuadrupleIndex++, + Identifier.Literal(units[0].Value), + null, + tempIdentifier + ) + ); + Assert(unit.QuadrupleIndex == 0); + unit.Value = tempName; + unit.QuadrupleIndex = QuadrupleIndex; + AddToIdentifierTable(tempIdentifier); + + break; + } + case 27: + { + Assert(units.Count == 3); + Identifier identifier = GetIdentifier(units[1].Value); + string tempName = GetTempName(); + Identifier tempIdentifier = identifier.Type switch + { + IdentifierType.Int => Identifier.Int(tempName, identifier.Value), + IdentifierType.Char => Identifier.Char(tempName, identifier.Value), + _ => throw new Exception("Type is not supported.") + }; + Assert(unit.QuadrupleIndex == 0); + unit.Value = tempName; + unit.QuadrupleIndex = QuadrupleIndex; + Quadruples.Add( + new Quadruple("=", QuadrupleIndex++, identifier, null, tempIdentifier) + ); + AddToIdentifierTable(tempIdentifier); + break; + } + case 28: + case 29: + Assert(units.Count == 1); + unit.Value = units[0].Value; + break; + case 30: + case 31: + case 32: + Assert(units.Count == 1); + unit.Value = units[0].Value; + break; + case 33: + { + Assert(units.Count == 1); + unit.Value = units[0].Value; + string tempName = GetTempName(); + Identifier tempIdentifier = Identifier.Int(tempName, unit.Value); + Quadruples.Add( + new Quadruple( + "=", + QuadrupleIndex++, + Identifier.Literal(unit.Value), + null, + tempIdentifier + ) + ); + Assert(unit.QuadrupleIndex == 0); + unit.Value = tempName; + unit.QuadrupleIndex = QuadrupleIndex; + AddToIdentifierTable(tempIdentifier); + break; + } + case 34: + { + Assert(units.Count == 2); + unit.Value = "-" + units[1].Value; + string tempName = GetTempName(); + Identifier tempIdentifier = Identifier.Int(tempName, unit.Value); + Quadruples.Add( + new Quadruple( + "=", + QuadrupleIndex++, + Identifier.Literal(unit.Value), + null, + tempIdentifier + ) + ); + Assert(unit.QuadrupleIndex == 0); + unit.Value = tempName; + unit.QuadrupleIndex = QuadrupleIndex; + AddToIdentifierTable(tempIdentifier); + break; + } + case 35: + { + Assert(units.Count == 2); + unit.Value = units[1].Value; + string tempName = GetTempName(); + Identifier tempIdentifier = Identifier.Int(tempName, unit.Value); + Quadruples.Add( + new Quadruple( + "=", + QuadrupleIndex++, + Identifier.Literal(unit.Value), + null, + tempIdentifier + ) + ); + Assert(unit.QuadrupleIndex == 0); + unit.Value = tempName; + unit.QuadrupleIndex = QuadrupleIndex; + AddToIdentifierTable(tempIdentifier); + break; + } + case 36: + case 37: + case 38: + case 39: + case 40: + case 41: + Assert(units.Count == 1); + unit.Value = units[0].Value; + break; + case 42: + case 43: + Assert(units.Count == 1); + unit.Value = units[0].Value; + break; + case 44: + case 45: + break; + case 46: + Assert(units.Count == 0); + unit.Value = "None"; + break; + case 47: + { + Assert(units.Count == 3); + if (units[2].Value == "None") + { + unit.Value = units[0].Value + " " + units[1].Value; + break; + } + string tempName = GetTempName(); + string @operator = units[2].Value.Split()[0].Trim(); + Assert(@operator is "||" or "&&"); + string unit2Name = units[2].Value.Split()[1].Trim(); + Identifier unit1Identifier = GetIdentifier(units[1].Value); + Identifier unit2Identifier = GetIdentifier(unit2Name); + string value1 = GetFinalValue(units[1].Value); + string value2 = GetFinalValue(unit2Name); + Assert( + unit1Identifier.Type == IdentifierType.Int + && unit2Identifier.Type == IdentifierType.Int + ); + var value = @operator switch + { + "||" => int.Parse(value1) | int.Parse(value2), + "&&" => int.Parse(value1) & int.Parse(value2), + _ => throw new Exception("Type is not supported") + }; + Identifier tempIdentifier = new Identifier( + IdentifierType.Int, + tempName, + value + "" + ); + AddToIdentifierTable(tempIdentifier); + unit.Value = units[0].Value + " " + tempName; + Quadruples.Add( + new Quadruple( + @operator, + QuadrupleIndex++, + unit1Identifier, + unit2Identifier, + tempIdentifier + ) + ); + break; + } + case 48: + Assert(units.Count == 0); + unit.Value = "None"; + break; + case 49: + { + Assert(units.Count == 3); + if (units[2].Value == "None") + { + unit.Value = units[0].Value + " " + units[1].Value; + break; + } + string tempName = GetTempName(); + string @operator = units[2].Value.Split()[0].Trim(); + Assert(@operator is "+" or "-"); + string unit2Name = units[2].Value.Split()[1].Trim(); + Identifier unit1Identifier = GetIdentifier(units[1].Value); + Identifier unit2Identifier = GetIdentifier(unit2Name); + string value1 = GetFinalValue(units[1].Value); + string value2 = GetFinalValue(unit2Name); + Assert( + unit1Identifier.Type == IdentifierType.Int + && unit2Identifier.Type == IdentifierType.Int + ); + var value = @operator switch + { + "+" => int.Parse(value1) + int.Parse(value2), + "-" => int.Parse(value1) - int.Parse(value2), + _ => throw new Exception("Type is not supported") + }; + Identifier tempIdentifier = new Identifier( + IdentifierType.Int, + tempName, + value + "" + ); + AddToIdentifierTable(tempIdentifier); + unit.Value = units[0].Value + " " + tempName; + Quadruples.Add( + new Quadruple( + @operator, + QuadrupleIndex++, + unit1Identifier, + unit2Identifier, + tempIdentifier + ) + ); + break; + } + case 50: + case 51: + break; + case 52: + Assert(units.Count == 0); + unit.Value = "None"; + break; + case 53: + { + Assert(units.Count == 3); + if (units[2].Value == "None") + { + unit.Value = units[0].Value + " " + units[1].Value; + break; + } + string tempName = GetTempName(); + string @operator = units[2].Value.Split()[0].Trim(); + Assert(@operator is "*" or "/" or "%"); + string unit2Name = units[2].Value.Split()[1].Trim(); + Identifier unit1Identifier = GetIdentifier(units[1].Value); + Identifier unit2Identifier = GetIdentifier(unit2Name); + string value1 = GetFinalValue(units[1].Value); + string value2 = GetFinalValue(unit2Name); + Assert( + unit1Identifier.Type == IdentifierType.Int + && unit2Identifier.Type == IdentifierType.Int + ); + var value = (int)( + @operator switch + { + "*" => int.Parse(value1) * int.Parse(value2), + "/" => int.Parse(value1) / int.Parse(value2), + "%" => int.Parse(value1) % int.Parse(value2), + _ => throw new Exception("Type is not supported") + } + ); + Identifier tempIdentifier = new Identifier( + IdentifierType.Int, + tempName, + value + "" + ); + AddToIdentifierTable(tempIdentifier); + unit.Value = units[0].Value + " " + tempName; + Quadruples.Add( + new Quadruple( + @operator, + QuadrupleIndex++, + unit1Identifier, + unit2Identifier, + tempIdentifier + ) + ); + break; + } + case 54: + Assert(units.Count == 1); + unit.Value = units[0].Value; + unit.QuadrupleIndex = units[0].QuadrupleIndex; + AddToIdentifierTable(Identifier.Unknown(unit.Value)); + break; + case 55: + Assert(units.Count == 1); + unit.Value = units[0].Value; + unit.QuadrupleIndex = units[0].QuadrupleIndex; + break; + case 56: + Assert(units.Count == 0); + unit.Value = "None"; + break; + case 57: + Assert(units.Count == 3); + unit.Value = units[1].Value; + unit.QuadrupleIndex = units[1].QuadrupleIndex; + AddToIdentifierTable(Identifier.Unknown(unit.Value)); + break; + case 58: + Assert(units.Count == 3); + unit.Value = units[1].Value; + unit.QuadrupleIndex = units[1].QuadrupleIndex; + break; + default: + break; + } + return unit; + } + + internal void PrintQuadruples() + { + for (int i = 0; i < Quadruples.Count; i++) + { + Console.Write($"{i, 3}"); + Console.WriteLine(Quadruples[i]); + } + } + + internal static bool Assert(bool val) => + !val ? throw new Exception("Assertion failed.") : false; + + internal void AddToIdentifierTable(Identifier identifier) + { + if (IdentifierTables[^1].Table.ContainsKey(identifier.Name)) + throw new InvalidOperationException($"{identifier.Name} redefined."); + IdentifierTables[^1].Table.Add(identifier.Name, identifier); + } + + internal string GetTempName() => "@T" + TempNameCounter++; + + internal Identifier GetIdentifier(string identifier) + { + for (int i = 1; i <= IdentifierTables.Count; i++) + { + if (IdentifierTables[^i].Table.TryGetValue(identifier, out var val)) + return val; + } + throw new InvalidOperationException($"No identifier called: {identifier}"); + } + + internal void UpdateIdentifier(Identifier identifier) + { + for (int i = 1; i <= IdentifierTables.Count; i++) + { + if (IdentifierTables[^i].Table.TryGetValue(identifier.Name, out var oldIdentifier)) + { + if (oldIdentifier.Type is IdentifierType.ConstInt or IdentifierType.ConstChar) + throw new InvalidOperationException( + "Change the value of const is not allowed." + ); + IdentifierTables[^i].Table[identifier.Name] = identifier; + return; + } + } + throw new InvalidOperationException($"No identifier called: {identifier.Name}"); + } + + internal Identifier GetFinalIdentifier(string identifier) + { + var nextIdentifier = GetIdentifier(identifier); + if (nextIdentifier.Value.StartsWith("@")) + return GetFinalIdentifier(nextIdentifier.Value); + else + return nextIdentifier; + } + + internal string GetFinalValue(string any) + { + string ans = any; + if (any.StartsWith("@")) + { + ans = GetFinalIdentifier(any).Value; + } + if (ans.Length == 0) + throw new InvalidOperationException("Identifier used before assignment"); + return ans; + } + + internal int OperatorCalculator(string a, string op, string b) + { + if (a.StartsWith('@')) + { + var identifier = GetFinalIdentifier(a); + if (identifier.Type != IdentifierType.Int) + throw new InvalidOperationException("This type is not allowed to compare."); + a = GetFinalValue(identifier.Value); + } + if (b.StartsWith('@')) + { + var identifier = GetFinalIdentifier(b); + if (identifier.Type != IdentifierType.Int) + throw new InvalidOperationException("This type is not allowed to compare."); + b = GetFinalValue(identifier.Value); + } + int av = int.Parse(a), + bv = int.Parse(b); + return op.Trim() switch + { + "==" => av == bv, + ">" => av > bv, + ">=" => av >= bv, + "<" => av < bv, + "<=" => av <= bv, + "!=" => av != bv, + _ => throw new Exception("Type is not uspported.") + } + ? 1 + : 0; + } + } + + enum IdentifierType + { + Int, + Char, + ConstInt, + ConstChar, + Literal, + Address, + Unknown + } + + internal class Identifier + { + internal IdentifierType Type { get; set; } = IdentifierType.Literal; + internal string Name { get; set; } = ""; + internal string Value { get; set; } = ""; + + internal Identifier(IdentifierType type, string name, string value) + { + Type = type; + Name = name; + Value = value; + } + + internal static Identifier Literal(string value) => + new Identifier(IdentifierType.Literal, "", value); + + internal static Identifier Literal(string name, string value) => + new Identifier(IdentifierType.Literal, name, value); + + internal static Identifier Int(string name, string value) => + new Identifier(IdentifierType.Int, name, value); + + internal static Identifier Char(string name, string value) => + new Identifier(IdentifierType.Char, name, value); + + internal static Identifier Address(string name, string value) => + new Identifier(IdentifierType.Address, name, value); + + internal static Identifier Unknown(string name) => + new Identifier(IdentifierType.Unknown, name, ""); + + internal Identifier Clone() + { + return new Identifier(Type, Name, Value); + } + } + + internal class Quadruple + { + internal string Operator; + internal int Index = 0; + internal Identifier A; + internal Identifier? B; + internal Identifier To; + + internal Quadruple(string @operator, int index, Identifier a, Identifier? b, Identifier to) + { + Operator = @operator; + this.Index = index; + A = a; + B = b; + To = to; + } + + internal Quadruple Clone() + { + return new Quadruple(Operator, Index, A.Clone(), B?.Clone(), To.Clone()); + } + + public override string ToString() + { + var sb = new StringBuilder(); + string GetValue(Identifier? identifier) + { + if (identifier is null) + return ""; + if (identifier.Type == IdentifierType.Address) + return identifier.Value; + if (identifier.Name.Length != 0) + return identifier.Name; + return identifier.Value; + } + sb.Append('(') + .Append(Operator.PadLeft(4, ' ')) + .Append(',') + .Append(GetValue(A).PadLeft(4, ' ')) + .Append(',') + .Append(GetValue(B).PadLeft(4, ' ')) + .Append(',') + .Append(GetValue(To).PadLeft(4, ' ')) + .Append(")"); + return sb.ToString(); + } + } + + internal class IdentifierTable + { + internal string Value = ""; + internal Dictionary Table { get; set; } = []; + + internal IdentifierTable(string value) + { + Value = value; + } + } +} +/* +文法: +key: Program + 0 Program ::= . StatementList +key: StatementList + 1 StatementList ::= . LBrace Statement_0 RBrace +key: IfStatement + 2 IfStatement ::= . If ConditionPart PartIfStatement Else Statement + 3 IfStatement ::= . If ConditionPart Statement +key: PartIfStatement + 4 PartIfStatement ::= . If ConditionPart PartIfStatement Else PartIfStatement + 5 PartIfStatement ::= . NoIfStatement +key: ConditionPart + 6 ConditionPart ::= . LParen Condition RParen +key: Condition + 7 Condition ::= . ConditionalExpression LogicalOperator_ConditionalExpression_0 +key: ConditionalExpression + 8 ConditionalExpression ::= . Expression Operator Expression + 9 ConditionalExpression ::= . Expression +key: Expression + 10 Expression ::= . Term AddLike_Term_0 +key: Statement + 11 Statement ::= . IfStatement + 12 Statement ::= . NoIfStatement +key: NoIfStatement + 13 NoIfStatement ::= . AssignmentStatement Semicolon + 14 NoIfStatement ::= . VariableDefinition Semicolon + 15 NoIfStatement ::= . LBrace Statement_1 RBrace + 16 NoIfStatement ::= . ConstantDefinition Semicolon + 17 NoIfStatement ::= . Semicolon +key: AssignmentStatement + 18 AssignmentStatement ::= . Identifier Equal Expression +key: Term + 19 Term ::= . Factor MultiplyLike_Factor_0 +key: ConstantDefinition + 20 ConstantDefinition ::= . Const VariableDefinition +key: VariableDefinition + 21 VariableDefinition ::= . Type Identifier__AssignmentStatement_0 Comma_Identifier__Comma_AssignmentStatement_0 +key: Type + 22 Type ::= . Int + 23 Type ::= . Char +key: Factor + 24 Factor ::= . Identifier + 25 Factor ::= . Number + 26 Factor ::= . Character + 27 Factor ::= . LParen Expression RParen +key: AddLike + 28 AddLike ::= . Plus + 29 AddLike ::= . Minus +key: MultiplyLike + 30 MultiplyLike ::= . Multiply + 31 MultiplyLike ::= . Divide + 32 MultiplyLike ::= . Modulo +key: Number + 33 Number ::= . UnsignedNumber + 34 Number ::= . Minus UnsignedNumber + 35 Number ::= . Plus UnsignedNumber +key: Operator + 36 Operator ::= . EqualTo + 37 Operator ::= . NotEqualTo + 38 Operator ::= . LessThan + 39 Operator ::= . GreaterThan + 40 Operator ::= . LessThanOrEqual + 41 Operator ::= . GreaterThanOrEqual +key: LogicalOperator + 42 LogicalOperator ::= . And + 43 LogicalOperator ::= . Or +key: Statement_0 + 44 Statement_0 ::= . + 45 Statement_0 ::= . Statement Statement_0 +key: LogicalOperator_ConditionalExpression_0 + 46 LogicalOperator_ConditionalExpression_0 ::= . + 47 LogicalOperator_ConditionalExpression_0 ::= . LogicalOperator ConditionalExpression LogicalOperator_ConditionalExpression_0 +key: AddLike_Term_0 + 48 AddLike_Term_0 ::= . + 49 AddLike_Term_0 ::= . AddLike Term AddLike_Term_0 +key: Statement_1 + 50 Statement_1 ::= . + 51 Statement_1 ::= . Statement Statement_1 +key: MultiplyLike_Factor_0 + 52 MultiplyLike_Factor_0 ::= . + 53 MultiplyLike_Factor_0 ::= . MultiplyLike Factor MultiplyLike_Factor_0 +key: Identifier__AssignmentStatement_0 + 54 Identifier__AssignmentStatement_0 ::= . Identifier + 55 Identifier__AssignmentStatement_0 ::= . AssignmentStatement +key: Comma_Identifier__Comma_AssignmentStatement_0 + 56 Comma_Identifier__Comma_AssignmentStatement_0 ::= . + 57 Comma_Identifier__Comma_AssignmentStatement_0 ::= . Comma Identifier Comma_Identifier__Comma_AssignmentStatement_0 + 58 Comma_Identifier__Comma_AssignmentStatement_0 ::= . Comma AssignmentStatement Comma_Identifier__Comma_AssignmentStatement_0 +*/ diff --git a/CompilerDesignIflr1/StateMachine.cs b/CompilerDesignIflr1/StateMachine.cs index 386ddbc..7e6b1bd 100644 --- a/CompilerDesignIflr1/StateMachine.cs +++ b/CompilerDesignIflr1/StateMachine.cs @@ -12,15 +12,17 @@ namespace CompilerDesignIFlr1 internal LR1Table Table; internal LexicalAnalysis AnalysisResult; internal LR1Creator Creator; - internal List<(LR1Unit, int)> stack = [(new LR1Unit("End","#"),0)]; + internal List<(LR1Unit, int)> _Stack = [(new LR1Unit("End","#"),0)]; internal Stack Tokens; + internal SemanticAnalysis SemanticAnalysis; - internal StateMachine(LR1Table table, LexicalAnalysis analysis, LR1Creator creator) + internal StateMachine(LR1Table table, LexicalAnalysis analysis, LR1Creator creator, SemanticAnalysis semanticAnalysis) { Table = table; AnalysisResult = analysis; Creator = creator; Tokens = AnalysisResult.GetStack(); + SemanticAnalysis = semanticAnalysis; Compute(); } @@ -35,23 +37,26 @@ namespace CompilerDesignIFlr1 internal bool ComputeOnce(LR1Unit unit) { - var (action, destination) = Table.Rows[stack[^1].Item2].Next(unit.Name); + var (action, destination) = Table.Rows[_Stack[^1].Item2].Next(unit.Name); switch (action) { case "GOTO": - stack.Add((unit, destination)); + _Stack.Add((unit, destination)); + SemanticAnalysis.ShiftAnalysis(unit); break; case "Reduce": var reduceUnit = Creator.UnitIndex[destination]; - if (reduceUnit.CanReduce(stack.Select(x => x.Item1).ToList())) + if (reduceUnit.CanReduce(_Stack.Select(x => x.Item1).ToList())) { - stack.RemoveRange(stack.Count - reduceUnit.Grammar.Count, reduceUnit.Grammar.Count); + var vals = _Stack.Skip(_Stack.Count - reduceUnit.Grammar.Count).Take(reduceUnit.Grammar.Count).Select(x=>x.Item1) .ToList(); + reduceUnit = SemanticAnalysis.Analysis(vals, reduceUnit.Clone()); + _Stack.RemoveRange(_Stack.Count - reduceUnit.Grammar.Count, reduceUnit.Grammar.Count); } else throw new Exception("Reduce not allow."); Console.WriteLine(reduceUnit); Tokens.Push(unit); - Tokens.Push(reduceUnit.Clone()); + Tokens.Push(reduceUnit); break; case "ACC": Console.WriteLine(Creator.UnitIndex[destination]); diff --git a/CompilerDesignIflr1/files/code b/CompilerDesignIflr1/files/code index 8359440..36d2ca6 100644 --- a/CompilerDesignIflr1/files/code +++ b/CompilerDesignIflr1/files/code @@ -1,9 +1,12 @@ -int i=0,t,b=15; -if(i>=10) - if(k==9) - h = 6; - else - { - c=10; - if(k<=95 && ) - } +{ + int a =1*9+2; + if(a>9){ + a=a+1; + if(9>1){ + a=10; + } + a=2+2; + } + + +} \ No newline at end of file diff --git a/CompilerDesignIflr1/files/if-grammar.grammar b/CompilerDesignIflr1/files/if-grammar.grammar index b97e936..187a421 100644 --- a/CompilerDesignIflr1/files/if-grammar.grammar +++ b/CompilerDesignIflr1/files/if-grammar.grammar @@ -3,17 +3,25 @@ } StatementList { - Statement* + LBrace Statement* RBrace } @skip { Whitespace } IfStatement { - If LParen ConditionalExpression RParen PartIfStatement Else Statement | If LParen ConditionalExpression RParen Statement + If ConditionPart PartIfStatement Else Statement | If ConditionPart Statement } PartIfStatement { - If LParen ConditionalExpression RParen PartIfStatement Else PartIfStatement | NoIfStatement + If ConditionPart PartIfStatement Else PartIfStatement | NoIfStatement +} + +ConditionPart { + LParen Condition RParen +} + +Condition { + ConditionalExpression (LogicalOperator ConditionalExpression)* } ConditionalExpression { @@ -45,7 +53,7 @@ ConstantDefinition { } VariableDefinition { - Type (Identifier | AssignmentStatement)+ (Comma Identifier | Comma AssignmentStatement)* + Type (Identifier | AssignmentStatement) (Comma Identifier | Comma AssignmentStatement)* } Type { @@ -69,7 +77,11 @@ Number { } Operator { - EuqalTo | NotEqualTo | LessThan | GreaterThan | LessThanOrEqual | GreaterThanOrEqual + EqualTo | NotEqualTo | LessThan | GreaterThan | LessThanOrEqual | GreaterThanOrEqual +} + +LogicalOperator { + And | Or } @tokens { @@ -93,7 +105,7 @@ Operator { UnsignedNumber { $[0-9]+ } String { "\"" $[\x00-\x7F]* "\"" } Character { "'" $[\x00-\x7F] "'" } - EuqalTo { "==" } + EqualTo { "==" } NotEqualTo { "!=" } LessThan { "<" } GreaterThan { ">" } @@ -101,4 +113,6 @@ Operator { GreaterThanOrEqual { ">=" } Equal { "=" } Whitespace { $[\t\n\r]+ } + And { "&&" } + Or { "||" } } \ No newline at end of file diff --git a/CompilerDesignIflr1/files/newGrammar b/CompilerDesignIflr1/files/newGrammar new file mode 100644 index 0000000..38ed672 --- /dev/null +++ b/CompilerDesignIflr1/files/newGrammar @@ -0,0 +1,88 @@ +文法: +key: Program + 0 Program ::= . StatementList +key: StatementList + 1 StatementList ::= . LBrace Statement_0 RBrace +key: IfStatement + 2 IfStatement ::= . If ConditionPart PartIfStatement Else Statement + 3 IfStatement ::= . If ConditionPart Statement +key: PartIfStatement + 4 PartIfStatement ::= . If ConditionPart PartIfStatement Else PartIfStatement + 5 PartIfStatement ::= . NoIfStatement +key: ConditionPart + 6 ConditionPart ::= . LParen Condition RParen +key: Condition + 7 Condition ::= . ConditionalExpression LogicalOperator_ConditionalExpression_0 +key: ConditionalExpression + 8 ConditionalExpression ::= . Expression Operator Expression + 9 ConditionalExpression ::= . Expression +key: Expression + 10 Expression ::= . Term AddLike_Term_0 +key: Statement + 11 Statement ::= . IfStatement + 12 Statement ::= . NoIfStatement +key: NoIfStatement + 13 NoIfStatement ::= . AssignmentStatement Semicolon + 14 NoIfStatement ::= . VariableDefinition Semicolon + 15 NoIfStatement ::= . LBrace Statement_1 RBrace + 16 NoIfStatement ::= . ConstantDefinition Semicolon + 17 NoIfStatement ::= . Semicolon +key: AssignmentStatement + 18 AssignmentStatement ::= . Identifier Equal Expression +key: Term + 19 Term ::= . Factor MultiplyLike_Factor_0 +key: ConstantDefinition + 20 ConstantDefinition ::= . Const VariableDefinition +key: VariableDefinition + 21 VariableDefinition ::= . Type Identifier__AssignmentStatement_0 Comma_Identifier__Comma_AssignmentStatement_0 +key: Type + 22 Type ::= . Int + 23 Type ::= . Char +key: Factor + 24 Factor ::= . Identifier + 25 Factor ::= . Number + 26 Factor ::= . Character + 27 Factor ::= . LParen Expression RParen +key: AddLike + 28 AddLike ::= . Plus + 29 AddLike ::= . Minus +key: MultiplyLike + 30 MultiplyLike ::= . Multiply + 31 MultiplyLike ::= . Divide + 32 MultiplyLike ::= . Modulo +key: Number + 33 Number ::= . UnsignedNumber + 34 Number ::= . Minus UnsignedNumber + 35 Number ::= . Plus UnsignedNumber +key: Operator + 36 Operator ::= . EqualTo + 37 Operator ::= . NotEqualTo + 38 Operator ::= . LessThan + 39 Operator ::= . GreaterThan + 40 Operator ::= . LessThanOrEqual + 41 Operator ::= . GreaterThanOrEqual +key: LogicalOperator + 42 LogicalOperator ::= . And + 43 LogicalOperator ::= . Or +key: Statement_0 + 44 Statement_0 ::= . + 45 Statement_0 ::= . Statement Statement_0 +key: LogicalOperator_ConditionalExpression_0 + 46 LogicalOperator_ConditionalExpression_0 ::= . + 47 LogicalOperator_ConditionalExpression_0 ::= . LogicalOperator ConditionalExpression LogicalOperator_ConditionalExpression_0 +key: AddLike_Term_0 + 48 AddLike_Term_0 ::= . + 49 AddLike_Term_0 ::= . AddLike Term AddLike_Term_0 +key: Statement_1 + 50 Statement_1 ::= . + 51 Statement_1 ::= . Statement Statement_1 +key: MultiplyLike_Factor_0 + 52 MultiplyLike_Factor_0 ::= . + 53 MultiplyLike_Factor_0 ::= . MultiplyLike Factor MultiplyLike_Factor_0 +key: Identifier__AssignmentStatement_0 + 54 Identifier__AssignmentStatement_0 ::= . Identifier + 55 Identifier__AssignmentStatement_0 ::= . AssignmentStatement +key: Comma_Identifier__Comma_AssignmentStatement_0 + 56 Comma_Identifier__Comma_AssignmentStatement_0 ::= . + 57 Comma_Identifier__Comma_AssignmentStatement_0 ::= . Comma Identifier Comma_Identifier__Comma_AssignmentStatement_0 + 58 Comma_Identifier__Comma_AssignmentStatement_0 ::= . Comma AssignmentStatement Comma_Identifier__Comma_AssignmentStatement_0 \ No newline at end of file diff --git a/CompilerDesignIflr1/files/oldGrammar b/CompilerDesignIflr1/files/oldGrammar new file mode 100644 index 0000000..d784926 --- /dev/null +++ b/CompilerDesignIflr1/files/oldGrammar @@ -0,0 +1,90 @@ +文法: +key: Program + 0 Program ::= . StatementList +key: StatementList + 1 StatementList ::= . LBrace Statement_0 RBrace +key: IfStatement + 2 IfStatement ::= . If ConditionPart PartIfStatement Else Statement + 3 IfStatement ::= . If ConditionPart Statement +key: PartIfStatement + 4 PartIfStatement ::= . If ConditionPart PartIfStatement Else PartIfStatement + 5 PartIfStatement ::= . NoIfStatement +key: ConditionPart + 6 ConditionPart ::= . LParen Condition RParen +key: Condition + 7 Condition ::= . ConditionalExpression LogicalOperator_ConditionalExpression_0 +key: ConditionalExpression + 8 ConditionalExpression ::= . Expression Operator Expression + 9 ConditionalExpression ::= . Expression +key: Expression + 10 Expression ::= . Term AddLike_Term_0 +key: Statement + 11 Statement ::= . IfStatement + 12 Statement ::= . NoIfStatement +key: NoIfStatement + 13 NoIfStatement ::= . AssignmentStatement Semicolon + 14 NoIfStatement ::= . VariableDefinition Semicolon + 15 NoIfStatement ::= . LBrace Statement_1 RBrace + 16 NoIfStatement ::= . ConstantDefinition Semicolon + 17 NoIfStatement ::= . Semicolon +key: AssignmentStatement + 18 AssignmentStatement ::= . Identifier Equal Expression +key: Term + 19 Term ::= . Factor MultiplyLike_Factor_0 +key: ConstantDefinition + 20 ConstantDefinition ::= . Const VariableDefinition +key: VariableDefinition + 21 VariableDefinition ::= . Type Identifier__AssignmentStatement_0 Comma_Identifier__Comma_AssignmentStatement_0 +key: Type + 22 Type ::= . Int + 23 Type ::= . Char +key: Factor + 24 Factor ::= . Identifier + 25 Factor ::= . Number + 26 Factor ::= . Character + 27 Factor ::= . LParen Expression RParen +key: AddLike + 28 AddLike ::= . Plus + 29 AddLike ::= . Minus +key: MultiplyLike + 30 MultiplyLike ::= . Multiply + 31 MultiplyLike ::= . Divide + 32 MultiplyLike ::= . Modulo +key: Number + 33 Number ::= . UnsignedNumber + 34 Number ::= . Minus UnsignedNumber + 35 Number ::= . Plus UnsignedNumber +key: Operator + 36 Operator ::= . EqualTo + 37 Operator ::= . NotEqualTo + 38 Operator ::= . LessThan + 39 Operator ::= . GreaterThan + 40 Operator ::= . LessThanOrEqual + 41 Operator ::= . GreaterThanOrEqual +key: LogicalOperator + 42 LogicalOperator ::= . And + 43 LogicalOperator ::= . Or +key: Statement_0 + 44 Statement_0 ::= . + 45 Statement_0 ::= . Statement Statement_0 +key: LogicalOperator_ConditionalExpression_0 + 46 LogicalOperator_ConditionalExpression_0 ::= . + 47 LogicalOperator_ConditionalExpression_0 ::= . LogicalOperator ConditionalExpression LogicalOperator_ConditionalExpression_0 +key: AddLike_Term_0 + 48 AddLike_Term_0 ::= . + 49 AddLike_Term_0 ::= . AddLike Term AddLike_Term_0 +key: Statement_1 + 50 Statement_1 ::= . + 51 Statement_1 ::= . Statement Statement_1 +key: MultiplyLike_Factor_0 + 52 MultiplyLike_Factor_0 ::= . + 53 MultiplyLike_Factor_0 ::= . MultiplyLike Factor MultiplyLike_Factor_0 +key: Identifier__AssignmentStatement_0 + 54 Identifier__AssignmentStatement_0 ::= . Identifier + 55 Identifier__AssignmentStatement_0 ::= . Identifier Identifier__AssignmentStatement_0 + 56 Identifier__AssignmentStatement_0 ::= . AssignmentStatement + 57 Identifier__AssignmentStatement_0 ::= . AssignmentStatement Identifier__AssignmentStatement_0 +key: Comma_Identifier__Comma_AssignmentStatement_0 + 58 Comma_Identifier__Comma_AssignmentStatement_0 ::= . + 59 Comma_Identifier__Comma_AssignmentStatement_0 ::= . Comma Identifier Comma_Identifier__Comma_AssignmentStatement_0 + 60 Comma_Identifier__Comma_AssignmentStatement_0 ::= . Comma AssignmentStatement Comma_Identifier__Comma_AssignmentStatement_0 \ No newline at end of file