/* sa.c */ #include #include #include "la.h" #include "pa.h" #include "sa.h" Atype *return_type=NULL; void print_type(FILE *f, Atype *t) { print_syntax(f,t); } void semantic_check(Syntax *t, int level); void semantic_error(char *s, Syntax *t, int linenum) { if (linenum>0) fprintf(errfile,"Error on line %d ", linenum); else fprintf(errfile,"Semantic error "); if (t==NULL) fprintf(errfile,"%s\n", s); else { fprintf(errfile,"in "); print_syntax(errfile,t); fprintf(errfile,"\n...%s\n",s); } } void declare(SymbolDescription *var, Atype *type, int level, int linenum) { DeclarationRecord *dr=malloc(sizeof(DeclarationRecord)), *olddr=var->decls; if (olddr!=NULL) { if (olddr->level==level) { char errm[100]; sprintf(errm,"redeclaration of \"%s\"", var->name); semantic_error(errm,NULL,linenum); } } dr->type=type; dr->level=level; dr->place=0; dr->previous=olddr; var->decls=dr; } void undeclare(SymbolDescription *var) { DeclarationRecord *dr=var->decls; if (dr==NULL) { fprintf(stderr,"error in compiler, undeclaring %s/%d\n",var->name,dr->level); return; } var->decls=dr->previous; free(dr); } void print_declaration(DeclarationRecord *dr) { if (dr==NULL) printf("(no declaration)"); else { printf(" Level=%d Place=%d Type=",dr->level,dr->place); print_type(stdout,dr->type); printf("\n"); } } void print_declarations(SymbolDescription *var) { DeclarationRecord *dr=var->decls; printf("Declarations of \"%s\":",var->name); if (dr==NULL) { printf(" (none)\n"); return; } else printf("\n"); while (dr!=NULL) { print_declaration(dr); dr=dr->previous; } } struct Tsimple *t_void, *t_int, *t_float, *t_char; struct Tpointerto *t_charstar, *t_voidstar; void declare_builtin_functions(void) { struct Tfunction *t; SymbolDescription *s, *x; DeclarationRecord *d; struct Sdeclareparamlist *pl; struct Sfixedparam *p; x=lookup_symbol("X"); p=malloc(sizeof(struct Sfixedparam)); p->tag=TTfixedparam; p->linenum=0; p->type=t_int; p->var=x; pl=malloc(sizeof(struct Sdeclareparamlist)); pl->tag=TTdeclareparamlist; pl->first=p; pl->rest=NULL; t=malloc(sizeof(struct Tfunction)); t->tag=TTfunction; t->returns=t_void; t->params=pl; t->defined=1; d=malloc(sizeof(DeclarationRecord)); d->type=t; d->level=1; d->place=1; d->previous=NULL; s=lookup_symbol("PRINTINT"); s->kind=SKidentifier; s->decls=d; p=malloc(sizeof(struct Sfixedparam)); p->tag=TTfixedparam; p->linenum=0; p->type=t_float; p->var=x; pl=malloc(sizeof(struct Sdeclareparamlist)); pl->tag=TTdeclareparamlist; pl->first=p; pl->rest=NULL; t=malloc(sizeof(struct Tfunction)); t->tag=TTfunction; t->returns=t_void; t->params=pl; t->defined=1; d=malloc(sizeof(DeclarationRecord)); d->type=t; d->level=1; d->place=1; d->previous=NULL; s=lookup_symbol("PRINTFLOAT"); s->kind=SKidentifier; s->decls=d; p=malloc(sizeof(struct Sfixedparam)); p->tag=TTfixedparam; p->linenum=0; p->type=t_charstar; p->var=x; pl=malloc(sizeof(struct Sdeclareparamlist)); pl->tag=TTdeclareparamlist; pl->first=p; pl->rest=NULL; t=malloc(sizeof(struct Tfunction)); t->tag=TTfunction; t->returns=t_void; t->params=pl; t->defined=1; d=malloc(sizeof(DeclarationRecord)); d->type=t; d->level=1; d->place=1; d->previous=NULL; s=lookup_symbol("PRINTSTRING"); s->kind=SKidentifier; s->decls=d; t=malloc(sizeof(struct Tfunction)); t->tag=TTfunction; t->returns=t_int; t->params=NULL; t->defined=1; d=malloc(sizeof(DeclarationRecord)); d->type=t; d->level=1; d->place=1; d->previous=NULL; s=lookup_symbol("READINT"); s->kind=SKidentifier; s->decls=d; t=malloc(sizeof(struct Tfunction)); t->tag=TTfunction; t->returns=t_float; t->params=NULL; t->defined=1; d=malloc(sizeof(DeclarationRecord)); d->type=t; d->level=1; d->place=1; d->previous=NULL; s=lookup_symbol("READFLOAT"); s->kind=SKidentifier; s->decls=d; } void init_type_checker(void) { t_void=malloc(sizeof(struct Tsimple)); t_void->tag=TTsimple; t_void->type=TYvoid; t_int=malloc(sizeof(struct Tsimple)); t_int->tag=TTsimple; t_int->type=TYint; t_float=malloc(sizeof(struct Tsimple)); t_float->tag=TTsimple; t_float->type=TYfloat; t_char=malloc(sizeof(struct Tsimple)); t_char->tag=TTsimple; t_char->type=TYchar; t_charstar=malloc(sizeof(struct Tpointerto)); t_charstar->tag=TTpointerto; t_charstar->what=t_char; t_voidstar=malloc(sizeof(struct Tpointerto)); t_voidstar->tag=TTpointerto; t_voidstar->what=t_void; declare_builtin_functions(); } int is_function_type(Atype *t) { struct Tgeneric *g=t; return (g->tag==TTfunction); } int is_pointer(Atype *t) { struct Tgeneric *g=t; return (g->tag==TTpointerto); } int same_type(Atype *s, Atype *t) { struct Tgeneric *sg=s, *tg=t; if (sg==NULL || tg==NULL) return (0); switch (sg->tag) { case TTsimple: { struct Tsimple *ss=s, *ts=t; if (tg->tag!=TTsimple) return (0); return (ss->type==ts->type); } case TTpointerto: { struct Tpointerto *sp=s, *tp=t; struct Tarrayof *ta=t; if (tg->tag==TTpointerto) return (same_type(sp->what,tp->what)); else if (tg->tag==TTarrayof) return (same_type(sp->what,ta->what)); else return (0); } case TTarrayof: { struct Tarrayof *sa=s, *ta=t; struct Tpointerto *tp=t; if (tg->tag==TTpointerto) return (same_type(sa->what,tp->what)); else if (tg->tag==TTarrayof) return (same_type(sa->what,ta->what)); else return (0); } case TTfunction: { struct Tfunction *sf=s, *tf=t; struct Sdeclareparamlist *l1, *l2; if (tg->tag!=TTfunction) return (0); if (!same_type(sf->returns,tf->returns)) return (0); l1=sf->params; l2=tf->params; while (l1!=NULL && l2!=NULL) { struct Sfixedparam *p1=l1->first, *p2=l2->first; if (!same_type(p1->type,p2->type)) return (0); l1=l1->rest; l2=l2->rest; } return (l1==l2); } case TTstruct: { struct Tstruct *ss=s, *ts=t; structlink *l1, *l2; if (tg->tag!=TTstruct) return (0); if (ss->name!=NULL && ts->name!=NULL && strcmp(ss->name->name,ts->name->name)==0) return (1); l1=ss->fields; l2=ts->fields; while (l1!=NULL && l2!=NULL) { struct Sfixeddecl *f1=l1->field, *f2=l2->field; if (!same_type(f1->type, f2->type)) return (0); l1=l1->rest; l2=l2->rest; } return (l1==l2); } default: return (s==t); } } Atype *make_pointerto(Atype *t) { struct Tpointerto *r; if (t==t_void) return (t_voidstar); if (t==t_char) return (t_charstar); r=malloc(sizeof(struct Tpointerto)); r->tag=TTpointerto; r->what=t; return (r); } int sizeoftype(Atype *t) { struct Tgeneric *g=t; if (t==NULL) return (0); switch (g->tag) { case TTsimple: { struct Tsimple *s=t; switch (s->type) { case TYvoid: return (0); case TYint: return (4); case TYfloat: return (4); case TYchar: return (1); default : semantic_error("size of unknown basic type", NULL, 0); return (0); } } case TTpointerto: return (4); case TTarrayof: { struct Tarrayof *s=t; return (s->size); } case TTfunction: semantic_error("size of function", t, 0); return (0); case TTstruct: { struct Tstruct *s=t; return (s->size); } default: semantic_error("size of unknown type", t, 0); return (0); } } Atype *MakeBasicType(Syntax *t) { struct Sgeneric *g=t; if (g==NULL) return t_void; switch (g->tag) { case TTsimpletype: { struct Ssimpletype *s=t; switch (s->type) { case TYvoid: return (t_void); case TYint: return (t_int); case TYchar: return (t_char); case TYfloat: return (t_float); } return (NULL); } case TTstructtype: { struct Sstructtype *s=t; struct Sstatementlist *p; struct Tstruct *r; structlink *head=NULL, *last=NULL, *link; int totalsize=0; SymbolDescription *structsym=NULL; if (s->name!=NULL) { char newname[110]; DeclarationRecord *dr; strcpy(newname,"$$"); strcat(newname,s->name->name); structsym=lookup_symbol(newname); dr=structsym->decls; if (dr!=NULL) { struct Tgeneric *oldtype=dr->type; if (oldtype->tag==TTstruct) return (oldtype); } } r=malloc(sizeof(struct Tstruct)); r->tag=TTstruct; r->name=structsym; p=s->fielddecs; while (p!=NULL) { struct Sfixeddecl *d=p->first; link=malloc(sizeof(structlink)); link->field=d; link->position=totalsize; link->rest=NULL; totalsize+=sizeoftype(d->type); if (head==NULL) head=link; else last->rest=link; last=link; p=p->rest; } r->fields=head; r->size=totalsize; return (r); } default: { fprintf(errfile,"MakeBasicType can't handle "); print_syntax(errfile,t); return (NULL); } } return (NULL); } void ProcessDeclaration(Syntax *t, Atype *basic, Atype **type, SymbolDescription **var) { struct Sgeneric *g=t; if (g==NULL) return; switch (g->tag) { case TTdeclareitemvar: { struct Sdeclareitemvar *s=t; *var=s->variable; *type=basic; return; } case TTdeclareitemptr: { struct Sdeclareitemptr *s=t; ProcessDeclaration(s->towhat,make_pointerto(basic),type,var); return; } case TTdeclareitemarray: { struct Sdeclareitemarray *s=t; struct Tarrayof *basetype=malloc(sizeof(struct Tarrayof)); basetype->tag=TTarrayof; basetype->numels=s->numelements; if (s->numelements<0) basetype->size=0; else basetype->size=s->numelements*sizeoftype(basic); basetype->what=basic; ProcessDeclaration(s->ofwhat,basetype,type,var); return; } case TTdeclareitemfunction: { struct Sdeclareitemfunction *s=t; struct Tfunction *basetype=malloc(sizeof(struct Tfunction)); basetype->tag=TTfunction; basetype->returns=basic; basetype->params=s->parameters; basetype->defined=0; ProcessDeclaration(s->name,basetype,type,var); return; } default: { syntax_error("Bad Declaration\n"); } } } void undo_declaration(Syntax *t); void do_declaration(Syntax *t, int level) { struct Sgeneric *g=t; if (g==NULL) return; switch (g->tag) { case TTstatementlist: { struct Sstatementlist *s=t; while (s!=NULL) { do_declaration(s->first,level); s=s->rest; } return; } case TTfixeddecl: { struct Sfixeddecl *s=t; declare(s->var,s->type,level,s->linenum); return; } case TTdeclareparamlist: { struct Sdeclareparamlist *s=t; while (s!=NULL) { do_declaration(s->first,level); s=s->rest; } return; } case TTfixedparam: { struct Sfixedparam *s=t; declare(s->var,s->type,level,s->linenum); return; } case TTfixedfuncdef: { struct Sfixedfuncdef *s=t; SymbolDescription *sd=s->name; DeclarationRecord *dr=sd->decls; struct Tfunction *declaredtype; int ok=0; if (dr==NULL) ok=2; else if (dr->level!=level) ok=2; else if (same_type(dr->type,s->type)) { declaredtype=dr->type; if (s->body==NULL) ok=1; else if (declaredtype->defined==0) ok=1; } if (ok==0) { semantic_error("incompatible redeclaration of function",NULL,s->linenum); return; } if (ok==2) { declare(sd,s->type,level,s->linenum); dr=sd->decls; declaredtype=dr->type; } if (ok && s->body!=NULL) { declaredtype->defined=1; do_declaration(declaredtype->params,level+1); return_type=declaredtype->returns; semantic_check(s->body,level); undo_declaration(declaredtype->params); return; } return; } case TTfixedstructdef: { struct Sfixedstructdef *s=t; declare(s->name,s->type,level,s->linenum); return; } default: printf("\nDo declaration can't handle this:\n"); print_tagged_tree(stdout,t); } } void undo_declaration(Syntax *t) { struct Sgeneric *g=t; if (g==NULL) return; switch (g->tag) { case TTstatementlist: { struct Sstatementlist *s=t; while (s!=NULL) { undo_declaration(s->first); s=s->rest; } return; } case TTfixeddecl: { struct Sfixeddecl *s=t; undeclare(s->var); return; } case TTdeclareparamlist: { struct Sdeclareparamlist *s=t; while (s!=NULL) { undo_declaration(s->first); s=s->rest; } return; } case TTfixedparam: { struct Sfixedparam *s=t; undeclare(s->var); return; } case TTfixedfuncdef: { struct Sfixedfuncdef *s=t; SymbolDescription *sd=s->name; DeclarationRecord *dr=sd->decls; struct Tfunction *declaredtype; undeclare(sd); return; } case TTfixedstructdef: { struct Sfixedstructdef *s=t; undeclare(s->name); return; } default: printf("\nUndo declaration can't handle this:\n"); print_tagged_tree(stdout,t); } } void coerce(Syntax **thing, Atype *fromtype, Atype *totype) { struct Scoerce *s; if (fromtype==totype) return; s=malloc(sizeof(struct Scoerce)); s->tag=TTcoerce; s->fromtype=fromtype; s->totype=totype; s->operand=*thing; *thing=s; } Atype *gently_coerce(Syntax **thing, Atype *fromtype, Atype *totype, int linenum) { if (fromtype==totype) return (totype); coerce(thing,fromtype,totype); if (fromtype==t_char && totype==t_int) return (totype); semantic_error("impossible coercion", *thing, linenum); return (fromtype); } Atype *usual_unary_conversion(Syntax *t, Atype *basetype, int linenum) { if (basetype==t_char) return (t_int); return (basetype); } Atype *typecheck_assignment(Syntax **t, Atype *ltype, Atype *rtype, int linenum) { if (same_type(ltype,rtype)) return (rtype); if (is_pointer(ltype) && is_pointer(rtype)) { if (ltype==t_voidstar || rtype==t_voidstar || same_type(ltype,rtype)) return (rtype); semantic_error("incompatible pointer types for assignment",*t,linenum); return (rtype); } if ((ltype==t_int || ltype==t_char || ltype==t_float) && (rtype==t_int || rtype==t_char || rtype==t_float)) { coerce(t, rtype, ltype); return (ltype); } semantic_error("incompatible types for assignment", *t, linenum); return (rtype); } Atype *typecheck_expr(Syntax *t, int linenum); Atype *typecheck_lvalue(Syntax *t, int linenum) { struct Sgeneric *g=t; if (g==NULL) { semantic_error("Error found during parsing", NULL, linenum); return (t_void); } switch (g->tag) { case TTbad: { semantic_error("Error found during parsing", NULL, linenum); return (t_void); } case TTidentifier: { struct Sidentifier *s=t; SymbolDescription *sd=s->symbol; DeclarationRecord *dr=sd->decls; if (dr==NULL) { semantic_error("Undeclared indentifier used", t, linenum); return (t_int); } return (dr->type); } case TTarrayaccess: { struct Sarrayaccess *s=t; struct Tarrayof *arraytype; Atype *indextype, *resulttype; struct Sbinaryexpr *extra; struct Sinteger *scale; int elemsize; arraytype=typecheck_expr(s->array, linenum); elemsize=sizeoftype(arraytype->what); indextype=typecheck_expr(s->index, linenum); if (arraytype->tag!=TTarrayof) { semantic_error("Non-array accessed as array", t, linenum); resulttype=t_void; } else resulttype=arraytype->what; indextype=gently_coerce(&(s->index), indextype, t_int, linenum); if (indextype!=t_int) semantic_error("Array index must be int", t, linenum); if (elemsize!=1) { scale=malloc(sizeof(struct Sinteger)); extra=malloc(sizeof(struct Sbinaryexpr)); scale->tag=TTinteger; scale->value=elemsize; extra->tag=TTbinaryexpr; extra->left=s->index; extra->right=scale; extra->operator=OPstar; s->index=extra; } return (resulttype); } case TTfieldselect: { return (typecheck_expr(t, linenum)); } case TTunaryexpr: { struct Sunaryexpr *s=t; Atype *basetype=typecheck_expr(s->operand, linenum); if (s->operator==OPstar) { struct Tpointerto *p=basetype; if (p->tag!=TTpointerto) { semantic_error("* applied to non-pointer", t, linenum); return (basetype); } if (p->what==t_void) semantic_error("dereferencing (void *) pointer", t, linenum); return (p->what); } semantic_error("This is not an Lvalue", t, linenum); return (basetype); } default: semantic_error("This is not an Lvalue", t, linenum); return (t_void); } } SymbolKind float_version_of(SymbolKind s) { switch (s) { case OPplus: return (OPFplus); case OPminus: return (OPFminus); case OPstar: return (OPFstar); case OPdivide: return (OPFdivide); case OPplusequal: return (OPFplusequal); case OPminusequal: return (OPFminusequal); case OPstarequal: return (OPFstarequal); case OPdivideequal: return (OPFdivideequal); case OPequalequal: return (OPFequalequal); case OPnotequal: return (OPFnotequal); case OPless: return (OPFless); case OPgreater: return (OPFgreater); case OPlessequal: return (OPFlessequal); case OPgreaterequal: return (OPFgreaterequal); default: return (SKunknown); } } Atype *typecheck_expr(Syntax *t, int linenum) { struct Sgeneric *g=t; if (g==NULL) { semantic_error("Error found during parsing", NULL, linenum); return (t_void); } switch (g->tag) { case TTbad: { semantic_error("Error found during parsing", NULL, linenum); return (t_void); } case TTnull: return (t_voidstar); case TTinteger: return (t_int); case TTfloat: return (t_float); case TTstring: return (t_charstar); case TTcoerce: { struct Scoerce *s=t; return (s->totype); } case TTidentifier: { struct Sidentifier *s=t; SymbolDescription *sd; DeclarationRecord *dr; sd=s->symbol; dr=sd->decls; if (dr==NULL) { semantic_error("Undeclared indentifier used", t, linenum); return (t_int); } return (dr->type); } case TTarrayaccess: { struct Sarrayaccess *s=t; struct Tarrayof *arraytype; Atype *indextype, *resulttype; struct Sbinaryexpr *extra; struct Sinteger *scale; int elemsize; arraytype=typecheck_expr(s->array, linenum); elemsize=sizeoftype(arraytype->what); indextype=typecheck_expr(s->index, linenum); if (arraytype->tag!=TTarrayof) { semantic_error("Non-array accessed as array", t, linenum); resulttype=t_void; } else resulttype=arraytype->what; indextype=gently_coerce(&(s->index), indextype, t_int, linenum); if (indextype!=t_int) semantic_error("Array index must be int", t, linenum); if (elemsize!=1) { scale=malloc(sizeof(struct Sinteger)); extra=malloc(sizeof(struct Sbinaryexpr)); scale->tag=TTinteger; scale->value=elemsize; extra->tag=TTbinaryexpr; extra->left=s->index; extra->right=scale; extra->operator=OPstar; s->index=extra; } return (resulttype); } case TTfunctioncall: { struct Sfunctioncall *s=t; struct Tfunction *fntype; struct Sdeclareparamlist *formals; struct Sexpressionlist *actuals; fntype=typecheck_expr(s->function, linenum); if (fntype->tag!=TTfunction) { semantic_error("This is not a function that you are calling",t,linenum); return (t_void); } formals=fntype->params; actuals=s->arguments; while (formals!=NULL && actuals!=NULL) { struct Sfixedparam *formal=formals->first; Atype *formaltype=formal->type; Atype *actualtype; actualtype=typecheck_expr(actuals->first, linenum); typecheck_assignment(&(actuals->first), formaltype, actualtype, linenum); formals=formals->rest; actuals=actuals->rest; } if (formals!=NULL || actuals!=NULL) semantic_error("wrong number of arguments in call",t,linenum); return (fntype->returns); } case TTbinaryexpr: { struct Sbinaryexpr *s=t; Atype *ltype, *rtype; SymbolKind op=s->operator; rtype=typecheck_expr(s->right, linenum); if (op==OPequal) { ltype=typecheck_lvalue(s->left, linenum); return typecheck_assignment(&(s->right), ltype, rtype, linenum); } if (op==OPplusequal || op==OPminusequal || op==OPstarequal || op==OPdivideequal || op==OPmodequal) { if (rtype!=t_int && rtype!=t_char && rtype!=t_float) { semantic_error("numeric type required for this operation",t,linenum); return (rtype); } if (rtype==t_float) { op=float_version_of(op); if (op==SKunknown) semantic_error("This is not a floating point operation", t, linenum); s->operator=op; } ltype=typecheck_lvalue(s->left, linenum); return typecheck_assignment(&(s->right), ltype, rtype, linenum); } ltype=typecheck_expr(s->left, linenum); ltype=usual_unary_conversion(&(s->left), ltype, linenum); rtype=usual_unary_conversion(&(s->right), rtype, linenum); if (ltype==t_int && rtype==t_float) { coerce(&(s->left),t_int,t_float); ltype=t_float; } if (ltype==t_float && rtype==t_int) { coerce(&(s->right),t_int,t_float); rtype=t_float; } if (rtype==t_float) { op=float_version_of(op); if (op==SKunknown) semantic_error("This is not a floating point operation", t, linenum); s->operator=op; } if (op==OPplus || op==OPminus || op==OPstar || op==OPdivide || op==OPmod || op==OPFplus || op==OPFminus || op==OPFstar || op==OPFdivide) { if (ltype==t_int && rtype==t_int || ltype==t_float && rtype==t_float) return(ltype); semantic_error("int or float required for arithmetic",t,linenum); return (t_int); } if (ltype==t_int && rtype==t_int || ltype==t_float && rtype==t_float || is_pointer(ltype) && is_pointer(rtype)) return (t_int); semantic_error("illegal mix of types",t,linenum); return (t_int); } case TTunaryexpr: { struct Sunaryexpr *s=t; Atype *basetype, *resulttype; if (s->operator==OPaddress) { basetype=typecheck_lvalue(s->operand, linenum); return (make_pointerto(basetype)); } basetype=typecheck_expr(s->operand, linenum); resulttype=usual_unary_conversion(&(s->operand), basetype, linenum); if (s->operator==OPstar) { struct Tpointerto *p=resulttype; if (p->tag!=TTpointerto) { semantic_error("* applied to non-pointer", t, linenum); return (resulttype); } if (p->what==t_void) semantic_error("dereferencing (void *) pointer", t, linenum); return (p->what); } if (s->operator==OPplus || s->operator==OPminus || s->operator==OPnot) { if (resulttype!=t_int && resulttype!=t_float) semantic_error("int or float required for unary operation", t, linenum); if (resulttype==t_float) s->operator=float_version_of(s->operator); return (resulttype); } semantic_error("imporper unary operation", t, linenum); return (resulttype); } case TTfieldselect: { struct Sfieldselect *s=t; struct Tstruct *ltype=typecheck_expr(s->structure, linenum); structlink *fields; if (ltype->tag!=TTstruct) { semantic_error("non-struct used in field selection", t, linenum); return (t_void); } fields=ltype->fields; while (fields!=NULL) { struct Sfixeddecl *fd=fields->field; if (fd->var==s->field) return (fd->type); fields=fields->rest; } semantic_error("structure has no field of this name", t, linenum); return (t_void); } default: printf("\ntypecheck_expression can't handle this:\n"); printf("%d %d\n",TTfieldselect,g->tag); print_tagged_tree(stdout,t); } } void semantic_check(Syntax *t, int level) { struct Sgeneric *g=t; if (g==NULL) { semantic_error("Error found during parsing", NULL, 0); return; } switch (g->tag) { case TTblock: { struct Sblock *b=t; struct Sstatementlist *decls=b->declarations, *stmts=b->statements; while (decls!=NULL) { do_declaration(decls->first, level+1); decls=decls->rest; } while (stmts!=NULL) { semantic_check(stmts->first, level+1); stmts=stmts->rest; } decls=b->declarations; while (decls!=NULL) { undo_declaration(decls->first); decls=decls->rest; } return; } case TTreturnstatement: { struct Sreturnstatement *s=t; Atype *valtype; if (return_type==t_void && s->value==NULL) return; if (return_type==t_void) { semantic_error("Can't return value in void function",t,s->linenum); return; } if (s->value==NULL) { semantic_error("Must return a value",t,s->linenum); return; } valtype=typecheck_expr(s->value, s->linenum); typecheck_assignment(&(s->value),return_type,valtype,s->linenum); return; } case TTifstatement: { struct Sifstatement *s=t; Atype *cond=typecheck_expr(s->condition, s->linenum); if (cond!=t_int) semantic_error("condition must be an int", t, s->linenum); semantic_check(s->iftrue, level); semantic_check(s->iffalse, level); return; } case TTwhilestatement: { struct Swhilestatement *s=t; Atype *cond=typecheck_expr(s->condition, s->linenum); if (cond!=t_int) semantic_error("condition must be an int", t, s->linenum); semantic_check(s->body, level); return; } case TTexprstatement: { struct Sexprstatement *s=t; typecheck_expr(s->expression, s->linenum); return; } default: fprintf(stderr,"Can't semantic-check "); pt(stderr,t,0); fprintf(stderr,"\n"); return; } } void typecheck(Syntax *t) { do_declaration(t,0); }