#ifndef EXPRESSION_H#define EXPRESSION_Htypedef struct expression Expression;#include <assert.h>#include "bool.h"#include "list.h"#include "scope.h"#include "token.h"#include "type.h"typedef enum{ expr_and = 10, expr_bool_const, expr_char_const, expr_div, expr_eq, expr_func_call, expr_ge, expr_gt, expr_ident, expr_index, expr_int_const, expr_min, expr_mul, expr_ne, expr_newarray, expr_newobject, expr_not, expr_null, expr_or, expr_plus, expr_qualident, expr_real_const, expr_se, expr_select, expr_self, expr_size, expr_st, expr_string_const, expr_unary_min, expr_unary_plus}Expr_subtype;/* Expressions are stored in 'Expression'-type structures. The subtype * field indicates the type of the expression (listed in Expr_subtype). * Depending on this type, the union un may contain fields specific to * function call, indentifier, or string constant expressions. These * should be accessed using the EXPR_FUNC_CALL, EXPR_IDENT, * EXPR_STRING_CONSTANT defines! For most expressions all necessary data * is stored in the two operand fields, which point to other expressions. * For example, '3+4' would be represented as an expression of type * expr_plus, with operand[0] and operand[1] pointing to two expressions * of type expr_int_const. */struct expression{ Expr_subtype subtype; Token *token; Expression *operand [2]; Type *type; union { struct { List *formal_args; /* List<Declaration *> */ List *actual_args; /* List<Expression *> */ } func_call; struct { Scope *scope; int used_as_field; } identifier; struct { Scope *scope; Expression *object; } qualident; struct { Scope *scope; } self; struct { unsigned index; unsigned length; } string_const; } un;};/* Enforce that expression e is of subtype st. The result is again e. To * prevent double evaluation of the macro argument, the argument is temporarily * stored in the __expr variable.*/#define ASSERT_EXPR_SUBTYPE(e,st) (__expr = (e), assert(__expr->subtype == st), __expr)extern Expression *__expr;/* Macros for less verbose access to the members of the structs within * the union. These macros also check that they are applied to appropriate * instances of the Expression struct. * * In essence, these macros perform (e)->un.xxx */#define EXPR_FUNC_CALL(e) \ (ASSERT_EXPR_SUBTYPE(e, expr_func_call)->un.func_call)#define EXPR_IDENT(e) \ (ASSERT_EXPR_SUBTYPE(e, expr_ident)->un.identifier)#define EXPR_QUALIDENT(e) \ (ASSERT_EXPR_SUBTYPE(e, expr_qualident)->un.qualident)#define EXPR_STRING_CONST(e) \ (ASSERT_EXPR_SUBTYPE(e, expr_string_const)->un.string_const)#define EXPR_SELF(e) \ (ASSERT_EXPR_SUBTYPE(e, expr_self)->un.self)Expression *new_expression(Expr_subtype, Token *, Expression *left, Expression *right);void delete_expression(Expression *);Type *type_check_expression(Expression *);Bool is_lvalue_(Expression *, char **);#define is_lvalue(e) is_lvalue_((e), NULL)void generate_expression(Expression *);/* During type checking, all string constants are listed in 'string_list'. * At code generation time, this list is converted to a C as an array of * strings. */void generate_string_list(void);extern List *string_list;#endif