Компилятор 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 с функцией в качестве поля.

Другие вопросы по тегам