📄 declaration.c
字号:
#include "declaration.h"#include "error.h"#include "io.h"#include "salloc.h"#include <string.h>/* Variable to temporarily hold a Declaration pointer for subtype check. Used * in the ASSERT_DECL_SUBTYPE macro. */Declaration *__decl;List *global_declarations;Declaration *new_subprogram_declaration(Token *token){ Declaration *decl = safe_malloc(sizeof(Declaration)); decl->subtype = subprog_decl; decl->token = token; SUBPROG_DECL(decl).body = 0; SUBPROG_DECL(decl).formal_args_scope = 0; SUBPROG_DECL(decl).formal_args = 0; SUBPROG_DECL(decl).type = 0; SUBPROG_DECL(decl).return_type = 0; SUBPROG_DECL(decl).redeclaration = 0; SUBPROG_DECL(decl).has_been_defined = false; return decl;}Declaration *new_var_declaration(Token *token){ Declaration *decl = safe_malloc(sizeof(Declaration)); decl->subtype = var_decl; decl->token = token; VAR_DECL(decl).type = 0; return decl;}/*add : create a new record declaration */Declaration *new_record_declaration(Token *token){ Declaration *decl = safe_malloc(sizeof(Declaration)); decl->subtype = record_decl; decl->token = token; return decl;}void delete_declaration(Declaration *decl){ if (decl != 0) { switch (decl->subtype) { case subprog_decl: delete_statement(SUBPROG_DECL(decl).body); delete_scope(SUBPROG_DECL(decl).formal_args_scope); delete_declaration_list(SUBPROG_DECL(decl).formal_args); delete_type(SUBPROG_DECL(decl).type); delete_type(SUBPROG_DECL(decl).return_type); break; case var_decl: delete_type(VAR_DECL(decl).type); break; case record_decl: /*add*/ delete_scope(RECORD_DECL(decl).formal_var_scope); delete_declaration_list(RECORD_DECL(decl).formal_var); break; } delete_token(decl->token); free(decl); }}void delete_declaration_list(List *declarations){ if (declarations != 0) { unsigned i; for (i = 0; i < list_size(declarations); i ++) delete_declaration(list_index(declarations, i)); delete_list(declarations); }}/* Redeclaring is only allowed for subprograms, and only if the types * are identical. This function checks whether that is the case for * two declarations. */static void match_subprogram_prototypes(Declaration *d1, Declaration *d2){ unsigned i; List *formals1, *formals2; Type *t1, *t2; if (d1->subtype != subprog_decl) { error(d2->token, "%s redeclares non-subprogram", d2->token->name); return; } formals1 = SUBPROG_DECL(d1).formal_args; formals2 = SUBPROG_DECL(d2).formal_args; if (formals1 != 0 && formals2 != 0) { if (list_size(formals1) != list_size(formals2)) error(d2->token, "%s redeclared with different number of arguments", d2->token->name); else for (i = 0; i < list_size(formals1); i ++) { Declaration *var1 = list_index(formals1, i); Declaration *var2 = list_index(formals2, i); t1 = VAR_DECL(var1).type; t2 = VAR_DECL(var2).type; if (!types_compatible(t1, t2) || t1->call_by_ref != t2->call_by_ref) error(var2->token, "argument %u redeclared with different type", i + 1); } } t1 = SUBPROG_DECL(d1).return_type; t2 = SUBPROG_DECL(d2).return_type; if (!types_compatible(t1, t2)) error(d2->token, "different return type for redeclared subprogram %s", d2->token->name);}static void type_check_main_function(Declaration *decl){ List *formals; Declaration *arg; Type *type; if (strcmp(decl->token->name, "main") == 0 && (formals = SUBPROG_DECL(decl).formal_args) != 0 && (list_size(formals) != 1 || ((arg = list_index(formals, 0)) != 0 && (type = VAR_DECL(arg).type) != 0 && (type->call_by_ref || type->subtype != array_type || ((type = ARRAY_TYPE(type).base_type) != 0 && (type->subtype != array_type || ((type = ARRAY_TYPE(type).base_type) != 0 && type->subtype != char_type))))) || SUBPROG_DECL(decl).return_type == 0 || SUBPROG_DECL(decl).return_type->subtype != int_type)) error(decl->token, "prototype of global function main should be: " "\"function main(argv : array of string) : int;\"");}static void type_check_subprogram_declaration(Declaration *decl){ Declaration *redecl = SUBPROG_DECL(decl).redeclaration; if (redecl != 0) { match_subprogram_prototypes(redecl, decl); if (redecl->subtype == subprog_decl && SUBPROG_DECL(decl).body != 0) { if (SUBPROG_DECL(redecl).has_been_defined) error(decl->token, "multiple definition of %s", decl->token->name); else SUBPROG_DECL(redecl).has_been_defined = true; } } type_check_statement(SUBPROG_DECL(decl).body, decl); type_check_main_function(decl);}/*add : check if there is a recursive definition in record declaration */void type_check_record_declaration(Declaration *decl){ unsigned i; Declaration *var; for(i=0;i<list_size(RECORD_DECL(decl).formal_var);i++) { var=list_index(RECORD_DECL(decl).formal_var,i); if(VAR_DECL(var).type->subtype==record_type) { if(decl->token->name==RECORD_TYPE(VAR_DECL(var).type).decl->token->name) { error(decl->token,"%s struct has a recursive definition",decl->token->name); break; } } }}void type_check_declaration(Declaration *decl){ if (decl == 0) return; switch (decl->subtype) { case subprog_decl: type_check_subprogram_declaration(decl); break; case var_decl: break; /*add : check recursion in record declaration */ case record_decl: type_check_record_declaration(decl); break; }}void type_check_declaration_list(List *declarations){ if (declarations != 0) { unsigned i; for (i = 0; i < list_size(declarations); i ++) type_check_declaration(list_index(declarations, i)); }}/*add : initialize a new record declaration and create C code */void initialize_record_decl(FILE *file, Declaration *decl){ Declaration *var; unsigned i; fprintf(file,"{"); for(i=0;i<list_size(RECORD_DECL(decl).formal_var);i++) { var=list_index(RECORD_DECL(decl).formal_var,i); switch (VAR_DECL(var).type->subtype) { case bool_type: fprintf(file,"false"); if(i!=list_size(RECORD_DECL(decl).formal_var)-1) fprintf(file,","); break; case char_type: fprintf(file,"0"); if(i!=list_size(RECORD_DECL(decl).formal_var)-1) fprintf(file,","); break; case int_type: fprintf(file,"0"); if(i!=list_size(RECORD_DECL(decl).formal_var)-1) fprintf(file,","); break; case real_type: fprintf(file,"0.0"); if(i!=list_size(RECORD_DECL(decl).formal_var)-1) fprintf(file,","); break; case array_type: fprintf(file,"NULL"); if(i!=list_size(RECORD_DECL(decl).formal_var)-1) fprintf(file,","); break; case record_type: initialize_record_decl(file,RECORD_TYPE(VAR_DECL(var).type).decl); if(i!=list_size(RECORD_DECL(decl).formal_var)-1) fprintf(file,","); break; default: error(decl->token,"this declaration %s is unknown", decl->token->name); break; } } fprintf(file,"}");}/* add : adding initialision of record declaration*/static void generate_var_declaration(FILE *file, Declaration *decl, Bool initialize){ /* RAFB: bug fix. We must generate an extern declaration for * each global variable in case it is used before it is * declared. */ if (lookup_in_this_scope(global_scope, decl->token->name) == decl) { fprintf(h_out, "extern "); generate_type(h_out, VAR_DECL(decl).type); fprintf(h_out, " cb_%s;\n", decl->token->name); } generate_type(file, VAR_DECL(decl).type); fprintf(file, " cb_%s", decl->token->name); if(initialize) { switch (VAR_DECL(decl).type->subtype) { case bool_type: fprintf(file,"=false"); break; case char_type: fprintf(file,"=0"); break; case int_type: fprintf(file,"=0"); break; case real_type: fprintf(file,"=0.0"); break; case array_type: fprintf(file,"=NULL"); break; case record_type: fprintf(file,"="); initialize_record_decl(file,RECORD_TYPE(VAR_DECL(decl).type).decl); break; default: error(decl->token,"this declaration %s is unknown", decl->token->name); break; } }}static void generate_prototype(FILE *file, Declaration *decl){ unsigned i; generate_type(file, SUBPROG_DECL(decl).return_type); fprintf(file, " cb_%s", decl->token->name); for (i = 0; i < list_size(SUBPROG_DECL(decl).formal_args); i ++) { Declaration *arg = list_index(SUBPROG_DECL(decl).formal_args, i); putc(i == 0 ? '(' : ',', file); generate_var_declaration(file, arg, false); } fprintf(file, i == 0 ? "(void)" : ")");}/*add : create C code in h_out file for a record declaration */static void generate_record_declaration(FILE *file, Declaration *decl,Bool initialize){ unsigned i; Declaration *var; fprintf(file,"typedef struct"); fprintf(file," {\n"); for(i=0;i<list_size(RECORD_DECL(decl).formal_var);i++) { var=list_index(RECORD_DECL(decl).formal_var,i); generate_var_declaration(file, var, initialize); fprintf(file,";\n"); } fprintf(file,"}\n"); fprintf(file,"record_%s;\n",decl->token->name);}static void generate_subprog_declaration(Declaration *decl){ generate_prototype(h_out, decl); fprintf(h_out, ";\n"); if (SUBPROG_DECL(decl).body != 0) { generate_prototype(c_out, decl); fprintf(c_out, "{\n"); generate_statement(SUBPROG_DECL(decl).body); if (SUBPROG_DECL(decl).return_type->subtype != void_type) fprintf(c_out, "runtime_error(\"%s returns no value\");", decl->token->name); fprintf(c_out, "}\n"); }}void generate_declaration(Declaration *decl){ switch (decl->subtype) { case subprog_decl: generate_subprog_declaration(decl); break; case var_decl: if(VAR_DECL(decl).type->subtype!=record_type) generate_var_declaration(c_out, decl, true); else generate_var_declaration(c_out, decl, true); fprintf(c_out, ";\n"); break; case record_decl: generate_record_declaration(h_out,decl,false); break; }}void generate_declaration_list(List *declarations){ unsigned i; for (i = 0; i < list_size(declarations); i ++) generate_declaration(list_index(declarations, i));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -