Компилятор AST как реализовать операторы и выражения
В настоящее время работает над небольшим игрушечным компилятором, рассмотрим этот код
// AST base class
abstract class AST { /* codegen methods */}
// abstract classes for Statements and Expressions
abstract class Statement : AST {}
abstract class Expression : AST {}
// usage of the abstract classes
class CodeBlock : AST {
public List<Statement> BlockStatements;
}
class BinOp : AST {
public Expression LHS, RHS;
public char Operator;
}
// a constant value is always an expression
class ConstantInt : Expression {
public int Value;
}
Теперь к проблеме, как бы я реализовать FunctionCall
учебный класс? Если он используется в выражении, он будет частью выражения, как min(4, 5) + 3
для этого FunctionCall : Expression
имеет смысл. Но тогда я не могу иметь вызовы функций в блоке, как это { writeToConsole("Hello World"); }
Итак FunctionCall : Statement
звучит разумно, но это не будет работать с синтаксисом выражения. Изготовление Statement
наследовать от Expression
не будет работать, так как это позволит AST, как это min(4, 5) + int a
,
Я хотел бы получить предложения о том, как сохранить операторы и выражения отдельно, за исключением вещей, которые могут быть обоими.
3 ответа
Делать так, чтобы заявления были выражениями, на самом деле не очень хорошая идея (по той причине, на которую вы указали). Однако сделать так, чтобы выражения были заявлениями, гораздо больше достоинств.
На самом деле грамматика большинства языков имеет следующую запись:
statement ::= expression ';'
Это выражение, за которым следует точка с запятой, это оператор, так называемый оператор выражения. В вашем AST вы можете представить это либо сделав Expression
унаследовать Statement
или создав класс ExpressionStatement
, который просто заворачивает Expression
,
Помимо разрешения вызовов функций как операторов, он также позволяет использовать другие выражения как операторы. Для выражений с побочными эффектами, таких как присваивания, составные присваивания или выражения приращения, это имеет большой смысл.
Для выражений без побочных эффектов, таких как простая арифметика, это имеет меньше смысла. В C и C++ утверждение типа a + b;
на самом деле является законным, но вызывает большинство компиляторов предупреждение. В других языках существует явное правило, которое запрещает использование определенных типов выражений в качестве выражений операторов.
¹ Разумеется, только с учетом тех языков, которые вообще имеют различие между утверждениями и выражениями.
Простой способ достижения этого - работа с интерфейсами. Используйте интерфейс IStatement и IExpression, и заставьте FunctionCall реализовать оба. Кроме того, заставьте свой BinOp реализовать IExpression
Вы должны понимать, что у вас есть "функции, возвращающие значения" (которые должны быть выражениями), и "функции, которые не возвращают значения (которые должны быть выражениями).
Таким образом, ваша проблема исчезнет, если вы определите ExpressionFunction и StatementFunction как отдельные классы.
Альтернатива: вы можете определить функцию как выражение и определить StatementFunction как AST с функцией в качестве поля.