using System.Text; 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() { Console.WriteLine("四元式:"); for (int i = 0; i < Quadruples.Count; i++) { //Console.Write($"{i, 3}"); Console.WriteLine(Quadruples[i]); } } internal void OptimizeQuadruples() { HashSet basedOn = []; bool CanBasedOn(Quadruple quadruple) { return quadruple.Operator != "=" || !quadruple.To.Name.StartsWith("@"); } Identifier GetFinal(Identifier? identifier, int from) { if (identifier == null) return null!; if (identifier.Type == IdentifierType.Literal) { if (identifier.Value.StartsWith("@")) { for (int i = from - 1; i >= 0; i--) { if (Quadruples[i].To.Name == identifier.Value) { return Identifier.Literal(Quadruples[i].To.Value); } } throw new Exception("Failed to track identifier"); } else return Identifier.Literal(identifier.Value); } if (identifier.Name.StartsWith("@")) { for (int i = from - 1; i >= 0; i--) { if (Quadruples[i].To.Name == identifier.Name) { if (Quadruples[i].Operator == "=") return GetFinal(Quadruples[i].A, i); else return identifier; } } throw new Exception("Failed to track identifier"); } else return identifier; } for (int i = 0; i < Quadruples.Count; i++) { if (CanBasedOn(Quadruples[i])) { basedOn.Add(i); Quadruples[i].A = GetFinal(Quadruples[i].A, i); Quadruples[i].B = GetFinal(Quadruples[i].B, i); } } List afterList = basedOn.Order().Select(x => Quadruples[x].Clone()).ToList(); HashSet reAddInAfterList = []; for (int i = 1; i <= afterList.Count; i++) { reAddInAfterList.Add(i); Quadruple quadruple = afterList[^i]; if (quadruple.Operator == "=" && quadruple.A.Name.StartsWith('@')) { reAddInAfterList.Remove(i); bool find = false; for (i++; i <= afterList.Count; i++) { reAddInAfterList.Add(i); if (afterList[^i].To.Name == quadruple.A.Name) { afterList[^i].To = quadruple.To; find = true; break; } } if(!find) throw new Exception("Failed to track identifier"); } } afterList = reAddInAfterList.Order().Select(x => afterList[^x]).Reverse().ToList(); Dictionary tempValueReplace = []; // >x 时 回填到 y Stack<(int, int)> addressReset = []; int tempValueIndex = 0; string GetNewTempName() { return "@T" + tempValueIndex++; } for (int i = 0; i < afterList.Count; i++) { var quadruple = afterList[i]; while (addressReset.Count > 0 && addressReset.Peek().Item1 < quadruple.Index) afterList[addressReset.Pop().Item2].To.Value = i + ""; quadruple.Index = i; if (quadruple.A.Name.StartsWith("@")) { if (tempValueReplace.TryGetValue(quadruple.A.Name, out string? newName)) quadruple.A.Name = newName; else { tempValueReplace.Add(quadruple.A.Name, GetNewTempName()); quadruple.A.Name = tempValueReplace[quadruple.A.Name]; } } if (quadruple.B is not null && quadruple.B.Name.StartsWith("@")) { if (tempValueReplace.TryGetValue(quadruple.B.Name, out string? newName)) quadruple.B.Name = newName; else { tempValueReplace.Add(quadruple.B.Name, GetNewTempName()); quadruple.B.Name = tempValueReplace[quadruple.B.Name]; } } if ( quadruple.To.Name.StartsWith("@") && quadruple.To.Type != IdentifierType.Address ) { if (tempValueReplace.TryGetValue(quadruple.To.Name, out string? newName)) quadruple.To.Name = newName; else { tempValueReplace.Add(quadruple.To.Name, GetNewTempName()); quadruple.To.Name = tempValueReplace[quadruple.To.Name]; } } if (quadruple.Operator.StartsWith('j')) addressReset.Push((int.Parse(quadruple.To.Value), i)); } while (addressReset.Count > 0) afterList[addressReset.Pop().Item2].To.Value = afterList.Count + ""; Console.WriteLine("After optimize."); //foreach (int i in basedOn.Order().ToList()) //{ // Console.WriteLine(Quadruples[i]); //} foreach (var t in afterList) { Console.WriteLine(t); } } 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; 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($"{Index, 3}") .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 */