📄 expression.c
字号:
#include "error.h"#include "expression.h"#include "salloc.h"#include "declaration.h"#include <assert.h>#include <string.h>#include <limits.h>#include <float.h>#include <errno.h>#include <ctype.h>/* Variable to temporarily hold a Expression pointer for subtype check. Used * in the ASSERT_EXPR_SUBTYPE macro. */Expression *__expr;List *string_list;Expression *new_expression(Expr_subtype subtype, Token *token, Expression *left_operand, Expression *right_operand){ Expression *expr = safe_malloc(sizeof(Expression)); expr->subtype = subtype; expr->token = token; expr->operand [0] = left_operand; expr->operand [1] = right_operand; expr->type = 0; switch (subtype) { case expr_func_call: EXPR_FUNC_CALL(expr).formal_args = 0; EXPR_FUNC_CALL(expr).actual_args = 0; break; case expr_ident: EXPR_IDENT(expr).scope = 0; break; case expr_record: break; default: break; } return expr;}void delete_expression(Expression *expr){ if (expr != 0) { delete_token(expr->token); delete_expression(expr->operand [0]); delete_expression(expr->operand [1]); delete_type(expr->type); switch (expr->subtype) { List *actuals; unsigned i; case expr_func_call: actuals = EXPR_FUNC_CALL(expr).actual_args; for (i = 0; i < list_size(actuals); i ++) delete_expression(list_index(actuals, i)); delete_list(actuals); break; case expr_record: break; default: break; } free(expr); }}Bool is_lvalue_(Expression *expr, char **offence){ if (expr == 0 || expr->type == 0) return true; if (offence != NULL) *offence = expr->token->name; switch (expr->subtype) { case expr_ident: return expr->type->subtype != subprog_type; case expr_index: return true; case expr_func_call: if (offence != NULL) *offence = "a function call"; return false; case expr_record: return is_lvalue_(expr->operand[0],offence); /*add : check if members of expression is lvalue*/ default: return false; }}/* Type check expr, and see it is of the proper type */static Type *match_type(Expression *expr, Type_subtype subtype_set, const char *expected){ Type *type = type_check_expression(expr); if (type != 0 && (type->subtype & subtype_set) == 0) { error(expr->token, "expected %s type", expected); type = 0; } return type;}static void check_operands_compatibility(Expression *expr){ Expression *operand_0 = expr->operand [0], *operand_1 = expr->operand [1]; if (operand_0 != 0 && operand_1 != 0 && !types_compatible(operand_0->type, operand_1->type)) error(expr->token, "incompatible types for %s operator", expr->token->name);}static void type_check_function_call(Expression *expr){ List *formals, *actuals; unsigned i; Declaration *decl; Expression *func; Type *func_type; if (expr == 0) return; func = expr->operand [0]; func_type = type_check_expression(func); if (func_type == 0) return; if (func_type->subtype != subprog_type) { error(func->token, "called object is not a subprogram"); return; } if ((decl = SUBPROG_TYPE(func_type).decl) == 0) return; /* Koen: fill type in now so caller won't complain when we detect a * problem with the parameters down below */ if ((expr->type = SUBPROG_DECL(decl).return_type) != 0) inc_ref_count(expr->type, 1); formals = EXPR_FUNC_CALL(expr).formal_args = SUBPROG_DECL(decl).formal_args; if (formals == 0) return; if ((actuals = EXPR_FUNC_CALL(expr).actual_args) == 0) return; if (list_size(formals) != list_size(actuals)) { error(expr->token, "parameter count mismatch"); return; } for (i = 0; i < list_size(actuals); i ++) { Declaration *formal_arg = list_index(formals, i); Type *formal_type = VAR_DECL(formal_arg).type; Expression *actual_arg = list_index(actuals, i); Type *actual_type = type_check_expression(actual_arg); Bool call_by_ref = formal_type != 0 && formal_type->call_by_ref; if (!types_compatible(formal_type, actual_type)) error(actual_arg->token, "argument %u: incompatible type", i + 1); /*add : check if parameters have the same struct when call a function */ if (formal_type!=0&&actual_type!=0&&formal_type->subtype==record_type&&actual_type->subtype==record_type) { if(strcmp(RECORD_TYPE(formal_type).decl->token->name,RECORD_TYPE(actual_type).decl->token->name)!=0) error(expr->token,"argument %u: two record types has not the same struct", i+1); } if (call_by_ref && !is_lvalue(actual_arg)) error(actual_arg->token, "actual value of call-by-reference argument must be lvalue"); }}static void type_check_identifier(Expression *expr){ Declaration *decl; if ((decl = lookup(EXPR_IDENT(expr).scope, expr->token->name)) == 0) error(expr->token, "%s not declared", expr->token->name); else { switch (decl->subtype) { case subprog_decl: expr->type = SUBPROG_DECL(decl).type; break; case var_decl: expr->type = VAR_DECL(decl).type; break; case record_decl: /*do nothing*/ break; } inc_ref_count(expr->type, 1); }}/* add : check if an expression of a record is correct */static void type_check_expr_record(Expression *expr){ if(expr->subtype!=expr_record&&expr->subtype!=expr_index&&expr->subtype!=expr_ident&&expr->subtype!=expr_func_call) { error(expr->token, "%s is illegal in an expression of record", expr->token->name); } else { if (expr->subtype==expr_ident) { type_check_identifier(expr); } if (expr->subtype==expr_index) { type_check_expression(expr->operand[0]); type_check_expression(expr); } if (expr->subtype==expr_func_call) { type_check_function_call(expr); } if (expr->subtype==expr_record) { type_check_expr_record(expr->operand[0]); if(expr->operand[0]->type==0||expr->operand[0]->type->subtype != record_type) error(expr->operand[0]->token,"%s an undeclared variable or not a struct ",expr->operand[0]->token->name); else { Declaration *decl=lookup_in_this_scope(RECORD_DECL(RECORD_TYPE(expr->operand[0]->type).decl).formal_var_scope,expr->token->name); if(decl==0) error(expr->token,"%s an undeclared variable ",expr->token->name); else expr->type=VAR_DECL(decl).type; } } }}/* Check escapes in given string (may also be character constant), and calculate the length after interpretation of escapes. */static unsigned check_string_escapes(Token *string, unsigned length) { unsigned i, j, output_length = 0; const char *str = string->name + 1; for (i = 0; i < length; i++) { if (str[i] != '\\') { output_length++; continue; } /* An unterminated string may end in '\' */ if (++i == length) return output_length; if (str[i] == 'x') { for (j = i + 1; j < length; j++) { if (!((str[j] >= '0' && str[j] <= '9') || (str[j] >= 'a' && str[j] <= 'f') || (str[j] >= 'A' && str[j] <= 'F'))) break; } if (j - i == 1) error(string, "invalid esacape sequence '\\x'"); else if (j - i > 3) error(string, "too long hex escape sequence '\\%.*s'", j - i, str + i); i = j - 1; } else if (str[i] >= '0' && str[i] <= '7') { unsigned value = str[i] - '0'; for (j = 1; j < 3 && j + i < length; j++) { if (str[i+j] >= '0' && str[i+j] <= '7') value = value * 8 + (str[i+j] - '0'); else break; } if (value > 255) error(string, "octal escape sequence out of range '\\%.*s'", j, str + i); i += j - 1; } else if (strchr("ntvbrfa\\?'\"", str[i]) == 0) { error(string, "invalid escape sequence '\\%c'", str[i]); } output_length++; } return output_length;}static void check_char_const(Token *string) { unsigned length = strlen(string->name); if (length < 2) /* single ' */ return; if (length == 2 && string->name[1] == '\'') error(string, "empty character constant"); length = check_string_escapes(string, length - 2); if (length > 1) error(string, "more than one character in character constant %s", string->name);}static unsigned check_string_const(Token *string) { unsigned length = strlen(string->name); if (length <= 2) return 0; return check_string_escapes(string, length - 2);}Type *type_check_expression(Expression *expr){ if (expr == 0) return 0; switch (expr->subtype) { Type *type; case expr_bool_const: expr->type = new_simple_type(bool_type); break; case expr_char_const: expr->type = new_simple_type(char_type); check_char_const(expr->token); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -