feat: 对于条件表达式的短路支持 (#80)

Reviewed-on: PostGuard/Canon#80
This commit is contained in:
jackfiled 2024-05-12 20:28:56 +08:00
parent b34383ea74
commit ab80d0c269
2 changed files with 105 additions and 12 deletions

View File

@ -1,9 +1,11 @@
using System.Globalization; using System.Globalization;
using Canon.Core.CodeGenerators; using Canon.Core.CodeGenerators;
using Canon.Core.Enums; using Canon.Core.Enums;
using Canon.Core.GrammarParser;
using Canon.Core.LexicalParser; using Canon.Core.LexicalParser;
using Canon.Core.SyntaxNodes; using Canon.Core.SyntaxNodes;
using BasicType = Canon.Core.Enums.BasicType; using BasicType = Canon.Core.Enums.BasicType;
using Expression = Canon.Core.SyntaxNodes.Expression;
namespace Canon.Core.SemanticParser; namespace Canon.Core.SemanticParser;
@ -278,6 +280,12 @@ public class CodeGeneratorVisitor : TypeCheckVisitor
: variable.Identifier.IdentifierName; : variable.Identifier.IdentifierName;
} }
private record CircuitLabel(string Circuit, string End);
private readonly Stack<CircuitLabel> _andCircuitLabels = [];
private readonly Stack<CircuitLabel> _orCircuitLabels = [];
public override void PreVisit(Term term) public override void PreVisit(Term term)
{ {
base.PreVisit(term); base.PreVisit(term);
@ -286,25 +294,56 @@ public class CodeGeneratorVisitor : TypeCheckVisitor
{ {
e.Left.IsCondition = term.IsCondition; e.Left.IsCondition = term.IsCondition;
e.Right.IsCondition = term.IsCondition; e.Right.IsCondition = term.IsCondition;
if (e.Operator.OperatorToken == new Terminator(KeywordType.And))
{
_andCircuitLabels.Push(new CircuitLabel($"and_circult_{_labelCount}",
$"and_end_{_labelCount}"));
_labelCount += 1;
}
}; };
term.OnFactorGenerator += (_, e) => { e.Factor.IsCondition = term.IsCondition; }; term.OnFactorGenerator += (_, e) => { e.Factor.IsCondition = term.IsCondition; };
} }
private string? _termVariableName;
public override void PostVisit(Term term) public override void PostVisit(Term term)
{ {
base.PostVisit(term); base.PostVisit(term);
term.OnFactorGenerator += (_, e) => { term.VariableName = e.Factor.VariableName; }; term.OnFactorGenerator += (_, e) =>
{
term.VariableName = e.Factor.VariableName;
_termVariableName = term.VariableName;
};
term.OnMultiplyGenerator += (_, e) => term.OnMultiplyGenerator += (_, e) =>
{ {
string temporaryName = GenerateTemporaryVariable(); string temporaryName = GenerateTemporaryVariable();
Builder.AddLine( if (e.Operator.OperatorToken == new Terminator(KeywordType.And))
$"{GenerateBasicTypeString(term.VariableType)} {temporaryName} = " + {
$"{e.Left.VariableName} {GenerateMultipleOperator(e.Operator)} {e.Right.VariableName};"); // 处理and的短路代码
Builder.AddLine($"""
bool {temporaryName} = {e.Left.VariableName} && {e.Right.VariableName};
goto {_andCircuitLabels.Peek().End};
{_andCircuitLabels.Peek().Circuit}:;
{temporaryName} = false;
{_andCircuitLabels.Peek().End}:;
""");
_andCircuitLabels.Pop();
}
else
{
Builder.AddLine(
$"{GenerateBasicTypeString(term.VariableType)} {temporaryName} = " +
$"{e.Left.VariableName} {GenerateMultipleOperator(e.Operator)} {e.Right.VariableName};");
}
term.VariableName = temporaryName; term.VariableName = temporaryName;
_termVariableName = temporaryName;
}; };
} }
@ -316,26 +355,58 @@ public class CodeGeneratorVisitor : TypeCheckVisitor
{ {
e.Left.IsCondition = simpleExpression.IsCondition; e.Left.IsCondition = simpleExpression.IsCondition;
e.Right.IsCondition = simpleExpression.IsCondition; e.Right.IsCondition = simpleExpression.IsCondition;
if (e.Operator.OperatorToken == new Terminator(KeywordType.Or))
{
_orCircuitLabels.Push(new CircuitLabel($"or_circuit_{_labelCount}",
$"or_end_circuit_{_labelCount}"));
_labelCount += 1;
}
}; };
simpleExpression.OnTermGenerator += (_, e) => { e.Term.IsCondition = simpleExpression.IsCondition; }; simpleExpression.OnTermGenerator += (_, e) => { e.Term.IsCondition = simpleExpression.IsCondition; };
} }
private string? _simpleExpressionVairableName;
public override void PostVisit(SimpleExpression simpleExpression) public override void PostVisit(SimpleExpression simpleExpression)
{ {
base.PostVisit(simpleExpression); base.PostVisit(simpleExpression);
simpleExpression.OnTermGenerator += (_, e) => { simpleExpression.VariableName = e.Term.VariableName; }; simpleExpression.OnTermGenerator += (_, e) =>
{
simpleExpression.VariableName = e.Term.VariableName;
_simpleExpressionVairableName = simpleExpression.VariableName;
};
simpleExpression.OnAddGenerator += (_, e) => simpleExpression.OnAddGenerator += (_, e) =>
{ {
string temporaryName = GenerateTemporaryVariable(); string temporaryName = GenerateTemporaryVariable();
Builder.AddLine( if (e.Operator.OperatorToken == new Terminator(KeywordType.Or))
$"{GenerateBasicTypeString(simpleExpression.VariableType)} {temporaryName} = " + {
$"{e.Left.VariableName} {GenerateAddOperator(e.Operator)} {e.Right.VariableName};"); // or的短路代码
Builder.AddLine($"""
bool {temporaryName};
{temporaryName} = {e.Left.VariableName} || {e.Right.VariableName};
goto {_orCircuitLabels.Peek().End};
{_orCircuitLabels.Peek().Circuit}:;
{temporaryName} = true;
{_orCircuitLabels.Peek().End}:;
""");
_orCircuitLabels.Pop();
}
else
{
Builder.AddLine(
$"{GenerateBasicTypeString(simpleExpression.VariableType)} {temporaryName} = " +
$"{e.Left.VariableName} {GenerateAddOperator(e.Operator)} {e.Right.VariableName};");
}
simpleExpression.VariableName = temporaryName; simpleExpression.VariableName = temporaryName;
_simpleExpressionVairableName = temporaryName;
}; };
} }
@ -723,7 +794,20 @@ public class CodeGeneratorVisitor : TypeCheckVisitor
goto {_whileEndLabels.Peek()}; goto {_whileEndLabels.Peek()};
"""); """);
} }
break;
case KeywordType.And:
// 加上and短路的判断代码
Builder.AddLine($"""
if (!{_termVariableName})
goto {_andCircuitLabels.Peek().Circuit};
""");
break;
case KeywordType.Or:
// 加上or短路的判断代码
Builder.AddLine($"""
if ({_simpleExpressionVairableName})
goto {_orCircuitLabels.Peek().Circuit};
""");
break; break;
} }
} }
@ -853,6 +937,8 @@ public class CodeGeneratorVisitor : TypeCheckVisitor
return basicType.IsReference ? "char *" : "char"; return basicType.IsReference ? "char *" : "char";
case BasicType.Boolean: case BasicType.Boolean:
return basicType.IsReference ? "bool *" : "bool"; return basicType.IsReference ? "bool *" : "bool";
case BasicType.Void:
return "void";
} }
return string.Empty; return string.Empty;

View File

@ -71,17 +71,24 @@ public abstract class PascalType : IEquatable<PascalType>
public static PascalType operator +(PascalType a, PascalType b) public static PascalType operator +(PascalType a, PascalType b)
{ {
if (a is PascalBasicType { Type: BasicType.Boolean } && b is PascalBasicType { Type: BasicType.Boolean }) if (a is not PascalBasicType aType || b is not PascalBasicType bType)
{
return PascalBasicType.Void;
}
if (aType.Type == BasicType.Boolean && bType.Type == BasicType.Boolean)
{ {
return PascalBasicType.Boolean; return PascalBasicType.Boolean;
} }
if (a is PascalBasicType { Type: BasicType.Integer } && b is PascalBasicType { Type: BasicType.Integer }) if (aType.Type == BasicType.Integer && bType.Type == BasicType.Integer)
{ {
return PascalBasicType.Integer; return PascalBasicType.Integer;
} }
if (a is PascalBasicType { Type : BasicType.Real } && b is PascalBasicType { Type: BasicType.Real }) if ((aType.Type == BasicType.Real && bType.Type == BasicType.Real)
|| (aType.Type == BasicType.Real && bType.Type == BasicType.Integer)
|| (aType.Type == BasicType.Integer && bType.Type == BasicType.Real))
{ {
return PascalBasicType.Real; return PascalBasicType.Real;
} }