Я хотел бы изменить генератор кода моего компилятора, чтобы использовать шаблон посетителя, поскольку текущий подход должен использовать несколько условных операторов для проверки реального типа дочернего элемента перед созданием соответствующего кода. Однако у меня проблемы с получением атрибутов детей после их посещения. Например, в двоичном выражении я использую это:
LHSCode := GenerateExpressionCode(LHSNode);
RHSCode := GenerateExpressionCode(RHSNode);
CreateBinaryExpression(Self,LHS,RHS);
В шаблоне посетителя метод посещения обычно недействителен, поэтому я не могу получить код выражения из LHS и RHS. Сохранение общих глобальных переменных невозможно, поскольку генерация кода выражений является рекурсивной, поэтому предыдущие значения, хранящиеся в переменных, могут быть удалены.
Я просто покажу бинарное выражение, так как это самая сложная часть (на данный момент):
function TLLVMCodeGenerator.GenerateExpressionCode(
Expr: TASTExpression): TLLVMValue;
var
BinExpr: TASTBinaryExpression;
UnExpr: TASTUnaryExpression;
LHSCode, RHSCode, ExprCode: TLLVMValue;
VarExpr: TASTVariableExpression;
begin
if Expr is TASTBinaryExpression then begin
BinExpr := Expr as TASTBinaryExpression;
LHSCode := GenerateExpressionCode(BinExpr.LHS);
RHSCode := GenerateExpressionCode(BinExpr.RHS);
case BinExpr.Op of
'<': Result := FBuilder.CreateICmp(ccSLT, LHSCode, RHSCode);
'<=': Result := FBuilder.CreateICmp(ccSLE, LHSCode, RHSCode);
'>': Result := FBuilder.CreateICmp(ccSGT, LHSCode, RHSCode);
'>=': Result := FBuilder.CreateICmp(ccSGE, LHSCode, RHSCode);
'==': Result := FBuilder.CreateICmp(ccEQ, LHSCode, RHSCode);
'<>': Result := FBuilder.CreateICmp(ccNE, LHSCode, RHSCode);
'/\': Result := FBuilder.CreateAnd(LHSCode, RHSCode);
'\/': Result := FBuilder.CreateOr(LHSCode, RHSCode);
'+': Result := FBuilder.CreateAdd(LHSCode, RHSCode);
'-': Result := FBuilder.CreateSub(LHSCode, RHSCode);
'*': Result := FBuilder.CreateMul(LHSCode, RHSCode);
'/': Result := FBuilder.CreateSDiv(LHSCode, RHSCode);
end;
end else if Expr is TASTPrimaryExpression then
if Expr is TASTBooleanConstant then
with Expr as TASTBooleanConstant do
Result := FBuilder.CreateConstant(Ord(Value), ltI1)
else if Expr is TASTIntegerConstant then
with Expr as TASTIntegerConstant do
Result := FBuilder.CreateConstant(Value, ltI32)
else if Expr is TASTUnaryExpression then begin
UnExpr := Expr as TASTUnaryExpression;
ExprCode := GenerateExpressionCode(UnExpr.Expr);
case UnExpr.Op of
'~': Result := FBuilder.CreateXor(
FBuilder.CreateConstant(1, ltI1), ExprCode);
'-': Result := FBuilder.CreateSub(
FBuilder.CreateConstant(0, ltI32), ExprCode);
end;
end else if Expr is TASTVariableExpression then begin
VarExpr := Expr as TASTVariableExpression;
with VarExpr.VarDecl do
Result := FBuilder.CreateVar(Ident, BaseTypeLLVMTypeMap[BaseType]);
end;
end;
Надеюсь, вы это понимаете :)