diff --git a/common.c b/common.c index a9542bd..80fe859 100644 --- a/common.c +++ b/common.c @@ -19,36 +19,36 @@ TOKENS ══════════════════════════════════════════════════════════ */ typedef enum { - /* literals */ - TK_NUM, TK_STR, TK_ID, - /* types */ - TK_UINT8, TK_UINT16, TK_UINT32, TK_UINT64, TK_VOID, - TK_INT8, TK_INT16, TK_INT32, TK_INT64, - /* keywords */ - TK_IF, TK_ELSE, TK_WHILE, TK_FOR, - TK_SWITCH, TK_CASE, TK_DEFAULT, - TK_BREAK, TK_CONTINUE, TK_RETURN, - /* operators (multi-char first) */ - TK_EQ, TK_NEQ, TK_LEQ, TK_GEQ, TK_AND, TK_OR, - TK_SHL, TK_SHR, TK_INC, TK_DEC, - TK_ADDEQ, TK_SUBEQ, TK_MULEQ, TK_DIVEQ, TK_MODEQ, - TK_ANDEQ, TK_OREQ, TK_XOREQ, TK_SHLEQ, TK_SHREQ, - /* single-char operators / punctuation */ - TK_PLUS, TK_MINUS, TK_STAR, TK_SLASH, TK_MOD, - TK_AMP, TK_PIPE, TK_CARET, TK_TILDE, TK_BANG, - TK_LT, TK_GT, TK_ASSIGN, - TK_LPAREN, TK_RPAREN, TK_LBRACE, TK_RBRACE, - TK_LBRACK, TK_RBRACK, - TK_SEMI, TK_COMMA, TK_COLON, TK_QUESTION, - TK_EOF + /* literals */ + TK_NUM, TK_STR, TK_ID, + /* types */ + TK_UINT8, TK_UINT16, TK_UINT32, TK_UINT64, TK_VOID, + TK_INT8, TK_INT16, TK_INT32, TK_INT64, + /* keywords */ + TK_IF, TK_ELSE, TK_WHILE, TK_FOR, + TK_SWITCH, TK_CASE, TK_DEFAULT, + TK_BREAK, TK_CONTINUE, TK_RETURN, + /* operators (multi-char first) */ + TK_EQ, TK_NEQ, TK_LEQ, TK_GEQ, TK_AND, TK_OR, + TK_SHL, TK_SHR, TK_INC, TK_DEC, + TK_ADDEQ, TK_SUBEQ, TK_MULEQ, TK_DIVEQ, TK_MODEQ, + TK_ANDEQ, TK_OREQ, TK_XOREQ, TK_SHLEQ, TK_SHREQ, + /* single-char operators / punctuation */ + TK_PLUS, TK_MINUS, TK_STAR, TK_SLASH, TK_MOD, + TK_AMP, TK_PIPE, TK_CARET, TK_TILDE, TK_BANG, + TK_LT, TK_GT, TK_ASSIGN, + TK_LPAREN, TK_RPAREN, TK_LBRACE, TK_RBRACE, + TK_LBRACK, TK_RBRACK, + TK_SEMI, TK_COMMA, TK_COLON, TK_QUESTION, + TK_EOF } TKind; typedef struct { - TKind kind; - char str[512]; /* identifier / string value — 512 to match str_val */ - int slen; /* FIX(bug2+3): explicit byte count for str, excl. terminator */ - long num; /* numeric value */ - int line; /* source line where token starts */ + TKind kind; + char str[512]; /* identifier / string value — 512 to match str_val */ + int slen; /* FIX(bug2+3): explicit byte count for str, excl. terminator */ + long num; /* numeric value */ + int line; /* source line where token starts */ } Token; /* ══════════════════════════════════════════════════════════ @@ -60,160 +60,160 @@ static int src_line = 1; /* current line number (1-based) */ static Token tok; /* current token */ static void die(const char *fmt, ...) { - fprintf(stderr, "line %d: ", src_line); - va_list ap; va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - fputc('\n', stderr); - exit(1); + fprintf(stderr, "line %d: ", src_line); + va_list ap; va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + fputc('\n', stderr); + exit(1); } static void skip_ws(void) { - for (;;) { - while (isspace((unsigned char)src[src_pos])) { - if (src[src_pos] == '\n') src_line++; - src_pos++; - } - if (src[src_pos]=='/' && src[src_pos+1]=='/') { - while (src[src_pos] && src[src_pos]!='\n') src_pos++; - } else if (src[src_pos]=='/' && src[src_pos+1]=='*') { - src_pos += 2; - while (src[src_pos] && !(src[src_pos-1]=='*' && src[src_pos]=='/')) { - if (src[src_pos] == '\n') src_line++; - src_pos++; - } - if (src[src_pos]) src_pos++; - } else break; + for (;;) { + while (isspace((unsigned char)src[src_pos])) { + if (src[src_pos] == '\n') src_line++; + src_pos++; } + if (src[src_pos]=='/' && src[src_pos+1]=='/') { + while (src[src_pos] && src[src_pos]!='\n') src_pos++; + } else if (src[src_pos]=='/' && src[src_pos+1]=='*') { + src_pos += 2; + while (src[src_pos] && !(src[src_pos-1]=='*' && src[src_pos]=='/')) { + if (src[src_pos] == '\n') src_line++; + src_pos++; + } + if (src[src_pos]) src_pos++; + } else break; + } } static struct { const char *kw; TKind tk; } kw_table[] = { - {"if",TK_IF},{"else",TK_ELSE},{"while",TK_WHILE},{"for",TK_FOR}, - {"switch",TK_SWITCH},{"case",TK_CASE},{"default",TK_DEFAULT}, - {"break",TK_BREAK},{"continue",TK_CONTINUE},{"return",TK_RETURN}, - {"void",TK_VOID},{"uint8",TK_UINT8},{"uint16",TK_UINT16}, - {"uint32",TK_UINT32},{"uint64",TK_UINT64}, - {"int8",TK_INT8},{"int16",TK_INT16},{"int32",TK_INT32}, - {"int64", TK_INT64},{NULL,TK_EOF} + {"if",TK_IF},{"else",TK_ELSE},{"while",TK_WHILE},{"for",TK_FOR}, + {"switch",TK_SWITCH},{"case",TK_CASE},{"default",TK_DEFAULT}, + {"break",TK_BREAK},{"continue",TK_CONTINUE},{"return",TK_RETURN}, + {"void",TK_VOID},{"uint8",TK_UINT8},{"uint16",TK_UINT16}, + {"uint32",TK_UINT32},{"uint64",TK_UINT64}, + {"int8",TK_INT8},{"int16",TK_INT16},{"int32",TK_INT32}, + {"int64", TK_INT64},{NULL,TK_EOF} }; static void next(void) { - skip_ws(); - tok.line = src_line; - char c = src[src_pos]; - if (!c) { tok.kind = TK_EOF; return; } + skip_ws(); + tok.line = src_line; + char c = src[src_pos]; + if (!c) { tok.kind = TK_EOF; return; } - /* number */ - if (isdigit((unsigned char)c)) { - char *end; - tok.num = (long)strtoul(src+src_pos, &end, 0); - src_pos = (int)(end - src); - tok.kind = TK_NUM; return; - } + /* number */ + if (isdigit((unsigned char)c)) { + char *end; + tok.num = (long)strtoul(src+src_pos, &end, 0); + src_pos = (int)(end - src); + tok.kind = TK_NUM; return; + } - /* string literal */ - if (c == '"') { - src_pos++; int i=0; - while (src[src_pos] && src[src_pos]!='"') { - /* FIX(bug3): bounds check before writing into tok.str */ - if (i >= 511) die("string literal too long"); - if (src[src_pos]=='\\') { - src_pos++; - switch(src[src_pos]) { - case 'n': tok.str[i++]='\n'; break; - case 't': tok.str[i++]='\t'; break; - case 'r': tok.str[i++]='\r'; break; - case '0': tok.str[i++]='\0'; break; - default: tok.str[i++]=src[src_pos]; break; - } - } else tok.str[i++]=src[src_pos]; - src_pos++; - } - if (src[src_pos]=='"') src_pos++; - tok.str[i]=0; - tok.slen=i; /* FIX(bug2): record true byte count */ - tok.kind=TK_STR; - return; + /* string literal */ + if (c == '"') { + src_pos++; int i=0; + while (src[src_pos] && src[src_pos]!='"') { + /* FIX(bug3): bounds check before writing into tok.str */ + if (i >= 511) die("string literal too long"); + if (src[src_pos]=='\\') { + src_pos++; + switch(src[src_pos]) { + case 'n': tok.str[i++]='\n'; break; + case 't': tok.str[i++]='\t'; break; + case 'r': tok.str[i++]='\r'; break; + case '0': tok.str[i++]='\0'; break; + default: tok.str[i++]=src[src_pos]; break; + } + } else tok.str[i++]=src[src_pos]; + src_pos++; } + if (src[src_pos]=='"') src_pos++; + tok.str[i]=0; + tok.slen=i; /* FIX(bug2): record true byte count */ + tok.kind=TK_STR; + return; + } - /* identifier / keyword */ - if (isalpha((unsigned char)c) || c=='_') { - int i=0; - while (isalnum((unsigned char)src[src_pos]) || src[src_pos]=='_') { - /* FIX(bug3): bounds check for identifiers too */ - if (i >= 511) die("identifier too long"); - tok.str[i++]=src[src_pos++]; - } - tok.str[i]=0; - tok.slen=i; - tok.kind=TK_ID; - for (int k=0; kw_table[k].kw; k++) - if (!strcmp(tok.str, kw_table[k].kw)) { tok.kind=kw_table[k].tk; return; } - return; + /* identifier / keyword */ + if (isalpha((unsigned char)c) || c=='_') { + int i=0; + while (isalnum((unsigned char)src[src_pos]) || src[src_pos]=='_') { + /* FIX(bug3): bounds check for identifiers too */ + if (i >= 511) die("identifier too long"); + tok.str[i++]=src[src_pos++]; } + tok.str[i]=0; + tok.slen=i; + tok.kind=TK_ID; + for (int k=0; kw_table[k].kw; k++) + if (!strcmp(tok.str, kw_table[k].kw)) { tok.kind=kw_table[k].tk; return; } + return; + } - /* multi/single char operators */ - src_pos++; - #define PEEK src[src_pos] - #define EAT src_pos++ - switch(c) { - case '+': if(PEEK=='+'){ EAT; tok.kind=TK_INC; } - else if(PEEK=='='){ EAT; tok.kind=TK_ADDEQ; } - else tok.kind=TK_PLUS; break; - case '-': if(PEEK=='-'){ EAT; tok.kind=TK_DEC; } - else if(PEEK=='='){ EAT; tok.kind=TK_SUBEQ; } - else tok.kind=TK_MINUS; break; - case '*': if(PEEK=='='){ EAT; tok.kind=TK_MULEQ; } else tok.kind=TK_STAR; break; - case '/': if(PEEK=='='){ EAT; tok.kind=TK_DIVEQ; } else tok.kind=TK_SLASH; break; - case '%': if(PEEK=='='){ EAT; tok.kind=TK_MODEQ; } else tok.kind=TK_MOD; break; - case '&': if(PEEK=='&'){ EAT; tok.kind=TK_AND; } - else if(PEEK=='='){ EAT; tok.kind=TK_ANDEQ; } - else tok.kind=TK_AMP; break; - case '|': if(PEEK=='|'){ EAT; tok.kind=TK_OR; } - else if(PEEK=='='){ EAT; tok.kind=TK_OREQ; } - else tok.kind=TK_PIPE; break; - case '^': if(PEEK=='='){ EAT; tok.kind=TK_XOREQ; } else tok.kind=TK_CARET; break; - case '<': if(PEEK=='<'){ EAT; if(PEEK=='='){ EAT; tok.kind=TK_SHLEQ; } else tok.kind=TK_SHL; } - else if(PEEK=='='){ EAT; tok.kind=TK_LEQ; } else tok.kind=TK_LT; break; - case '>': if(PEEK=='>'){ EAT; if(PEEK=='='){ EAT; tok.kind=TK_SHREQ; } else tok.kind=TK_SHR; } - else if(PEEK=='='){ EAT; tok.kind=TK_GEQ; } else tok.kind=TK_GT; break; - case '=': if(PEEK=='='){ EAT; tok.kind=TK_EQ; } else tok.kind=TK_ASSIGN; break; - case '!': if(PEEK=='='){ EAT; tok.kind=TK_NEQ; } else tok.kind=TK_BANG; break; - case '~': tok.kind=TK_TILDE; break; - case '(': tok.kind=TK_LPAREN; break; - case ')': tok.kind=TK_RPAREN; break; - case '{': tok.kind=TK_LBRACE; break; - case '}': tok.kind=TK_RBRACE; break; - case '[': tok.kind=TK_LBRACK; break; - case ']': tok.kind=TK_RBRACK; break; - case ';': tok.kind=TK_SEMI; break; - case ',': tok.kind=TK_COMMA; break; - case ':': tok.kind=TK_COLON; break; - case '?': tok.kind=TK_QUESTION;break; - default: die("Unknown char '%c'", c); - } - #undef PEEK - #undef EAT + /* multi/single char operators */ + src_pos++; +#define PEEK src[src_pos] +#define EAT src_pos++ + switch(c) { + case '+': if(PEEK=='+'){ EAT; tok.kind=TK_INC; } + else if(PEEK=='='){ EAT; tok.kind=TK_ADDEQ; } + else tok.kind=TK_PLUS; break; + case '-': if(PEEK=='-'){ EAT; tok.kind=TK_DEC; } + else if(PEEK=='='){ EAT; tok.kind=TK_SUBEQ; } + else tok.kind=TK_MINUS; break; + case '*': if(PEEK=='='){ EAT; tok.kind=TK_MULEQ; } else tok.kind=TK_STAR; break; + case '/': if(PEEK=='='){ EAT; tok.kind=TK_DIVEQ; } else tok.kind=TK_SLASH; break; + case '%': if(PEEK=='='){ EAT; tok.kind=TK_MODEQ; } else tok.kind=TK_MOD; break; + case '&': if(PEEK=='&'){ EAT; tok.kind=TK_AND; } + else if(PEEK=='='){ EAT; tok.kind=TK_ANDEQ; } + else tok.kind=TK_AMP; break; + case '|': if(PEEK=='|'){ EAT; tok.kind=TK_OR; } + else if(PEEK=='='){ EAT; tok.kind=TK_OREQ; } + else tok.kind=TK_PIPE; break; + case '^': if(PEEK=='='){ EAT; tok.kind=TK_XOREQ; } else tok.kind=TK_CARET; break; + case '<': if(PEEK=='<'){ EAT; if(PEEK=='='){ EAT; tok.kind=TK_SHLEQ; } else tok.kind=TK_SHL; } + else if(PEEK=='='){ EAT; tok.kind=TK_LEQ; } else tok.kind=TK_LT; break; + case '>': if(PEEK=='>'){ EAT; if(PEEK=='='){ EAT; tok.kind=TK_SHREQ; } else tok.kind=TK_SHR; } + else if(PEEK=='='){ EAT; tok.kind=TK_GEQ; } else tok.kind=TK_GT; break; + case '=': if(PEEK=='='){ EAT; tok.kind=TK_EQ; } else tok.kind=TK_ASSIGN; break; + case '!': if(PEEK=='='){ EAT; tok.kind=TK_NEQ; } else tok.kind=TK_BANG; break; + case '~': tok.kind=TK_TILDE; break; + case '(': tok.kind=TK_LPAREN; break; + case ')': tok.kind=TK_RPAREN; break; + case '{': tok.kind=TK_LBRACE; break; + case '}': tok.kind=TK_RBRACE; break; + case '[': tok.kind=TK_LBRACK; break; + case ']': tok.kind=TK_RBRACK; break; + case ';': tok.kind=TK_SEMI; break; + case ',': tok.kind=TK_COMMA; break; + case ':': tok.kind=TK_COLON; break; + case '?': tok.kind=TK_QUESTION;break; + default: die("Unknown char '%c'", c); + } +#undef PEEK +#undef EAT } static void expect(TKind k) { - if (tok.kind != k) { - fprintf(stderr, "line %d: syntax error near '%s'\n", tok.line, tok.str); - exit(1); - } - next(); + if (tok.kind != k) { + fprintf(stderr, "line %d: syntax error near '%s'\n", tok.line, tok.str); + exit(1); + } + next(); } static int accept(TKind k) { - if (tok.kind == k) { next(); return 1; } - return 0; + if (tok.kind == k) { next(); return 1; } + return 0; } static int is_type(void) { - return tok.kind==TK_UINT8||tok.kind==TK_UINT16|| - tok.kind==TK_UINT32||tok.kind==TK_UINT64||tok.kind==TK_VOID|| - tok.kind==TK_INT8||tok.kind==TK_INT16||tok.kind==TK_INT32|| - tok.kind==TK_INT64; + return tok.kind==TK_UINT8||tok.kind==TK_UINT16|| + tok.kind==TK_UINT32||tok.kind==TK_UINT64||tok.kind==TK_VOID|| + tok.kind==TK_INT8||tok.kind==TK_INT16||tok.kind==TK_INT32|| + tok.kind==TK_INT64; } static int is_signed(TKind t) { - return t==TK_INT8||t==TK_INT16||t==TK_INT32||t==TK_INT64; + return t==TK_INT8||t==TK_INT16||t==TK_INT32||t==TK_INT64; } static int is_64bit(TKind t) { return t==TK_UINT64||t==TK_INT64; @@ -223,53 +223,53 @@ static int is_64bit(TKind t) { AST NODES ══════════════════════════════════════════════════════════ */ typedef enum { - N_PROG, N_FUNC, N_FDECL, N_GVAR, N_GARR, - N_BLK, N_LVAR, N_LARR, N_ES, N_RET, N_BRK, N_CONT, - N_IF, N_WHILE, N_FOR, N_SW, N_CASE, N_DEF, - N_NUM, N_STR, N_ID, - N_BOPN, N_UOPN, N_ASGN, N_TERN, - N_CALL, N_IDX, N_ADDR, N_DEREF, N_CAST, - N_POSTINC, N_POSTDEC, N_PREINC, N_PREDEC, - N_PARAM + N_PROG, N_FUNC, N_FDECL, N_GVAR, N_GARR, + N_BLK, N_LVAR, N_LARR, N_ES, N_RET, N_BRK, N_CONT, + N_IF, N_WHILE, N_FOR, N_SW, N_CASE, N_DEF, + N_NUM, N_STR, N_ID, + N_BOPN, N_UOPN, N_ASGN, N_TERN, + N_CALL, N_IDX, N_ADDR, N_DEREF, N_CAST, + N_POSTINC, N_POSTDEC, N_PREINC, N_PREDEC, + N_PARAM } NKind; typedef struct Node Node; struct Node { - NKind kind; - TKind op; /* operator token */ - long num; - char str[512]; /* FIX(bug3): was 256, now 512 to match str_val */ - int slen; /* FIX(bug2): explicit byte count for str literals */ - /* type */ - TKind tbase; /* TK_UINT8 … TK_VOID */ - int ptrs; /* pointer depth */ - /* children */ - Node *ch[4]; /* left/right/body/else */ - /* lists */ - Node **list; /* params, args, stmts, cases */ - int nlist; - int cap; + NKind kind; + TKind op; /* operator token */ + long num; + char str[512]; /* FIX(bug3): was 256, now 512 to match str_val */ + int slen; /* FIX(bug2): explicit byte count for str literals */ + /* type */ + TKind tbase; /* TK_UINT8 … TK_VOID */ + int ptrs; /* pointer depth */ + /* children */ + Node *ch[4]; /* left/right/body/else */ + /* lists */ + Node **list; /* params, args, stmts, cases */ + int nlist; + int cap; }; static Node *alloc_node(NKind k) { - Node *n = calloc(1, sizeof(Node)); - n->kind = k; return n; + Node *n = calloc(1, sizeof(Node)); + n->kind = k; return n; } static void list_push(Node *n, Node *child) { - if (n->nlist == n->cap) { - n->cap = n->cap ? n->cap*2 : 4; - n->list = realloc(n->list, n->cap * sizeof(Node*)); - } - n->list[n->nlist++] = child; + if (n->nlist == n->cap) { + n->cap = n->cap ? n->cap*2 : 4; + n->list = realloc(n->list, n->cap * sizeof(Node*)); + } + n->list[n->nlist++] = child; } /* ══════════════════════════════════════════════════════════ PARSER ══════════════════════════════════════════════════════════ */ static void parse_type(TKind *base, int *ptrs) { - *base = tok.kind; next(); - *ptrs = 0; - while (tok.kind==TK_STAR) { (*ptrs)++; next(); } + *base = tok.kind; next(); + *ptrs = 0; + while (tok.kind==TK_STAR) { (*ptrs)++; next(); } } static Node *expr(void); @@ -279,284 +279,284 @@ static Node *stmt(void); static Node *block(void); static Node *primary(void) { - Node *n; - if (tok.kind==TK_NUM) { - n=alloc_node(N_NUM); n->num=tok.num; next(); return n; - } - if (tok.kind==TK_STR) { - n=alloc_node(N_STR); - /* FIX(bug2): use memcpy + slen instead of strcpy so embedded nulls survive */ - memcpy(n->str, tok.str, tok.slen+1); - n->slen=tok.slen; - next(); return n; - } - if (tok.kind==TK_ID) { - n=alloc_node(N_ID); strcpy(n->str, tok.str); next(); return n; - } - if (tok.kind==TK_LPAREN) { - next(); n=expr(); expect(TK_RPAREN); return n; - } - die("expected expression"); - return NULL; + Node *n; + if (tok.kind==TK_NUM) { + n=alloc_node(N_NUM); n->num=tok.num; next(); return n; + } + if (tok.kind==TK_STR) { + n=alloc_node(N_STR); + /* FIX(bug2): use memcpy + slen instead of strcpy so embedded nulls survive */ + memcpy(n->str, tok.str, tok.slen+1); + n->slen=tok.slen; + next(); return n; + } + if (tok.kind==TK_ID) { + n=alloc_node(N_ID); strcpy(n->str, tok.str); next(); return n; + } + if (tok.kind==TK_LPAREN) { + next(); n=expr(); expect(TK_RPAREN); return n; + } + die("expected expression"); + return NULL; } static Node *postfix(void) { - Node *e = primary(), *t; - for(;;) { - if (tok.kind==TK_LPAREN) { - next(); t=alloc_node(N_CALL); t->ch[0]=e; - if (tok.kind!=TK_RPAREN) - for(;;) { - list_push(t, expr()); - if (!accept(TK_COMMA)) break; - } - expect(TK_RPAREN); e=t; - } else if (tok.kind==TK_LBRACK) { - next(); t=alloc_node(N_IDX); t->ch[0]=e; t->ch[1]=expr(); - expect(TK_RBRACK); e=t; - } else if (tok.kind==TK_INC) { - next(); t=alloc_node(N_POSTINC); t->ch[0]=e; e=t; - } else if (tok.kind==TK_DEC) { - next(); t=alloc_node(N_POSTDEC); t->ch[0]=e; e=t; - } else break; - } - return e; + Node *e = primary(), *t; + for(;;) { + if (tok.kind==TK_LPAREN) { + next(); t=alloc_node(N_CALL); t->ch[0]=e; + if (tok.kind!=TK_RPAREN) + for(;;) { + list_push(t, expr()); + if (!accept(TK_COMMA)) break; + } + expect(TK_RPAREN); e=t; + } else if (tok.kind==TK_LBRACK) { + next(); t=alloc_node(N_IDX); t->ch[0]=e; t->ch[1]=expr(); + expect(TK_RBRACK); e=t; + } else if (tok.kind==TK_INC) { + next(); t=alloc_node(N_POSTINC); t->ch[0]=e; e=t; + } else if (tok.kind==TK_DEC) { + next(); t=alloc_node(N_POSTDEC); t->ch[0]=e; e=t; + } else break; + } + return e; } static Node *unary(void) { - Node *t; - if (tok.kind==TK_MINUS||tok.kind==TK_BANG||tok.kind==TK_TILDE) { - TKind op=tok.kind; next(); - t=alloc_node(N_UOPN); t->op=op; t->ch[0]=unary(); return t; + Node *t; + if (tok.kind==TK_MINUS||tok.kind==TK_BANG||tok.kind==TK_TILDE) { + TKind op=tok.kind; next(); + t=alloc_node(N_UOPN); t->op=op; t->ch[0]=unary(); return t; + } + if (tok.kind==TK_AMP) { + next(); t=alloc_node(N_ADDR); t->ch[0]=unary(); return t; + } + if (tok.kind==TK_STAR) { + next(); t=alloc_node(N_DEREF); t->ch[0]=unary(); return t; + } + if (tok.kind==TK_INC) { + next(); t=alloc_node(N_PREINC); t->ch[0]=unary(); return t; + } + if (tok.kind==TK_DEC) { + next(); t=alloc_node(N_PREDEC); t->ch[0]=unary(); return t; + } + /* cast: (type) expr */ + if (tok.kind==TK_LPAREN && (src[src_pos]==' '||1)) { + int saved=src_pos; Token saved_tok=tok; int saved_line=src_line; + next(); + if (is_type()) { + TKind tb; int pt; + parse_type(&tb,&pt); + if (tok.kind==TK_RPAREN) { + next(); t=alloc_node(N_CAST); + t->tbase=tb; t->ptrs=pt; t->ch[0]=unary(); return t; + } } - if (tok.kind==TK_AMP) { - next(); t=alloc_node(N_ADDR); t->ch[0]=unary(); return t; - } - if (tok.kind==TK_STAR) { - next(); t=alloc_node(N_DEREF); t->ch[0]=unary(); return t; - } - if (tok.kind==TK_INC) { - next(); t=alloc_node(N_PREINC); t->ch[0]=unary(); return t; - } - if (tok.kind==TK_DEC) { - next(); t=alloc_node(N_PREDEC); t->ch[0]=unary(); return t; - } - /* cast: (type) expr */ - if (tok.kind==TK_LPAREN && (src[src_pos]==' '||1)) { - int saved=src_pos; Token saved_tok=tok; int saved_line=src_line; - next(); - if (is_type()) { - TKind tb; int pt; - parse_type(&tb,&pt); - if (tok.kind==TK_RPAREN) { - next(); t=alloc_node(N_CAST); - t->tbase=tb; t->ptrs=pt; t->ch[0]=unary(); return t; - } - } - src_pos=saved; tok=saved_tok; src_line=saved_line; - } - return postfix(); + src_pos=saved; tok=saved_tok; src_line=saved_line; + } + return postfix(); } -#define BINOP(name, next_fn, ...) \ -static Node *name(void) { \ - Node *l=next_fn(), *t; TKind ops[]={__VA_ARGS__, TK_EOF}; \ - for(;;) { \ - int found=0; \ - for(int i=0;ops[i]!=TK_EOF;i++) if(tok.kind==ops[i]){found=1;break;} \ - if(!found) break; \ - TKind op=tok.kind; next(); \ - t=alloc_node(N_BOPN); t->op=op; t->ch[0]=l; t->ch[1]=next_fn(); l=t; \ - } return l; \ -} +#define BINOP(name, next_fn, ...) \ + static Node *name(void) { \ + Node *l=next_fn(), *t; TKind ops[]={__VA_ARGS__, TK_EOF}; \ + for(;;) { \ + int found=0; \ + for(int i=0;ops[i]!=TK_EOF;i++) if(tok.kind==ops[i]){found=1;break;} \ + if(!found) break; \ + TKind op=tok.kind; next(); \ + t=alloc_node(N_BOPN); t->op=op; t->ch[0]=l; t->ch[1]=next_fn(); l=t; \ + } return l; \ + } BINOP(mul_expr, unary, TK_STAR, TK_SLASH, TK_MOD) -BINOP(add_expr, mul_expr, TK_PLUS, TK_MINUS) -BINOP(shf_expr, add_expr, TK_SHL, TK_SHR) -BINOP(cmp_expr, shf_expr, TK_LT, TK_LEQ, TK_GT, TK_GEQ) -BINOP(eq_expr, cmp_expr, TK_EQ, TK_NEQ) -BINOP(band_expr, eq_expr, TK_AMP) -BINOP(bxor_expr, band_expr,TK_CARET) -BINOP(bor_expr, bxor_expr,TK_PIPE) + BINOP(add_expr, mul_expr, TK_PLUS, TK_MINUS) + BINOP(shf_expr, add_expr, TK_SHL, TK_SHR) + BINOP(cmp_expr, shf_expr, TK_LT, TK_LEQ, TK_GT, TK_GEQ) + BINOP(eq_expr, cmp_expr, TK_EQ, TK_NEQ) + BINOP(band_expr, eq_expr, TK_AMP) + BINOP(bxor_expr, band_expr,TK_CARET) + BINOP(bor_expr, bxor_expr,TK_PIPE) -static Node *land_expr(void) { - Node *l=bor_expr(), *t; - while (tok.kind==TK_AND) { - next(); t=alloc_node(N_BOPN); t->op=TK_AND; - t->ch[0]=l; t->ch[1]=bor_expr(); l=t; - } return l; + static Node *land_expr(void) { + Node *l=bor_expr(), *t; + while (tok.kind==TK_AND) { + next(); t=alloc_node(N_BOPN); t->op=TK_AND; + t->ch[0]=l; t->ch[1]=bor_expr(); l=t; + } return l; } static Node *lor_expr(void) { - Node *l=land_expr(), *t; - while (tok.kind==TK_OR) { - next(); t=alloc_node(N_BOPN); t->op=TK_OR; - t->ch[0]=l; t->ch[1]=land_expr(); l=t; - } return l; + Node *l=land_expr(), *t; + while (tok.kind==TK_OR) { + next(); t=alloc_node(N_BOPN); t->op=TK_OR; + t->ch[0]=l; t->ch[1]=land_expr(); l=t; + } return l; } static Node *ternary(void); static Node *ternary(void) { - Node *c=lor_expr(), *t; - if (tok.kind==TK_QUESTION) { - next(); t=alloc_node(N_TERN); t->ch[0]=c; - t->ch[1]=expr(); expect(TK_COLON); t->ch[2]=ternary(); return t; - } - return c; + Node *c=lor_expr(), *t; + if (tok.kind==TK_QUESTION) { + next(); t=alloc_node(N_TERN); t->ch[0]=c; + t->ch[1]=expr(); expect(TK_COLON); t->ch[2]=ternary(); return t; + } + return c; } static TKind asgn_ops[] = { - TK_ASSIGN, TK_ADDEQ, TK_SUBEQ, TK_MULEQ, TK_DIVEQ, TK_MODEQ, - TK_ANDEQ, TK_OREQ, TK_XOREQ, TK_SHLEQ, TK_SHREQ, TK_EOF + TK_ASSIGN, TK_ADDEQ, TK_SUBEQ, TK_MULEQ, TK_DIVEQ, TK_MODEQ, + TK_ANDEQ, TK_OREQ, TK_XOREQ, TK_SHLEQ, TK_SHREQ, TK_EOF }; static Node *expr(void) { - Node *l=ternary(), *t; - for(int i=0; asgn_ops[i]!=TK_EOF; i++) - if (tok.kind==asgn_ops[i]) { - TKind op=tok.kind; next(); - t=alloc_node(N_ASGN); t->op=op; t->ch[0]=l; t->ch[1]=expr(); - return t; - } - return l; + Node *l=ternary(), *t; + for(int i=0; asgn_ops[i]!=TK_EOF; i++) + if (tok.kind==asgn_ops[i]) { + TKind op=tok.kind; next(); + t=alloc_node(N_ASGN); t->op=op; t->ch[0]=l; t->ch[1]=expr(); + return t; + } + return l; } static Node *decl_local(void) { - TKind tb; int pt; - parse_type(&tb,&pt); - char nm[512]; strcpy(nm, tok.str); expect(TK_ID); - Node *n; - if (tok.kind==TK_LBRACK) { - next(); n=alloc_node(N_LARR); - n->tbase=tb; n->ptrs=pt; strcpy(n->str,nm); - n->ch[0]=expr(); expect(TK_RBRACK); - if (accept(TK_ASSIGN)) { - expect(TK_LBRACE); - while (tok.kind!=TK_RBRACE) { - list_push(n, expr()); accept(TK_COMMA); - } - expect(TK_RBRACE); - } - } else { - n=alloc_node(N_LVAR); - n->tbase=tb; n->ptrs=pt; strcpy(n->str,nm); - if (accept(TK_ASSIGN)) n->ch[0]=expr(); + TKind tb; int pt; + parse_type(&tb,&pt); + char nm[512]; strcpy(nm, tok.str); expect(TK_ID); + Node *n; + if (tok.kind==TK_LBRACK) { + next(); n=alloc_node(N_LARR); + n->tbase=tb; n->ptrs=pt; strcpy(n->str,nm); + n->ch[0]=expr(); expect(TK_RBRACK); + if (accept(TK_ASSIGN)) { + expect(TK_LBRACE); + while (tok.kind!=TK_RBRACE) { + list_push(n, expr()); accept(TK_COMMA); + } + expect(TK_RBRACE); } - expect(TK_SEMI); return n; + } else { + n=alloc_node(N_LVAR); + n->tbase=tb; n->ptrs=pt; strcpy(n->str,nm); + if (accept(TK_ASSIGN)) n->ch[0]=expr(); + } + expect(TK_SEMI); return n; } static Node *stmt(void) { - Node *n, *t; - if (is_type()) return decl_local(); - switch(tok.kind) { - case TK_LBRACE: return block(); - case TK_IF: - n=alloc_node(N_IF); next(); - expect(TK_LPAREN); n->ch[0]=expr(); expect(TK_RPAREN); - n->ch[1]=stmt(); - if (tok.kind==TK_ELSE) { - next(); n->ch[2]=stmt(); - } - return n; - case TK_WHILE: - n=alloc_node(N_WHILE); next(); - expect(TK_LPAREN); n->ch[0]=expr(); expect(TK_RPAREN); - n->ch[1]=stmt(); return n; - case TK_FOR: - n=alloc_node(N_FOR); next(); expect(TK_LPAREN); - if (is_type()) n->ch[0]=decl_local(); /* consumes ; */ - else if (tok.kind!=TK_SEMI) { Node *es=alloc_node(N_ES); es->ch[0]=expr(); expect(TK_SEMI); n->ch[0]=es; } - else { next(); } - if (tok.kind!=TK_SEMI) n->ch[1]=expr(); - expect(TK_SEMI); - if (tok.kind!=TK_RPAREN) n->ch[2]=expr(); - expect(TK_RPAREN); n->ch[3]=stmt(); return n; - case TK_SWITCH: - n=alloc_node(N_SW); next(); - expect(TK_LPAREN); n->ch[0]=expr(); expect(TK_RPAREN); - expect(TK_LBRACE); - while (tok.kind!=TK_RBRACE) { - if (tok.kind==TK_CASE) { - next(); t=alloc_node(N_CASE); t->ch[0]=expr(); expect(TK_COLON); - while(tok.kind!=TK_CASE&&tok.kind!=TK_DEFAULT&&tok.kind!=TK_RBRACE) - list_push(t, stmt()); - list_push(n, t); - } else if (tok.kind==TK_DEFAULT) { - next(); expect(TK_COLON); - t=alloc_node(N_DEF); - while(tok.kind!=TK_CASE&&tok.kind!=TK_DEFAULT&&tok.kind!=TK_RBRACE) - list_push(t, stmt()); - list_push(n, t); - } else break; - } - expect(TK_RBRACE); return n; - case TK_RETURN: - n=alloc_node(N_RET); next(); - if (tok.kind!=TK_SEMI) n->ch[0]=expr(); - expect(TK_SEMI); return n; - case TK_BREAK: - next(); expect(TK_SEMI); return alloc_node(N_BRK); - case TK_CONTINUE: - next(); expect(TK_SEMI); return alloc_node(N_CONT); - default: - n=alloc_node(N_ES); n->ch[0]=expr(); expect(TK_SEMI); return n; + Node *n, *t; + if (is_type()) return decl_local(); + switch(tok.kind) { + case TK_LBRACE: return block(); + case TK_IF: + n=alloc_node(N_IF); next(); + expect(TK_LPAREN); n->ch[0]=expr(); expect(TK_RPAREN); + n->ch[1]=stmt(); + if (tok.kind==TK_ELSE) { + next(); n->ch[2]=stmt(); } + return n; + case TK_WHILE: + n=alloc_node(N_WHILE); next(); + expect(TK_LPAREN); n->ch[0]=expr(); expect(TK_RPAREN); + n->ch[1]=stmt(); return n; + case TK_FOR: + n=alloc_node(N_FOR); next(); expect(TK_LPAREN); + if (is_type()) n->ch[0]=decl_local(); /* consumes ; */ + else if (tok.kind!=TK_SEMI) { Node *es=alloc_node(N_ES); es->ch[0]=expr(); expect(TK_SEMI); n->ch[0]=es; } + else { next(); } + if (tok.kind!=TK_SEMI) n->ch[1]=expr(); + expect(TK_SEMI); + if (tok.kind!=TK_RPAREN) n->ch[2]=expr(); + expect(TK_RPAREN); n->ch[3]=stmt(); return n; + case TK_SWITCH: + n=alloc_node(N_SW); next(); + expect(TK_LPAREN); n->ch[0]=expr(); expect(TK_RPAREN); + expect(TK_LBRACE); + while (tok.kind!=TK_RBRACE) { + if (tok.kind==TK_CASE) { + next(); t=alloc_node(N_CASE); t->ch[0]=expr(); expect(TK_COLON); + while(tok.kind!=TK_CASE&&tok.kind!=TK_DEFAULT&&tok.kind!=TK_RBRACE) + list_push(t, stmt()); + list_push(n, t); + } else if (tok.kind==TK_DEFAULT) { + next(); expect(TK_COLON); + t=alloc_node(N_DEF); + while(tok.kind!=TK_CASE&&tok.kind!=TK_DEFAULT&&tok.kind!=TK_RBRACE) + list_push(t, stmt()); + list_push(n, t); + } else break; + } + expect(TK_RBRACE); return n; + case TK_RETURN: + n=alloc_node(N_RET); next(); + if (tok.kind!=TK_SEMI) n->ch[0]=expr(); + expect(TK_SEMI); return n; + case TK_BREAK: + next(); expect(TK_SEMI); return alloc_node(N_BRK); + case TK_CONTINUE: + next(); expect(TK_SEMI); return alloc_node(N_CONT); + default: + n=alloc_node(N_ES); n->ch[0]=expr(); expect(TK_SEMI); return n; + } } static Node *block(void) { - Node *n=alloc_node(N_BLK); expect(TK_LBRACE); - while (tok.kind!=TK_RBRACE) list_push(n, stmt()); - expect(TK_RBRACE); return n; + Node *n=alloc_node(N_BLK); expect(TK_LBRACE); + while (tok.kind!=TK_RBRACE) list_push(n, stmt()); + expect(TK_RBRACE); return n; } static Node *parse_prog(void) { - Node *prog=alloc_node(N_PROG); - next(); - while (tok.kind!=TK_EOF) { - TKind tb; int pt; - parse_type(&tb,&pt); - char nm[512]; strcpy(nm,tok.str); expect(TK_ID); - Node *d; - if (tok.kind==TK_LPAREN) { - next(); d=alloc_node(N_FUNC); - d->tbase=tb; d->ptrs=pt; strcpy(d->str,nm); - /* params */ - if (tok.kind!=TK_RPAREN) - for(;;) { - if (tok.kind==TK_VOID) { next(); break; } /* accept (void) as empty param list */ - TKind ptb; int ppt; - parse_type(&ptb,&ppt); - Node *p=alloc_node(N_PARAM); - p->tbase=ptb; p->ptrs=ppt; strcpy(p->str,tok.str); - expect(TK_ID); list_push(d, p); - if (!accept(TK_COMMA)) break; - } - expect(TK_RPAREN); - if (tok.kind==TK_SEMI) { next(); d->kind=N_FDECL; } - else d->ch[0]=block(); - } else if (tok.kind==TK_LBRACK) { - /* global array: type name[size]; - or type name[size] = { v, … }; */ - next(); - d=alloc_node(N_GARR); - d->tbase=tb; d->ptrs=pt; strcpy(d->str,nm); - d->ch[0]=expr(); /* size expression */ - expect(TK_RBRACK); - if (accept(TK_ASSIGN)) { - expect(TK_LBRACE); - while (tok.kind!=TK_RBRACE) { - list_push(d, expr()); accept(TK_COMMA); - } - expect(TK_RBRACE); - } - expect(TK_SEMI); - } else { - d=alloc_node(N_GVAR); - d->tbase=tb; d->ptrs=pt; strcpy(d->str,nm); - if (accept(TK_ASSIGN)) d->ch[0]=expr(); - expect(TK_SEMI); - } - list_push(prog, d); + Node *prog=alloc_node(N_PROG); + next(); + while (tok.kind!=TK_EOF) { + TKind tb; int pt; + parse_type(&tb,&pt); + char nm[512]; strcpy(nm,tok.str); expect(TK_ID); + Node *d; + if (tok.kind==TK_LPAREN) { + next(); d=alloc_node(N_FUNC); + d->tbase=tb; d->ptrs=pt; strcpy(d->str,nm); + /* params */ + if (tok.kind!=TK_RPAREN) + for(;;) { + if (tok.kind==TK_VOID) { next(); break; } /* accept (void) as empty param list */ + TKind ptb; int ppt; + parse_type(&ptb,&ppt); + Node *p=alloc_node(N_PARAM); + p->tbase=ptb; p->ptrs=ppt; strcpy(p->str,tok.str); + expect(TK_ID); list_push(d, p); + if (!accept(TK_COMMA)) break; + } + expect(TK_RPAREN); + if (tok.kind==TK_SEMI) { next(); d->kind=N_FDECL; } + else d->ch[0]=block(); + } else if (tok.kind==TK_LBRACK) { + /* global array: type name[size]; + or type name[size] = { v, … }; */ + next(); + d=alloc_node(N_GARR); + d->tbase=tb; d->ptrs=pt; strcpy(d->str,nm); + d->ch[0]=expr(); /* size expression */ + expect(TK_RBRACK); + if (accept(TK_ASSIGN)) { + expect(TK_LBRACE); + while (tok.kind!=TK_RBRACE) { + list_push(d, expr()); accept(TK_COMMA); + } + expect(TK_RBRACE); + } + expect(TK_SEMI); + } else { + d=alloc_node(N_GVAR); + d->tbase=tb; d->ptrs=pt; strcpy(d->str,nm); + if (accept(TK_ASSIGN)) d->ch[0]=expr(); + expect(TK_SEMI); } - return prog; + list_push(prog, d); + } + return prog; } /* ══════════════════════════════════════════════════════════ @@ -571,12 +571,12 @@ static int str_cnt = 0; /* FIX(bug2): length-aware string interning using memcmp instead of strcmp */ static int intern_str_n(const char *s, int len) { - for (int i=0; i 0) E("[ebp+%d]", off); - else E("[ebp%d]", off); + int off = find_local(nm); + if (off == 0x7fffffff) E("[%s]", nm); + else if (off > 0) E("[ebp+%d]", off); + else E("[ebp%d]", off); } /* Emit address of a local/global (for array decay: lea not mov) */ static void emit_addr(const char *nm) { - int off = find_local(nm); - if (off == 0x7fffffff) { E(" mov eax, %s\n", nm); return; } /* global: label IS address */ - if (off > 0) EL("lea eax, [ebp+%d]\n", off); - else EL("lea eax, [ebp%d]\n", off); + int off = find_local(nm); + if (off == 0x7fffffff) { E(" mov eax, %s\n", nm); return; } /* global: label IS address */ + if (off > 0) EL("lea eax, [ebp+%d]\n", off); + else EL("lea eax, [ebp%d]\n", off); } static void load_nm(const char *nm) { - /* Arrays decay to a pointer: yield address, not the value stored there */ - if (local_is_array(nm)) { emit_addr(nm); return; } - if (global_is_array(nm)) { E(" mov eax, %s\n", nm); return; } - E(" mov eax, "); emit_ref(nm); E("\n"); + /* Arrays decay to a pointer: yield address, not the value stored there */ + if (local_is_array(nm)) { emit_addr(nm); return; } + if (global_is_array(nm)) { E(" mov eax, %s\n", nm); return; } + E(" mov eax, "); emit_ref(nm); E("\n"); } /* ══════════════════════════════════════════════════════════ @@ -697,8 +697,8 @@ static int base_size(TKind tbase) { /* Stride for pointer arithmetic: the size of what the pointer points at. pointer-to-pointer always has stride 4 (one address). */ static int pointee_size(TKind tbase, int ptrs) { - if (ptrs > 1) return 4; - return base_size(tbase); + if (ptrs > 1) return 4; + return base_size(tbase); } /* forward */ @@ -709,499 +709,499 @@ static Type fun_ret_type(const char *nm); /* defined in codegen section */ /* Infer the type of an expression node. Walks the AST without emitting any code. */ static Type get_type(Node *n) { - if (!n) return T_INT; - switch (n->kind) { - case N_NUM: - return T_INT; - case N_STR: - return (Type){ TK_UINT8, 1 }; /* char* */ - case N_ID: { - /* Check locals first, then globals */ - for (int i=0; istr)) - return (Type){ locals[i].tbase, locals[i].ptrs }; - for (int i=0; istr)) - return (Type){ gvars[i].tbase, gvars[i].ptrs }; - return T_INT; - } - case N_ADDR: { - Type inner = get_type(n->ch[0]); - return (Type){ inner.tbase, inner.ptrs + 1 }; - } - case N_DEREF: { - Type inner = get_type(n->ch[0]); - if (inner.ptrs > 0) return (Type){ inner.tbase, inner.ptrs - 1 }; - return T_INT; - } - case N_IDX: { - Type arr = get_type(n->ch[0]); - if (arr.ptrs > 0) return (Type){ arr.tbase, arr.ptrs - 1 }; - return T_INT; - } - case N_CAST: - return (Type){ n->tbase, n->ptrs }; - case N_CALL: - if (n->ch[0] && n->ch[0]->kind == N_ID) - return fun_ret_type(n->ch[0]->str); - return T_INT; - case N_BOPN: - case N_ASGN: { - /* Arithmetic preserves a pointer type if either operand is a pointer */ - Type l = get_type(n->ch[0]); - Type r = get_type(n->ch[1]); - if (l.ptrs > 0) return l; - if (r.ptrs > 0) return r; - return T_INT; - } - case N_POSTINC: case N_POSTDEC: - case N_PREINC: case N_PREDEC: - return get_type(n->ch[0]); - case N_UOPN: - /* Negation/bitwise-not propagate the child type; the result is signed */ - if (n->op == TK_MINUS || n->op == TK_TILDE) - return (Type){ TK_INT32, 0 }; - return T_INT; - default: - return T_INT; - } + if (!n) return T_INT; + switch (n->kind) { + case N_NUM: + return T_INT; + case N_STR: + return (Type){ TK_UINT8, 1 }; /* char* */ + case N_ID: { + /* Check locals first, then globals */ + for (int i=0; istr)) + return (Type){ locals[i].tbase, locals[i].ptrs }; + for (int i=0; istr)) + return (Type){ gvars[i].tbase, gvars[i].ptrs }; + return T_INT; + } + case N_ADDR: { + Type inner = get_type(n->ch[0]); + return (Type){ inner.tbase, inner.ptrs + 1 }; + } + case N_DEREF: { + Type inner = get_type(n->ch[0]); + if (inner.ptrs > 0) return (Type){ inner.tbase, inner.ptrs - 1 }; + return T_INT; + } + case N_IDX: { + Type arr = get_type(n->ch[0]); + if (arr.ptrs > 0) return (Type){ arr.tbase, arr.ptrs - 1 }; + return T_INT; + } + case N_CAST: + return (Type){ n->tbase, n->ptrs }; + case N_CALL: + if (n->ch[0] && n->ch[0]->kind == N_ID) + return fun_ret_type(n->ch[0]->str); + return T_INT; + case N_BOPN: + case N_ASGN: { + /* Arithmetic preserves a pointer type if either operand is a pointer */ + Type l = get_type(n->ch[0]); + Type r = get_type(n->ch[1]); + if (l.ptrs > 0) return l; + if (r.ptrs > 0) return r; + return T_INT; + } + case N_POSTINC: case N_POSTDEC: + case N_PREINC: case N_PREDEC: + return get_type(n->ch[0]); + case N_UOPN: + /* Negation/bitwise-not propagate the child type; the result is signed */ + if (n->op == TK_MINUS || n->op == TK_TILDE) + return (Type){ TK_INT32, 0 }; + return T_INT; + default: + return T_INT; + } } /* Emit an integer scale instruction sequence. On entry eax holds the integer to scale; on exit eax = eax * scale. */ static void emit_scale(int scale) { - if (scale == 1) { /* nothing */ } - else if (scale == 2) EL("shl eax, 1\n"); - else if (scale == 4) EL("shl eax, 2\n"); - else if (scale == 8) EL("shl eax, 3\n"); - else EL("imul eax, %d\n", scale); + if (scale == 1) { /* nothing */ } + else if (scale == 2) EL("shl eax, 1\n"); + else if (scale == 4) EL("shl eax, 2\n"); + else if (scale == 8) EL("shl eax, 3\n"); + else EL("imul eax, %d\n", scale); } /* ══════════════════════════════════════════════════════════ LVALUE / STORE HELPERS ══════════════════════════════════════════════════════════ */ static void gen_lval_addr(Node *n) { - if (n->kind==N_ID) { - int off=find_local(n->str); - if (off==0x7fffffff) EL("mov eax, %s\n", n->str); - else if (off>0) EL("lea eax, [ebp+%d]\n", off); - else EL("lea eax, [ebp%d]\n", off); - } else if (n->kind==N_IDX) { - /* addr of arr[ix]: base + ix * element_size. - FIX: use gen_expr on the base, not gen_lval_addr. - gen_lval_addr on a pointer N_ID yields the stack slot address (lea), - but we need the pointer *value* (mov). gen_expr already handles both: - array identifiers decay to their base address (lea), pointer identifiers - load their value (mov). */ - Type arr = get_type(n->ch[0]); - int scale = pointee_size(arr.tbase, arr.ptrs); - gen_expr(n->ch[0]); EL("push eax\n"); - gen_expr(n->ch[1]); - emit_scale(scale); - EL("pop ecx\n"); EL("add eax, ecx\n"); - } else if (n->kind==N_DEREF) { - gen_expr(n->ch[0]); - } + if (n->kind==N_ID) { + int off=find_local(n->str); + if (off==0x7fffffff) EL("mov eax, %s\n", n->str); + else if (off>0) EL("lea eax, [ebp+%d]\n", off); + else EL("lea eax, [ebp%d]\n", off); + } else if (n->kind==N_IDX) { + /* addr of arr[ix]: base + ix * element_size. + FIX: use gen_expr on the base, not gen_lval_addr. + gen_lval_addr on a pointer N_ID yields the stack slot address (lea), + but we need the pointer *value* (mov). gen_expr already handles both: + array identifiers decay to their base address (lea), pointer identifiers + load their value (mov). */ + Type arr = get_type(n->ch[0]); + int scale = pointee_size(arr.tbase, arr.ptrs); + gen_expr(n->ch[0]); EL("push eax\n"); + gen_expr(n->ch[1]); + emit_scale(scale); + EL("pop ecx\n"); EL("add eax, ecx\n"); + } else if (n->kind==N_DEREF) { + gen_expr(n->ch[0]); + } } static void store_lval(Node *n) { - if (n->kind==N_ID) { - E(" mov "); emit_ref(n->str); E(", eax\n"); - } else if (n->kind==N_IDX || n->kind==N_DEREF) { - EL("push eax\n"); - gen_lval_addr(n); - EL("pop ecx\n"); - /* Store only as many bytes as the element type requires */ - Type t = get_type(n); - int sz = (t.ptrs > 0) ? 4 : base_size(t.tbase); - switch (sz) { - case 1: EL("mov byte [eax], cl\n"); break; - case 2: EL("mov word [eax], cx\n"); break; - default: EL("mov dword [eax], ecx\n"); break; - } + if (n->kind==N_ID) { + E(" mov "); emit_ref(n->str); E(", eax\n"); + } else if (n->kind==N_IDX || n->kind==N_DEREF) { + EL("push eax\n"); + gen_lval_addr(n); + EL("pop ecx\n"); + /* Store only as many bytes as the element type requires */ + Type t = get_type(n); + int sz = (t.ptrs > 0) ? 4 : base_size(t.tbase); + switch (sz) { + case 1: EL("mov byte [eax], cl\n"); break; + case 2: EL("mov word [eax], cx\n"); break; + default: EL("mov dword [eax], ecx\n"); break; } + } } /* ══════════════════════════════════════════════════════════ ARITHMETIC HELPERS ══════════════════════════════════════════════════════════ */ static void arith(TKind op, int sgn) { - /* ecx=left, eax=right → eax=result; sgn=1 for signed operands */ - switch(op) { - case TK_PLUS: EL("add eax, ecx\n"); break; - case TK_MINUS: EL("sub ecx, eax\n"); EL("mov eax, ecx\n"); break; - case TK_STAR: EL("imul eax, ecx\n"); break; - case TK_SLASH: - EL("xchg eax, ecx\n"); - if (sgn) { EL("cdq\n"); EL("idiv ecx\n"); } - else { EL("xor edx, edx\n"); EL("div ecx\n"); } - break; - case TK_MOD: - EL("xchg eax, ecx\n"); - if (sgn) { EL("cdq\n"); EL("idiv ecx\n"); } - else { EL("xor edx, edx\n"); EL("div ecx\n"); } - EL("mov eax, edx\n"); - break; - case TK_AMP: EL("and eax, ecx\n"); break; - case TK_PIPE: EL("or eax, ecx\n"); break; - case TK_CARET: EL("xor eax, ecx\n"); break; - case TK_SHL: EL("xchg eax, ecx\n"); EL("shl eax, cl\n"); break; - case TK_SHR: - EL("xchg eax, ecx\n"); - EL(sgn ? "sar eax, cl\n" : "shr eax, cl\n"); - break; - default: break; - } + /* ecx=left, eax=right → eax=result; sgn=1 for signed operands */ + switch(op) { + case TK_PLUS: EL("add eax, ecx\n"); break; + case TK_MINUS: EL("sub ecx, eax\n"); EL("mov eax, ecx\n"); break; + case TK_STAR: EL("imul eax, ecx\n"); break; + case TK_SLASH: + EL("xchg eax, ecx\n"); + if (sgn) { EL("cdq\n"); EL("idiv ecx\n"); } + else { EL("xor edx, edx\n"); EL("div ecx\n"); } + break; + case TK_MOD: + EL("xchg eax, ecx\n"); + if (sgn) { EL("cdq\n"); EL("idiv ecx\n"); } + else { EL("xor edx, edx\n"); EL("div ecx\n"); } + EL("mov eax, edx\n"); + break; + case TK_AMP: EL("and eax, ecx\n"); break; + case TK_PIPE: EL("or eax, ecx\n"); break; + case TK_CARET: EL("xor eax, ecx\n"); break; + case TK_SHL: EL("xchg eax, ecx\n"); EL("shl eax, cl\n"); break; + case TK_SHR: + EL("xchg eax, ecx\n"); + EL(sgn ? "sar eax, cl\n" : "shr eax, cl\n"); + break; + default: break; + } } /* Pointer-aware add/subtract. On entry: ecx = left operand, eax = right operand. On exit: eax = result. */ static void ptr_arith(TKind op, Type lt, Type rt) { - if (op == TK_PLUS) { - if (lt.ptrs > 0) { - /* ptr + int: scale the integer (eax) by pointee size */ - int scale = pointee_size(lt.tbase, lt.ptrs); - emit_scale(scale); - EL("add eax, ecx\n"); - } else if (rt.ptrs > 0) { - /* int + ptr: scale the integer (ecx) by pointee size */ - int scale = pointee_size(rt.tbase, rt.ptrs); - if (scale == 1) { /* nothing */ } - else if (scale == 2) EL("shl ecx, 1\n"); - else if (scale == 4) EL("shl ecx, 2\n"); - else if (scale == 8) EL("shl ecx, 3\n"); - else EL("imul ecx, %d\n", scale); - EL("add eax, ecx\n"); - } else { - EL("add eax, ecx\n"); - } - } else if (op == TK_MINUS) { - if (lt.ptrs > 0 && rt.ptrs == 0) { - /* ptr - int: scale the integer (eax) by pointee size */ - int scale = pointee_size(lt.tbase, lt.ptrs); - emit_scale(scale); - EL("sub ecx, eax\n"); EL("mov eax, ecx\n"); - } else if (lt.ptrs > 0 && rt.ptrs > 0) { - /* ptr - ptr: raw byte difference divided by pointee size */ - EL("sub ecx, eax\n"); EL("mov eax, ecx\n"); - int scale = pointee_size(lt.tbase, lt.ptrs); - if (scale > 1) { - EL("xor edx, edx\n"); - EL("mov ecx, %d\n", scale); - EL("div ecx\n"); - } - } else { - EL("sub ecx, eax\n"); EL("mov eax, ecx\n"); - } + if (op == TK_PLUS) { + if (lt.ptrs > 0) { + /* ptr + int: scale the integer (eax) by pointee size */ + int scale = pointee_size(lt.tbase, lt.ptrs); + emit_scale(scale); + EL("add eax, ecx\n"); + } else if (rt.ptrs > 0) { + /* int + ptr: scale the integer (ecx) by pointee size */ + int scale = pointee_size(rt.tbase, rt.ptrs); + if (scale == 1) { /* nothing */ } + else if (scale == 2) EL("shl ecx, 1\n"); + else if (scale == 4) EL("shl ecx, 2\n"); + else if (scale == 8) EL("shl ecx, 3\n"); + else EL("imul ecx, %d\n", scale); + EL("add eax, ecx\n"); + } else { + EL("add eax, ecx\n"); } + } else if (op == TK_MINUS) { + if (lt.ptrs > 0 && rt.ptrs == 0) { + /* ptr - int: scale the integer (eax) by pointee size */ + int scale = pointee_size(lt.tbase, lt.ptrs); + emit_scale(scale); + EL("sub ecx, eax\n"); EL("mov eax, ecx\n"); + } else if (lt.ptrs > 0 && rt.ptrs > 0) { + /* ptr - ptr: raw byte difference divided by pointee size */ + EL("sub ecx, eax\n"); EL("mov eax, ecx\n"); + int scale = pointee_size(lt.tbase, lt.ptrs); + if (scale > 1) { + EL("xor edx, edx\n"); + EL("mov ecx, %d\n", scale); + EL("div ecx\n"); + } + } else { + EL("sub ecx, eax\n"); EL("mov eax, ecx\n"); + } + } } /* ══════════════════════════════════════════════════════════ EXPRESSION CODE GENERATOR ══════════════════════════════════════════════════════════ */ static void gen_expr(Node *n) { - int la, lb; - switch(n->kind) { - case N_NUM: - EL("mov eax, %ld\n", n->num); break; - case N_STR: { - /* FIX(bug2): use length-aware intern */ - int id=intern_str_n(n->str, n->slen); - EL("mov eax, _s%d\n", id); break; } - case N_ID: - load_nm(n->str); break; - case N_ADDR: - gen_lval_addr(n->ch[0]); break; + int la, lb; + switch(n->kind) { + case N_NUM: + EL("mov eax, %ld\n", n->num); break; + case N_STR: { + /* FIX(bug2): use length-aware intern */ + int id=intern_str_n(n->str, n->slen); + EL("mov eax, _s%d\n", id); break; } + case N_ID: + load_nm(n->str); break; + case N_ADDR: + gen_lval_addr(n->ch[0]); break; - case N_DEREF: { - /* Load from pointer; respect the pointee width and signedness */ - gen_expr(n->ch[0]); - Type inner = get_type(n->ch[0]); - int psz = (inner.ptrs > 1) ? 4 : base_size(inner.tbase); - int sgn = (inner.ptrs == 1) && is_signed(inner.tbase); - switch (psz) { - case 1: EL(sgn ? "movsx eax, byte [eax]\n" : "movzx eax, byte [eax]\n"); break; - case 2: EL(sgn ? "movsx eax, word [eax]\n" : "movzx eax, word [eax]\n"); break; - case 8: EL("mov eax, [eax]\n"); break; /* truncate 64→32; full 64-bit NYI */ - default: EL("mov eax, [eax]\n"); break; - } - break; + case N_DEREF: { + /* Load from pointer; respect the pointee width and signedness */ + gen_expr(n->ch[0]); + Type inner = get_type(n->ch[0]); + int psz = (inner.ptrs > 1) ? 4 : base_size(inner.tbase); + int sgn = (inner.ptrs == 1) && is_signed(inner.tbase); + switch (psz) { + case 1: EL(sgn ? "movsx eax, byte [eax]\n" : "movzx eax, byte [eax]\n"); break; + case 2: EL(sgn ? "movsx eax, word [eax]\n" : "movzx eax, word [eax]\n"); break; + case 8: EL("mov eax, [eax]\n"); break; /* truncate 64→32; full 64-bit NYI */ + default: EL("mov eax, [eax]\n"); break; } + break; + } - case N_CAST: - gen_expr(n->ch[0]); - if (n->ptrs == 0) { - switch (n->tbase) { - case TK_INT8: EL("movsx eax, al\n"); break; /* sign-extend low byte */ - case TK_INT16: EL("movsx eax, ax\n"); break; /* sign-extend low word */ - case TK_UINT8: EL("and eax, 0xFF\n"); break; - case TK_UINT16: EL("and eax, 0xFFFF\n"); break; - default: break; /* int32/uint32/int64/uint64: no truncation needed */ - } - } - break; - - case N_POSTINC: { - Type t = get_type(n->ch[0]); - int stride = (t.ptrs > 0) ? pointee_size(t.tbase, t.ptrs) : 1; - gen_expr(n->ch[0]); EL("push eax\n"); - EL("add eax, %d\n", stride); store_lval(n->ch[0]); EL("pop eax\n"); - break; + case N_CAST: + gen_expr(n->ch[0]); + if (n->ptrs == 0) { + switch (n->tbase) { + case TK_INT8: EL("movsx eax, al\n"); break; /* sign-extend low byte */ + case TK_INT16: EL("movsx eax, ax\n"); break; /* sign-extend low word */ + case TK_UINT8: EL("and eax, 0xFF\n"); break; + case TK_UINT16: EL("and eax, 0xFFFF\n"); break; + default: break; /* int32/uint32/int64/uint64: no truncation needed */ + } } - case N_POSTDEC: { - Type t = get_type(n->ch[0]); - int stride = (t.ptrs > 0) ? pointee_size(t.tbase, t.ptrs) : 1; - gen_expr(n->ch[0]); EL("push eax\n"); - EL("sub eax, %d\n", stride); store_lval(n->ch[0]); EL("pop eax\n"); - break; + break; + + case N_POSTINC: { + Type t = get_type(n->ch[0]); + int stride = (t.ptrs > 0) ? pointee_size(t.tbase, t.ptrs) : 1; + gen_expr(n->ch[0]); EL("push eax\n"); + EL("add eax, %d\n", stride); store_lval(n->ch[0]); EL("pop eax\n"); + break; + } + case N_POSTDEC: { + Type t = get_type(n->ch[0]); + int stride = (t.ptrs > 0) ? pointee_size(t.tbase, t.ptrs) : 1; + gen_expr(n->ch[0]); EL("push eax\n"); + EL("sub eax, %d\n", stride); store_lval(n->ch[0]); EL("pop eax\n"); + break; + } + case N_PREINC: { + Type t = get_type(n->ch[0]); + int stride = (t.ptrs > 0) ? pointee_size(t.tbase, t.ptrs) : 1; + gen_expr(n->ch[0]); EL("add eax, %d\n", stride); store_lval(n->ch[0]); + break; + } + case N_PREDEC: { + Type t = get_type(n->ch[0]); + int stride = (t.ptrs > 0) ? pointee_size(t.tbase, t.ptrs) : 1; + gen_expr(n->ch[0]); EL("sub eax, %d\n", stride); store_lval(n->ch[0]); + break; + } + + case N_UOPN: + gen_expr(n->ch[0]); + if (n->op==TK_MINUS) EL("neg eax\n"); + else if (n->op==TK_TILDE) EL("not eax\n"); + else { EL("test eax, eax\n"); EL("setz al\n"); EL("movzx eax, al\n"); } + break; + + case N_BOPN: + if (n->op==TK_OR) { + la=new_lbl(); lb=new_lbl(); + gen_expr(n->ch[0]); EL("test eax, eax\n"); EL("jnz .L%d\n",la); + gen_expr(n->ch[1]); EL("test eax, eax\n"); EL("jnz .L%d\n",la); + EL("xor eax, eax\n"); EL("jmp .L%d\n",lb); + E(".L%d:\n",la); EL("mov eax, 1\n"); E(".L%d:\n",lb); + } else if (n->op==TK_AND) { + la=new_lbl(); lb=new_lbl(); + gen_expr(n->ch[0]); EL("test eax, eax\n"); EL("jz .L%d\n",la); + gen_expr(n->ch[1]); EL("test eax, eax\n"); EL("jz .L%d\n",la); + EL("mov eax, 1\n"); EL("jmp .L%d\n",lb); + E(".L%d:\n",la); EL("xor eax, eax\n"); E(".L%d:\n",lb); + } else { + /* Evaluate both sides; ecx=left, eax=right */ + gen_expr(n->ch[0]); EL("push eax\n"); + gen_expr(n->ch[1]); EL("pop ecx\n"); + { + int sgn = is_signed(get_type(n->ch[0]).tbase) || + is_signed(get_type(n->ch[1]).tbase); + switch(n->op) { + case TK_EQ: EL("cmp ecx, eax\n"); EL("sete al\n"); EL("movzx eax, al\n"); break; + case TK_NEQ: EL("cmp ecx, eax\n"); EL("setne al\n"); EL("movzx eax, al\n"); break; + case TK_LT: EL("cmp ecx, eax\n"); EL(sgn?"setl al\n" :"setb al\n"); EL("movzx eax, al\n"); break; + case TK_LEQ: EL("cmp ecx, eax\n"); EL(sgn?"setle al\n":"setbe al\n"); EL("movzx eax, al\n"); break; + case TK_GT: EL("cmp ecx, eax\n"); EL(sgn?"setg al\n" :"seta al\n"); EL("movzx eax, al\n"); break; + case TK_GEQ: EL("cmp ecx, eax\n"); EL(sgn?"setge al\n":"setae al\n"); EL("movzx eax, al\n"); break; + case TK_PLUS: + case TK_MINUS: { + Type lt = get_type(n->ch[0]); + Type rt = get_type(n->ch[1]); + if (lt.ptrs > 0 || rt.ptrs > 0) + ptr_arith(n->op, lt, rt); + else + arith(n->op, sgn); + break; + } + default: arith(n->op, sgn); break; + } + } } - case N_PREINC: { - Type t = get_type(n->ch[0]); - int stride = (t.ptrs > 0) ? pointee_size(t.tbase, t.ptrs) : 1; - gen_expr(n->ch[0]); EL("add eax, %d\n", stride); store_lval(n->ch[0]); - break; + break; + + case N_ASGN: + if (n->op==TK_ASSIGN) { + gen_expr(n->ch[1]); store_lval(n->ch[0]); + } else { + /* Compound assignment */ + TKind base; + switch(n->op){ + case TK_ADDEQ: base=TK_PLUS; break; case TK_SUBEQ: base=TK_MINUS; break; + case TK_MULEQ: base=TK_STAR; break; case TK_DIVEQ: base=TK_SLASH; break; + case TK_MODEQ: base=TK_MOD; break; case TK_ANDEQ: base=TK_AMP; break; + case TK_OREQ: base=TK_PIPE; break; case TK_XOREQ: base=TK_CARET; break; + case TK_SHLEQ: base=TK_SHL; break; case TK_SHREQ: base=TK_SHR; break; + default: base=TK_EOF; + } + gen_expr(n->ch[0]); EL("push eax\n"); + gen_expr(n->ch[1]); EL("pop ecx\n"); + { + int sgn = is_signed(get_type(n->ch[0]).tbase) || + is_signed(get_type(n->ch[1]).tbase); + if (base==TK_PLUS || base==TK_MINUS) { + Type lt = get_type(n->ch[0]); + Type rt = get_type(n->ch[1]); + if (lt.ptrs > 0 || rt.ptrs > 0) + ptr_arith(base, lt, rt); + else + arith(base, sgn); + } else { + arith(base, sgn); + } + } + store_lval(n->ch[0]); } - case N_PREDEC: { - Type t = get_type(n->ch[0]); - int stride = (t.ptrs > 0) ? pointee_size(t.tbase, t.ptrs) : 1; - gen_expr(n->ch[0]); EL("sub eax, %d\n", stride); store_lval(n->ch[0]); - break; + break; + + case N_TERN: + la=new_lbl(); lb=new_lbl(); + gen_expr(n->ch[0]); EL("test eax, eax\n"); EL("jz .L%d\n",la); + gen_expr(n->ch[1]); EL("jmp .L%d\n",lb); + E(".L%d:\n",la); gen_expr(n->ch[2]); E(".L%d:\n",lb); + break; + + case N_CALL: { + int argc=n->nlist; + for (int i=argc-1;i>=0;i--) { gen_expr(n->list[i]); EL("push eax\n"); } + if (n->ch[0]->kind==N_ID) EL("call %s\n", n->ch[0]->str); + else { gen_expr(n->ch[0]); EL("call eax\n"); } + if (argc) EL("add esp, %d\n", argc*4); + break; } + + case N_IDX: { + /* arr[i] — address then dereference with correct width and signedness */ + Type arr = get_type(n->ch[0]); + int psz = (arr.ptrs > 1) ? 4 : base_size(arr.tbase); + int sgn = (arr.ptrs == 1) && is_signed(arr.tbase); + gen_lval_addr(n); + switch (psz) { + case 1: EL(sgn ? "movsx eax, byte [eax]\n" : "movzx eax, byte [eax]\n"); break; + case 2: EL(sgn ? "movsx eax, word [eax]\n" : "movzx eax, word [eax]\n"); break; + default: EL("mov eax, [eax]\n"); break; } + break; + } - case N_UOPN: - gen_expr(n->ch[0]); - if (n->op==TK_MINUS) EL("neg eax\n"); - else if (n->op==TK_TILDE) EL("not eax\n"); - else { EL("test eax, eax\n"); EL("setz al\n"); EL("movzx eax, al\n"); } - break; - - case N_BOPN: - if (n->op==TK_OR) { - la=new_lbl(); lb=new_lbl(); - gen_expr(n->ch[0]); EL("test eax, eax\n"); EL("jnz .L%d\n",la); - gen_expr(n->ch[1]); EL("test eax, eax\n"); EL("jnz .L%d\n",la); - EL("xor eax, eax\n"); EL("jmp .L%d\n",lb); - E(".L%d:\n",la); EL("mov eax, 1\n"); E(".L%d:\n",lb); - } else if (n->op==TK_AND) { - la=new_lbl(); lb=new_lbl(); - gen_expr(n->ch[0]); EL("test eax, eax\n"); EL("jz .L%d\n",la); - gen_expr(n->ch[1]); EL("test eax, eax\n"); EL("jz .L%d\n",la); - EL("mov eax, 1\n"); EL("jmp .L%d\n",lb); - E(".L%d:\n",la); EL("xor eax, eax\n"); E(".L%d:\n",lb); - } else { - /* Evaluate both sides; ecx=left, eax=right */ - gen_expr(n->ch[0]); EL("push eax\n"); - gen_expr(n->ch[1]); EL("pop ecx\n"); - { - int sgn = is_signed(get_type(n->ch[0]).tbase) || - is_signed(get_type(n->ch[1]).tbase); - switch(n->op) { - case TK_EQ: EL("cmp ecx, eax\n"); EL("sete al\n"); EL("movzx eax, al\n"); break; - case TK_NEQ: EL("cmp ecx, eax\n"); EL("setne al\n"); EL("movzx eax, al\n"); break; - case TK_LT: EL("cmp ecx, eax\n"); EL(sgn?"setl al\n" :"setb al\n"); EL("movzx eax, al\n"); break; - case TK_LEQ: EL("cmp ecx, eax\n"); EL(sgn?"setle al\n":"setbe al\n"); EL("movzx eax, al\n"); break; - case TK_GT: EL("cmp ecx, eax\n"); EL(sgn?"setg al\n" :"seta al\n"); EL("movzx eax, al\n"); break; - case TK_GEQ: EL("cmp ecx, eax\n"); EL(sgn?"setge al\n":"setae al\n"); EL("movzx eax, al\n"); break; - case TK_PLUS: - case TK_MINUS: { - Type lt = get_type(n->ch[0]); - Type rt = get_type(n->ch[1]); - if (lt.ptrs > 0 || rt.ptrs > 0) - ptr_arith(n->op, lt, rt); - else - arith(n->op, sgn); - break; - } - default: arith(n->op, sgn); break; - } - } - } - break; - - case N_ASGN: - if (n->op==TK_ASSIGN) { - gen_expr(n->ch[1]); store_lval(n->ch[0]); - } else { - /* Compound assignment */ - TKind base; - switch(n->op){ - case TK_ADDEQ: base=TK_PLUS; break; case TK_SUBEQ: base=TK_MINUS; break; - case TK_MULEQ: base=TK_STAR; break; case TK_DIVEQ: base=TK_SLASH; break; - case TK_MODEQ: base=TK_MOD; break; case TK_ANDEQ: base=TK_AMP; break; - case TK_OREQ: base=TK_PIPE; break; case TK_XOREQ: base=TK_CARET; break; - case TK_SHLEQ: base=TK_SHL; break; case TK_SHREQ: base=TK_SHR; break; - default: base=TK_EOF; - } - gen_expr(n->ch[0]); EL("push eax\n"); - gen_expr(n->ch[1]); EL("pop ecx\n"); - { - int sgn = is_signed(get_type(n->ch[0]).tbase) || - is_signed(get_type(n->ch[1]).tbase); - if (base==TK_PLUS || base==TK_MINUS) { - Type lt = get_type(n->ch[0]); - Type rt = get_type(n->ch[1]); - if (lt.ptrs > 0 || rt.ptrs > 0) - ptr_arith(base, lt, rt); - else - arith(base, sgn); - } else { - arith(base, sgn); - } - } - store_lval(n->ch[0]); - } - break; - - case N_TERN: - la=new_lbl(); lb=new_lbl(); - gen_expr(n->ch[0]); EL("test eax, eax\n"); EL("jz .L%d\n",la); - gen_expr(n->ch[1]); EL("jmp .L%d\n",lb); - E(".L%d:\n",la); gen_expr(n->ch[2]); E(".L%d:\n",lb); - break; - - case N_CALL: { - int argc=n->nlist; - for (int i=argc-1;i>=0;i--) { gen_expr(n->list[i]); EL("push eax\n"); } - if (n->ch[0]->kind==N_ID) EL("call %s\n", n->ch[0]->str); - else { gen_expr(n->ch[0]); EL("call eax\n"); } - if (argc) EL("add esp, %d\n", argc*4); - break; } - - case N_IDX: { - /* arr[i] — address then dereference with correct width and signedness */ - Type arr = get_type(n->ch[0]); - int psz = (arr.ptrs > 1) ? 4 : base_size(arr.tbase); - int sgn = (arr.ptrs == 1) && is_signed(arr.tbase); - gen_lval_addr(n); - switch (psz) { - case 1: EL(sgn ? "movsx eax, byte [eax]\n" : "movzx eax, byte [eax]\n"); break; - case 2: EL(sgn ? "movsx eax, word [eax]\n" : "movzx eax, word [eax]\n"); break; - default: EL("mov eax, [eax]\n"); break; - } - break; - } - - default: break; - } + default: break; + } } /* ══════════════════════════════════════════════════════════ STATEMENT CODE GENERATOR ══════════════════════════════════════════════════════════ */ static void gen_stmt(Node *n) { - int la, lb, lc; - switch(n->kind) { - case N_BLK: - for(int i=0;inlist;i++) gen_stmt(n->list[i]); break; - case N_ES: - gen_expr(n->ch[0]); break; - case N_LVAR: - if (n->ch[0]) { gen_expr(n->ch[0]); E(" mov "); emit_ref(n->str); E(", eax\n"); } - break; - case N_LARR: - if (n->nlist) { - int base=find_local(n->str); - /* element size for initialiser stride */ - int esz = (n->ptrs > 0) ? 4 : base_size(n->tbase); - for(int i=0;inlist;i++) { - gen_expr(n->list[i]); - int off=base+i*esz; - switch(esz) { - case 1: - if(off>0) EL("mov byte [ebp+%d], al\n",off); - else EL("mov byte [ebp%d], al\n",off); - break; - case 2: - if(off>0) EL("mov word [ebp+%d], ax\n",off); - else EL("mov word [ebp%d], ax\n",off); - break; - default: - if(off>0) EL("mov dword [ebp+%d], eax\n",off); - else EL("mov dword [ebp%d], eax\n",off); - break; - } - } - } - break; - case N_RET: - if (n->ch[0]) gen_expr(n->ch[0]); - EL("jmp .Lret%d\n", ret_lbl); break; - case N_BRK: EL("jmp .Lbrk%d\n", brk_stk[stk_top-1]); break; - case N_CONT: EL("jmp .Lcont%d\n", cont_stk[stk_top-1]); break; - case N_IF: - la=new_lbl(); lb=new_lbl(); - gen_expr(n->ch[0]); EL("test eax, eax\n"); EL("jz .L%d\n",la); - gen_stmt(n->ch[1]); EL("jmp .L%d\n",lb); - E(".L%d:\n",la); - if (n->ch[2]) gen_stmt(n->ch[2]); - E(".L%d:\n",lb); break; - case N_WHILE: - la=new_lbl(); lb=new_lbl(); - brk_stk[stk_top]=lb; cont_stk[stk_top]=la; stk_top++; - E(".Lcont%d:\n",la); - gen_expr(n->ch[0]); EL("test eax, eax\n"); EL("jz .Lbrk%d\n",lb); - gen_stmt(n->ch[1]); EL("jmp .Lcont%d\n",la); - E(".Lbrk%d:\n",lb); stk_top--; break; - case N_FOR: - la=new_lbl(); lb=new_lbl(); lc=new_lbl(); - brk_stk[stk_top]=lb; cont_stk[stk_top]=lc; stk_top++; - if (n->ch[0]) gen_stmt(n->ch[0]); - E(".L%d:\n",la); - if (n->ch[1]) { gen_expr(n->ch[1]); EL("test eax, eax\n"); EL("jz .Lbrk%d\n",lb); } - gen_stmt(n->ch[3]); - E(".Lcont%d:\n",lc); - if (n->ch[2]) gen_expr(n->ch[2]); - EL("jmp .L%d\n",la); E(".Lbrk%d:\n",lb); stk_top--; break; - case N_SW: { - lb=new_lbl(); - int ncases=n->nlist; - int *clbls=malloc(ncases*sizeof(int)); - for(int i=0;ich[0]); EL("push eax\n"); - for(int i=0;ilist[i]; - if (c->kind==N_CASE) { - EL("mov eax, [esp]\n"); - EL("cmp eax, %ld\n", c->ch[0]->num); - EL("je .L%d\n", clbls[i]); - } else { - EL("jmp .L%d\n", clbls[i]); - } - } - EL("jmp .Lbrk%d\n",lb); - for(int i=0;ilist[i]; - int ns=(c->kind==N_CASE||c->kind==N_DEF)?c->nlist:0; - for(int j=0;jlist[j]); - } - E(".Lbrk%d:\n",lb); EL("add esp, 4\n"); - stk_top--; free(clbls); break; } - default: break; + int la, lb, lc; + switch(n->kind) { + case N_BLK: + for(int i=0;inlist;i++) gen_stmt(n->list[i]); break; + case N_ES: + gen_expr(n->ch[0]); break; + case N_LVAR: + if (n->ch[0]) { gen_expr(n->ch[0]); E(" mov "); emit_ref(n->str); E(", eax\n"); } + break; + case N_LARR: + if (n->nlist) { + int base=find_local(n->str); + /* element size for initialiser stride */ + int esz = (n->ptrs > 0) ? 4 : base_size(n->tbase); + for(int i=0;inlist;i++) { + gen_expr(n->list[i]); + int off=base+i*esz; + switch(esz) { + case 1: + if(off>0) EL("mov byte [ebp+%d], al\n",off); + else EL("mov byte [ebp%d], al\n",off); + break; + case 2: + if(off>0) EL("mov word [ebp+%d], ax\n",off); + else EL("mov word [ebp%d], ax\n",off); + break; + default: + if(off>0) EL("mov dword [ebp+%d], eax\n",off); + else EL("mov dword [ebp%d], eax\n",off); + break; + } + } } + break; + case N_RET: + if (n->ch[0]) gen_expr(n->ch[0]); + EL("jmp .Lret%d\n", ret_lbl); break; + case N_BRK: EL("jmp .Lbrk%d\n", brk_stk[stk_top-1]); break; + case N_CONT: EL("jmp .Lcont%d\n", cont_stk[stk_top-1]); break; + case N_IF: + la=new_lbl(); lb=new_lbl(); + gen_expr(n->ch[0]); EL("test eax, eax\n"); EL("jz .L%d\n",la); + gen_stmt(n->ch[1]); EL("jmp .L%d\n",lb); + E(".L%d:\n",la); + if (n->ch[2]) gen_stmt(n->ch[2]); + E(".L%d:\n",lb); break; + case N_WHILE: + la=new_lbl(); lb=new_lbl(); + brk_stk[stk_top]=lb; cont_stk[stk_top]=la; stk_top++; + E(".Lcont%d:\n",la); + gen_expr(n->ch[0]); EL("test eax, eax\n"); EL("jz .Lbrk%d\n",lb); + gen_stmt(n->ch[1]); EL("jmp .Lcont%d\n",la); + E(".Lbrk%d:\n",lb); stk_top--; break; + case N_FOR: + la=new_lbl(); lb=new_lbl(); lc=new_lbl(); + brk_stk[stk_top]=lb; cont_stk[stk_top]=lc; stk_top++; + if (n->ch[0]) gen_stmt(n->ch[0]); + E(".L%d:\n",la); + if (n->ch[1]) { gen_expr(n->ch[1]); EL("test eax, eax\n"); EL("jz .Lbrk%d\n",lb); } + gen_stmt(n->ch[3]); + E(".Lcont%d:\n",lc); + if (n->ch[2]) gen_expr(n->ch[2]); + EL("jmp .L%d\n",la); E(".Lbrk%d:\n",lb); stk_top--; break; + case N_SW: { + lb=new_lbl(); + int ncases=n->nlist; + int *clbls=malloc(ncases*sizeof(int)); + for(int i=0;ich[0]); EL("push eax\n"); + for(int i=0;ilist[i]; + if (c->kind==N_CASE) { + EL("mov eax, [esp]\n"); + EL("cmp eax, %ld\n", c->ch[0]->num); + EL("je .L%d\n", clbls[i]); + } else { + EL("jmp .L%d\n", clbls[i]); + } + } + EL("jmp .Lbrk%d\n",lb); + for(int i=0;ilist[i]; + int ns=(c->kind==N_CASE||c->kind==N_DEF)?c->nlist:0; + for(int j=0;jlist[j]); + } + E(".Lbrk%d:\n",lb); EL("add esp, 4\n"); + stk_top--; free(clbls); break; } + default: break; + } } /* ══════════════════════════════════════════════════════════ LOCAL VARIABLE PRE-SCAN ══════════════════════════════════════════════════════════ */ static void scan_locals(Node *n) { - if (!n) return; - if (n->kind==N_LVAR) { - frame_size+=4; - def_local(n->str, -frame_size, n->tbase, n->ptrs); - } else if (n->kind==N_LARR) { - long cnt = n->ch[0]->num; - /* size per element */ - int esz = (n->ptrs > 0) ? 4 : base_size(n->tbase); - frame_size += esz * (int)cnt; - /* Array name decays to a pointer to its element type */ - def_local_array(n->str, -frame_size, n->tbase, n->ptrs + 1); - } else { - for(int i=0;i<4;i++) scan_locals(n->ch[i]); - for(int i=0;inlist;i++) scan_locals(n->list[i]); - } + if (!n) return; + if (n->kind==N_LVAR) { + frame_size+=4; + def_local(n->str, -frame_size, n->tbase, n->ptrs); + } else if (n->kind==N_LARR) { + long cnt = n->ch[0]->num; + /* size per element */ + int esz = (n->ptrs > 0) ? 4 : base_size(n->tbase); + frame_size += esz * (int)cnt; + /* Array name decays to a pointer to its element type */ + def_local_array(n->str, -frame_size, n->tbase, n->ptrs + 1); + } else { + for(int i=0;i<4;i++) scan_locals(n->ch[i]); + for(int i=0;inlist;i++) scan_locals(n->list[i]); + } } /* ══════════════════════════════════════════════════════════ @@ -1210,39 +1210,39 @@ static void scan_locals(Node *n) { static char called[256][64]; static int ncalled=0; static void collect_calls(Node *n) { - if (!n) return; - if (n->kind==N_CALL && n->ch[0]->kind==N_ID) { - char *nm=n->ch[0]->str; - int found=0; - for(int i=0;ich[i]); - for(int i=0;inlist;i++) collect_calls(n->list[i]); + if (!n) return; + if (n->kind==N_CALL && n->ch[0]->kind==N_ID) { + char *nm=n->ch[0]->str; + int found=0; + for(int i=0;ich[i]); + for(int i=0;inlist;i++) collect_calls(n->list[i]); } static void gen_func(Node *fn) { - nlocals=0; frame_size=0; - scan_locals(fn->ch[0]); - int fsize=(frame_size+15)&~15; + nlocals=0; frame_size=0; + scan_locals(fn->ch[0]); + int fsize=(frame_size+15)&~15; - ret_lbl=new_lbl(); - E("\n%s:\n", fn->str); - EL("push ebp\n"); EL("mov ebp, esp\n"); - if (fsize) EL("sub esp, %d\n", fsize); + ret_lbl=new_lbl(); + E("\n%s:\n", fn->str); + EL("push ebp\n"); EL("mov ebp, esp\n"); + if (fsize) EL("sub esp, %d\n", fsize); - /* Bind params: [ebp+8], [ebp+12], … with their declared types */ - int poff=8; - for(int i=0;inlist;i++) { - def_local(fn->list[i]->str, poff, - fn->list[i]->tbase, fn->list[i]->ptrs); - poff+=4; - } + /* Bind params: [ebp+8], [ebp+12], … with their declared types */ + int poff=8; + for(int i=0;inlist;i++) { + def_local(fn->list[i]->str, poff, + fn->list[i]->tbase, fn->list[i]->ptrs); + poff+=4; + } - gen_stmt(fn->ch[0]); + gen_stmt(fn->ch[0]); - E(".Lret%d:\n", ret_lbl); - EL("mov esp, ebp\n"); EL("pop ebp\n"); EL("ret\n"); + E(".Lret%d:\n", ret_lbl); + EL("mov esp, ebp\n"); EL("pop ebp\n"); EL("ret\n"); } /* ══════════════════════════════════════════════════════════ @@ -1250,25 +1250,25 @@ static void gen_func(Node *fn) { ══════════════════════════════════════════════════════════ */ /* FIX(bug2): takes explicit length; walks to p<=end to include null terminator */ static void emit_str_data(const char *s, int len) { - E("db "); - int first=1; - const char *end = s + len; /* points at the null terminator */ - for(const char *p=s; p<=end; p++) { - unsigned char c=(unsigned char)*p; - if (c>=32 && c<127 && c!='"' && c!='\\') { - if (!first) E(","); - E("\""); - while (p<=end && (unsigned char)*p>=32 && (unsigned char)*p<127 - && *p!='"' && *p!='\\') { fputc(*p,out); p++; } - p--; - E("\""); - } else { - if (!first) E(","); - E("%d", c); - } - first=0; + E("db "); + int first=1; + const char *end = s + len; /* points at the null terminator */ + for(const char *p=s; p<=end; p++) { + unsigned char c=(unsigned char)*p; + if (c>=32 && c<127 && c!='"' && c!='\\') { + if (!first) E(","); + E("\""); + while (p<=end && (unsigned char)*p>=32 && (unsigned char)*p<127 + && *p!='"' && *p!='\\') { fputc(*p,out); p++; } + p--; + E("\""); + } else { + if (!first) E(","); + E("%d", c); } - E("\n"); + first=0; + } + E("\n"); } /* ══════════════════════════════════════════════════════════ @@ -1280,154 +1280,154 @@ static void emit_str_data(const char *s, int len) { static struct { char name[64]; TKind tbase; int ptrs; } funs[MAX_FUNS]; static int nfuns=0; static void def_fun(const char *nm, TKind tbase, int ptrs) { - if (nfuns==MAX_FUNS) return; - strncpy(funs[nfuns].name, nm, 63); - funs[nfuns].tbase = tbase; - funs[nfuns].ptrs = ptrs; - nfuns++; + if (nfuns==MAX_FUNS) return; + strncpy(funs[nfuns].name, nm, 63); + funs[nfuns].tbase = tbase; + funs[nfuns].ptrs = ptrs; + nfuns++; } static Type fun_ret_type(const char *nm) { - for (int i=0;inlist;i++) { + Node *d=prog->list[i]; + if(d->kind==N_GVAR) + def_global(d->str, d->tbase, d->ptrs); + else if(d->kind==N_GARR) + def_global_array(d->str, d->tbase, d->ptrs + 1); /* array decays to pointer */ + else if(d->kind==N_FUNC || d->kind==N_FDECL) + def_fun(d->str, d->tbase, d->ptrs); /* register return type */ + } + + /* Collect defined function names */ + char defined[256][64]; int ndef=0; + for(int i=0;inlist;i++) + if(prog->list[i]->kind==N_FUNC) + strcpy(defined[ndef++], prog->list[i]->str); + + collect_calls(prog); + + E("BITS 32\n"); + E("section .text\n"); + for(int i=0;inlist;i++) + if(prog->list[i]->kind==N_FUNC) + gen_func(prog->list[i]); + + /* ── .data section: string literals + explicitly initialised globals ── */ + int has_data = (str_cnt > 0); + for(int i=0;inlist;i++) { + Node *d=prog->list[i]; + /* FIX(bug1): guard with kind==N_NUM before checking num, so N_STR/N_ID + initializers don't accidentally satisfy num==0 and leak into .bss too */ + if (d->kind==N_GVAR && d->ch[0] != NULL && + !(d->ch[0]->kind==N_NUM && d->ch[0]->num==0)) has_data=1; + if (d->kind==N_GARR && d->nlist > 0) has_data=1; + } + if (has_data) { + E("\nsection .data\n"); for(int i=0;inlist;i++) { - Node *d=prog->list[i]; - if(d->kind==N_GVAR) - def_global(d->str, d->tbase, d->ptrs); - else if(d->kind==N_GARR) - def_global_array(d->str, d->tbase, d->ptrs + 1); /* array decays to pointer */ - else if(d->kind==N_FUNC || d->kind==N_FDECL) - def_fun(d->str, d->tbase, d->ptrs); /* register return type */ + Node *d=prog->list[i]; + /* scalar global with non-zero initialiser */ + if(d->kind==N_GVAR && d->ch[0] != NULL && + !(d->ch[0]->kind==N_NUM && d->ch[0]->num==0)) { + const char *dw = d->ptrs ? "dd" : + (base_size(d->tbase)==1?"db":base_size(d->tbase)==2?"dw": + base_size(d->tbase)==8?"dq":"dd"); + if (d->ch[0]->kind == N_NUM) { + long v = d->ch[0]->num; + E("%s: %s %ld\n", d->str, dw, v); + } else if (d->ch[0]->kind == N_STR) { + /* FIX(bug2): use length-aware intern for global string inits */ + int id = intern_str_n(d->ch[0]->str, d->ch[0]->slen); + E("%s: %s _s%d\n", d->str, dw, id); + } else if (d->ch[0]->kind == N_ID) { + E("%s: %s %s\n", d->str, dw, d->ch[0]->str); + } + } + /* global array with explicit initialiser */ + if(d->kind==N_GARR && d->nlist > 0) { + long cnt = d->ch[0]->num; + const char *dw = d->ptrs ? "dd" : + (base_size(d->tbase)==1?"db":base_size(d->tbase)==2?"dw": + base_size(d->tbase)==8?"dq":"dd"); + E("%s: %s", d->str, dw); + for(int j=0; jnlist; j++) + E("%s%ld", j ? "," : " ", d->list[j]->num); + for(long j=d->nlist; j 0 || d->nlist > 0) ? "," : " "); + E("\n"); + } } - - /* Collect defined function names */ - char defined[256][64]; int ndef=0; - for(int i=0;inlist;i++) - if(prog->list[i]->kind==N_FUNC) - strcpy(defined[ndef++], prog->list[i]->str); - - collect_calls(prog); - - E("BITS 32\n"); - E("section .text\n"); - for(int i=0;inlist;i++) - if(prog->list[i]->kind==N_FUNC) - gen_func(prog->list[i]); - - /* ── .data section: string literals + explicitly initialised globals ── */ - int has_data = (str_cnt > 0); + /* ── .bss section: zero-init scalars and uninitialised arrays ── */ + int has_bss = 0; + for(int i=0;inlist;i++) { + Node *d=prog->list[i]; + /* FIX(bug1): check kind==N_NUM before num==0, so string/id inits + don't produce a duplicate symbol in both .data and .bss */ + if (d->kind==N_GVAR && (!d->ch[0] || (d->ch[0]->kind==N_NUM && d->ch[0]->num==0))) has_bss=1; + if (d->kind==N_GARR && d->nlist == 0) has_bss=1; + } + if (has_bss) { + E("\nsection .bss\n"); for(int i=0;inlist;i++) { - Node *d=prog->list[i]; - /* FIX(bug1): guard with kind==N_NUM before checking num, so N_STR/N_ID - initializers don't accidentally satisfy num==0 and leak into .bss too */ - if (d->kind==N_GVAR && d->ch[0] != NULL && - !(d->ch[0]->kind==N_NUM && d->ch[0]->num==0)) has_data=1; - if (d->kind==N_GARR && d->nlist > 0) has_data=1; - } - if (has_data) { - E("\nsection .data\n"); - for(int i=0;inlist;i++) { - Node *d=prog->list[i]; - /* scalar global with non-zero initialiser */ - if(d->kind==N_GVAR && d->ch[0] != NULL && - !(d->ch[0]->kind==N_NUM && d->ch[0]->num==0)) { - const char *dw = d->ptrs ? "dd" : - (base_size(d->tbase)==1?"db":base_size(d->tbase)==2?"dw": - base_size(d->tbase)==8?"dq":"dd"); - if (d->ch[0]->kind == N_NUM) { - long v = d->ch[0]->num; - E("%s: %s %ld\n", d->str, dw, v); - } else if (d->ch[0]->kind == N_STR) { - /* FIX(bug2): use length-aware intern for global string inits */ - int id = intern_str_n(d->ch[0]->str, d->ch[0]->slen); - E("%s: %s _s%d\n", d->str, dw, id); - } else if (d->ch[0]->kind == N_ID) { - E("%s: %s %s\n", d->str, dw, d->ch[0]->str); - } - } - /* global array with explicit initialiser */ - if(d->kind==N_GARR && d->nlist > 0) { - long cnt = d->ch[0]->num; - const char *dw = d->ptrs ? "dd" : - (base_size(d->tbase)==1?"db":base_size(d->tbase)==2?"dw": - base_size(d->tbase)==8?"dq":"dd"); - E("%s: %s", d->str, dw); - for(int j=0; jnlist; j++) - E("%s%ld", j ? "," : " ", d->list[j]->num); - for(long j=d->nlist; j 0 || d->nlist > 0) ? "," : " "); - E("\n"); - } - } - /* FIX(bug2): pass length to emit_str_data */ - for(int i=0;inlist;i++) { - Node *d=prog->list[i]; - /* FIX(bug1): check kind==N_NUM before num==0, so string/id inits - don't produce a duplicate symbol in both .data and .bss */ - if (d->kind==N_GVAR && (!d->ch[0] || (d->ch[0]->kind==N_NUM && d->ch[0]->num==0))) has_bss=1; - if (d->kind==N_GARR && d->nlist == 0) has_bss=1; - } - if (has_bss) { - E("\nsection .bss\n"); - for(int i=0;inlist;i++) { - Node *d=prog->list[i]; - /* FIX(bug1): same guard as has_bss check above */ - if(d->kind==N_GVAR && (!d->ch[0] || (d->ch[0]->kind==N_NUM && d->ch[0]->num==0))) { - const char *rs = d->ptrs ? "resd" : - (base_size(d->tbase)==1?"resb":base_size(d->tbase)==2?"resw": - base_size(d->tbase)==8?"resq":"resd"); - E("%s: %s 1\n", d->str, rs); - } - if(d->kind==N_GARR && d->nlist == 0) { - long cnt = d->ch[0]->num; - const char *rs = d->ptrs ? "resd" : - (base_size(d->tbase)==1?"resb":base_size(d->tbase)==2?"resw": - base_size(d->tbase)==8?"resq":"resd"); - E("%s: %s %ld\n", d->str, rs, cnt); - } - } + Node *d=prog->list[i]; + /* FIX(bug1): same guard as has_bss check above */ + if(d->kind==N_GVAR && (!d->ch[0] || (d->ch[0]->kind==N_NUM && d->ch[0]->num==0))) { + const char *rs = d->ptrs ? "resd" : + (base_size(d->tbase)==1?"resb":base_size(d->tbase)==2?"resw": + base_size(d->tbase)==8?"resq":"resd"); + E("%s: %s 1\n", d->str, rs); + } + if(d->kind==N_GARR && d->nlist == 0) { + long cnt = d->ch[0]->num; + const char *rs = d->ptrs ? "resd" : + (base_size(d->tbase)==1?"resb":base_size(d->tbase)==2?"resw": + base_size(d->tbase)==8?"resq":"resd"); + E("%s: %s %ld\n", d->str, rs, cnt); + } } + } } /* ══════════════════════════════════════════════════════════ MAIN ══════════════════════════════════════════════════════════ */ static char *read_file(const char *path) { - FILE *f=fopen(path,"r"); - if(!f) die("cannot open: %s", path); - fseek(f,0,SEEK_END); long sz=ftell(f); rewind(f); - char *buf=malloc(sz+1); - fread(buf,1,sz,f); buf[sz]=0; fclose(f); - return buf; + FILE *f=fopen(path,"r"); + if(!f) die("cannot open: %s", path); + fseek(f,0,SEEK_END); long sz=ftell(f); rewind(f); + char *buf=malloc(sz+1); + fread(buf,1,sz,f); buf[sz]=0; fclose(f); + return buf; } int main(int argc, char **argv) { - if (argc<2) { fprintf(stderr,"usage: %s [out.asm]\n",argv[0]); return 1; } - char *source = read_file(argv[1]); - src=source; src_pos=0; - Node *prog = parse_prog(); - out = (argc>=3) ? fopen(argv[2],"w") : stdout; - if (!out) die("cannot open output: %s", argv[2]); - codegen(prog); - if (argc>=3) { fclose(out); fprintf(stderr,"wrote %s\n",argv[2]); } - return 0; + if (argc<2) { fprintf(stderr,"usage: %s [out.asm]\n",argv[0]); return 1; } + char *source = read_file(argv[1]); + src=source; src_pos=0; + Node *prog = parse_prog(); + out = (argc>=3) ? fopen(argv[2],"w") : stdout; + if (!out) die("cannot open output: %s", argv[2]); + codegen(prog); + if (argc>=3) { fclose(out); fprintf(stderr,"wrote %s\n",argv[2]); } + return 0; }