CompilerDesignIFLR1/CompilerDesignIflr1/SemanticAnalysis.cs

1169 lines
47 KiB
C#

using System.Text;
namespace CompilerDesignIFlr1
{
internal class SemanticAnalysis
{
List<Quadruple> Quadruples = [];
internal List<IdentifierTable> IdentifierTables = [new IdentifierTable("Global")];
internal int QuadrupleIndex = 0;
internal int TempNameCounter = 0;
internal Stack<int> 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<LR1Unit> 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<int> 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<Quadruple> afterList = basedOn.Order().Select(x => Quadruples[x].Clone()).ToList();
HashSet<int> 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<string, string> 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<string, Identifier> 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
*/