From: Peep P. <so...@us...> - 2004-03-16 20:21:41
|
Update of /cvsroot/agd/server/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27524 Modified Files: lang.y Log Message: Added trinary ?: operator; fixed implicit function return type Index: lang.y =================================================================== RCS file: /cvsroot/agd/server/src/lang.y,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- lang.y 16 Mar 2004 14:12:43 -0000 1.4 +++ lang.y 16 Mar 2004 20:12:21 -0000 1.5 @@ -6,8 +6,8 @@ YYLTYPE yylloc; /* Lexical tie-ins. */ -static int global_type - /*num_locals*/; /* So F_RETURN knows how much locals to pop. */ +static int global_type, + curr_f_type; extern int scope_level; void add_function(def_id_t *idp, int lineno, array_t *code); @@ -50,6 +50,7 @@ %left L_EQ L_NE %left L_PLUS L_MINUS %left L_MUL L_DIV L_MOD +%right '?' ':' %left L_DEREF /* L_DEREF _is_ a valid lval for call_other. i.e: ob->get_another_ob()->call(), as long as ob->get_another_ob() returns T_OBJECT. */ @@ -87,7 +88,6 @@ | type name_list ';' { add_variable(&$2, ID_GVAR); -/* free_array(&$2, (void (*)(void *))free_var);*/ global_type = 0; } ; @@ -114,6 +114,8 @@ $<id>$ = find_id($2); $<i>3 = 1; /* Means we just defined the prototype. */ } + + curr_f_type = $1; } '(' arguments ')' { @@ -145,21 +147,41 @@ char buf[256]; sprintf(buf, "definition doesn't match declaration for %s", $2); comp_error(buf); - /*goto out;*/ } idp->type = ID_FUN; - + if((int)$9.data[$9.length-1] != F_RETURN) { - if($1 != T_VOID) { + int warn = 0; + + switch(DEFAULT_FUNCTION_TYPE) { + case T_INT: + warn = 1; + array_push(&$9, (void *) F_PUSH_INT); + array_push(&$9, (void *) 0); + break; + case T_STRING: + warn = 1; + array_push(&$9, (void *) F_PUSH_STRING); + array_push(&$9, (void *) 0); + break; + case T_OBJECT: + warn = 1; + array_push(&$9, (void *) F_PUSH_NULL_OBJECT); + break; + case T_VOID: + array_push(&$9, (void *) F_PUSH_VOID); + break; + } + array_push(&$9, (void *) F_RETURN); + if(warn) { comp_error("control reaches end of non-void function"); - } else { - array_push(&$9, (void *) F_PUSH_VOID); - array_push(&$9, (void *) F_RETURN); } } add_function(idp, $<i>8, &$9); + + curr_f_type = 0; } else { def_id_t *idp = $<id>4; if(idp->type == ID_FUN_PROT && !$<i>3) { @@ -172,29 +194,120 @@ } } pop_scope(); -/* free_array(&$5, (void (*)(void *))free_var);*/ } - | L_IDENTIFIER + | L_IDENTIFIER { - comp_warning("return type defaults to int"); -/* $<i>$ = define_name(TYPE_FUN | SCOPE_LOCAL, $1, T_INT, NULL, 1);*/ + char buf[256]; + char *s; + switch(DEFAULT_FUNCTION_TYPE) { + case T_INT: s = "int"; break; + case T_STRING: s = "string"; break; + case T_VOID: s = "void"; break; + case T_OBJECT: s = "object"; break; + } + sprintf(buf, "warning: return type defaults to %s", s); + display_error(buf); + compile_warnings++; + /* Mid-rule action used only to store a value. + Feels hacky, but I don't want a global variable. + + 1 if the function declaration was just added; + 0 if it already existed. + Makes sense only in regard to the next action. */ + } + { + def_id_t *idp; + $<id>$ = idp = find_id($1); + if(idp) { + $<i>2 = 0; /* Means it already existed. */ + if(idp->type != ID_FUN_PROT) + redeclaration_error(idp, ID_FUN); + } else { + define_id($1, ID_FUN_PROT, DEFAULT_FUNCTION_TYPE, NULL); /* define_id could return id_t*. */ + $<id>$ = find_id($1); + $<i>2 = 1; /* Means we just defined the prototype. */ + } + + curr_f_type = DEFAULT_FUNCTION_TYPE; } '(' arguments ')' { -/* predeclare_function(T_INT, $1, &$4);*/ + def_id_t *idp; + int i; + idp = $<id>2; + idp->args = copy_array(&$5, NULL); + + scope_level++; + for(i=0;i<$5.length;i++) { + variable_t *v; + def_id_t *id; + v = $5.data[i]; + id = find_id(v->name); + if(id && id->base_scope >= scope_level) { + redeclaration_error(id, ID_ARG); + } else { + define_id(v->name, ID_ARG, v->type, NULL); + } + } + /*scope_level--;*/ $<i>$ = yylloc.line; } - block_or_semi + block_or_semi { -/* if($7.length) { - add_code(&$7); - add_function(T_INT, $1, $4, $<i>6); - } else if($<i>2 == 3) { - redefinition_error($1); - nametable_remove_cob(TYPE_FUN|SCOPE_LOCAL, $1); - }*/ -/* free_array(&$4, (void (*)(void *))free_var);*/ + if($8.length) { + def_id_t *idp = $<id>3; + if(idp->lpc_type != DEFAULT_FUNCTION_TYPE || compare_args(idp->args, &$5)) { + char buf[256]; + sprintf(buf, "definition doesn't match declaration for %s", $1); + comp_error(buf); + } + + idp->type = ID_FUN; + + if((int)$8.data[$8.length-1] != F_RETURN) { + int warn = 0; + + switch(DEFAULT_FUNCTION_TYPE) { + case T_INT: + warn = 1; + array_push(&$8, (void *) F_PUSH_INT); + array_push(&$8, (void *) 0); + break; + case T_STRING: + warn = 1; + array_push(&$8, (void *) F_PUSH_STRING); + array_push(&$8, (void *) 0); + break; + case T_OBJECT: + warn = 1; + array_push(&$8, (void *) F_PUSH_NULL_OBJECT); + break; + case T_VOID: + array_push(&$8, (void *) F_PUSH_VOID); + break; + array_push(&$8, (void *) F_RETURN); + if(warn) + comp_error("control reaches end of non-void function"); + } + } + + add_function(idp, $<i>7, &$8); + + curr_f_type = 0; + } else { + def_id_t *idp = $<id>3; + if(idp->type == ID_FUN_PROT && !$<i>2) { + char buf[256]; + sprintf(buf, "warning: repeated prototype for %s; using existing prototype", $1); + display_error(buf); + compile_warnings++; + } else { + add_function(idp, $<i>8, NULL); + } + } + pop_scope(); } + ; block_or_semi: @@ -214,21 +327,16 @@ { new_block_level(); } - local_vars - { -/* num_locals = $3.length;*/ - } - statements '}' + local_vars statements '}' { int i; - $$ = add_block(&$5); + $$ = add_block(&$4); if((int)$$.data[$$.length-1] != F_RETURN) { for(i=0;i<$3.length;i++) { /* Pop each local off the stack. */ array_push(&$$, (void *) F_POP); } } -/* num_locals = 0;*/ end_block_level(); } ; @@ -406,8 +514,7 @@ sprintf(buf, "warning: declaration of %s shadows function argument", $1); display_error(buf); compile_warnings++; - } else if(id->type == ID_DFUN - || id->base_scope >= scope_level) { + } else if(id->type == ID_DFUN || id->base_scope >= scope_level) { redeclaration_error(id, ID_LVAR); } } @@ -800,6 +907,24 @@ array_push(&$$.arr, (void *) F_PUSH_INT); array_push(&$$.arr, (void *) 0); } + | expr '?' expr ':' expr + { + $$.lval = $3.lval && $5.lval; + $$.side_effect = $3.side_effect || $5.side_effect; + $$.direct_type = 0; + $$.type = $3.type; + if($3.type != $5.type) { + comp_error("type mismatch"); + } + init_array(&$$.arr); + array_concat(&$$.arr, &$1.arr); + array_push(&$$.arr, (void *) F_JMPF); + array_push(&$$.arr, (void *) $3.arr.length + 3); + array_concat(&$$.arr, &$3.arr); + array_push(&$$.arr, (void *) F_JMP); + array_push(&$$.arr, (void *) $5.arr.length + 1); + array_concat(&$$.arr, &$5.arr); + } | string { $$.lval = $$.side_effect = 0; @@ -1193,13 +1318,16 @@ return: L_RETURN optional_expr { -/* int i;*/ + if(curr_f_type == T_VOID) { + if($2.arr.length) { + comp_error("return from a void function with a value"); + } + } else if($2.type != curr_f_type) { + comp_error("improper return type"); + } init_array(&$$); -/* for(i=0;i<num_locals;i++) { - array_push(&$$, (void *) F_POP); - }*/ - if(!$2.arr.length) { + if(!$2.arr.length) { array_push(&$$, (void *) F_PUSH_VOID); } else { array_concat(&$$, &$2.arr); |