1033 lines
41 KiB
C#
1033 lines
41 KiB
C#
|
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<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()
|
|||
|
{
|
|||
|
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<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
|
|||
|
*/
|