C言語の自作コンパイラを作成しているのですが、変数に値を格納した後、その値を表示する際に代入した変数名も同時にプロンプトに表示されるようにしたいです。以下に関連ファイルと実行例を記載します。また、表示量を減らすために必要のないであろう範囲は省略しました。
lex
alpha [a-zA-Z] digit [0-9] white [\n\t ] %% while { return WHILE; } if { return IF; } do { return DO; } // ここも正しいか不明 read { return READ; } print { return PRINT; } {alpha}({alpha}|{digit})* { return IDENT; } {digit}+ { return NUM; } [-+()=;{}<>*/%] { return yytext[0]; } {white} { ; }
yacc
%token NUM; %token IDENT; %token READ; %token PRINT; %left '+' '-'; %left '*' '/'; %% prog : IDENT '{' stlist'}' { dotree($3); return 0; } ; stlist : { $$ = 0; } | stlist stat { $$ = node(T_STLIST, $1, $2); } ; stat :var '=' expr ';' { $$ = node(T_ASSIGN, $1, $3); } | READ var ';' { $$ = node(T_READ, $2, 0); } | PRINT expr ';' { $$ = node(T_PRINT, $2, 0); } | '{' stlist '}' { $$ = $2; } ; cond : expr '<' expr { $$ = node(T_LT, $1, $3); } | expr '>' expr { $$ = node(T_GT, $1, $3); } ; expr : term { $$ = $1; } | expr '+' term { $$ = node(T_ADD, $1, $3); } | expr '-' term { $$ = node(T_SUB, $1, $3); } ; term: prim{ $$ = $1; } | term '*' prim { $$ = node(T_MUL, $1, $3); } | term '/' prim { $$ = node(T_DIV, $1, $3); } | term '%' prim { $$ = node(T_REM, $1, $3); } ; prim : NUM { $$ = node(T_NUM, atoi(yytext), 0); } | var { $$ = node(T_VAR, $1, 0); } | '(' expr ')' { $$ = $2; } ; var : IDENT { $$ = lookup(yytext); } ;
C
#include <stdio.h>struct stab { int val; char name[20]; } stab[100];int stabuse = 0;struct node { int type, left, right; } ntab[400];int ntabuse = 1;#define T_STLIST 1#define T_ASSIGN 2#define T_READ 3#define T_PRINT 4#define T_ADD 5#define T_REM 9#define T_NUM 10#define T_VAR 11#define T_LT 14#define T_GT 15int lookup(char*);int node(int, int, int);void dotree(int);extern char *yytext;#include "y.tab.c"#include "lex.yy.c" int main() { yyparse(); return 0;}int lookup(char *s) { int i; for(i = 0; i < stabuse; ++i) if(strcmp(stab[i].name, s) == 0) return i; if(stabuse >= 99) { printf("table overflow.\n"); exit(1); } strcpy(stab[stabuse].name, s); return stabuse++;}int node(int t, int l, int r) { int i = ntabuse++; ntab[i].type = t; ntab[i].left = l; ntab[i].right = r; return i;}void dotree(int i) { int stk; printf(" .section .rodata\n"); printf(".Lprompt: .string\"> \"\n"); /* ここの変更が必要、、、? printf(".Lread: .string\"%%ld\"\n"); printf(".Lprint: .string\"%%ld\\n\"\n"); printf(" .text\n"); printf(".global main\n"); printf("main:\n"); printf(" pushq %%rbp\n"); printf(" movq %%rsp,%%rbp\n"); stk = (8*stabuse + 15) / 16; stk *= 16; printf(" subq $%d,%%rsp\n", stk); emittree(i); printf(" leave\n"); printf(" ret\n"); } void emittree(int i) { static int labelno = 1; int l; switch(ntab[i].type) { case T_STLIST: if(ntab[i].left) emittree(ntab[i].left); emittree(ntab[i].right); break; case T_READ: printf(" movq $.Lprompt,%%rdi\n"); printf(" movq $0,%%rax\n"); /* 浮動小数点レジスタを使わない */ printf(" call printf\n"); printf(" leaq %d(%%rbp),%%rsi\n", -(ntab[i].left+1)*8); printf(" movq $.Lread,%%rdi\n"); printf(" movq $0,%%rax\n"); /* 浮動小数点レジスタを使わない */ printf(" call scanf\n"); break; case T_PRINT: emittree(ntab[i].left); printf(" popq %%rsi\n"); printf(" movq $.Lprint,%%rdi\n"); printf(" movq $0,%%rax\n"); /* 浮動小数点レジスタを使わない */ printf(" call printf\n"); break; case T_NUM: printf(" pushq $%d\n", ntab[i].left); break; case T_VAR: printf(" pushq %d(%%rbp)\n", -(ntab[i].left+1)*8); break; default: printf("NotImplemented: %d\n", ntab[i].type); break; case T_ASSIGN: emittree(ntab[i].right); printf(" popq %d(%%rbp)\n", -(ntab[i].left+1)*8); break; case T_ADD: emittree(ntab[i].left); emittree(ntab[i].right); printf(" popq %%rdx\n"); printf(" popq %%rax\n"); printf(" addq %%rdx,%%rax\n"); printf(" pushq %%rax\n"); break; case T_REM: emittree(ntab[i].left); emittree(ntab[i].right); printf(" popq %%rsp\n"); printf(" popq %%rax\n"); printf(" movq $0,%%rdx\n"); printf(" idivq %%rsp\n"); printf(" pushq %%rdx\n"); case T_LT: emittree(ntab[i].left); emittree(ntab[i].right); printf(" popq %%rcx\n"); printf(" popq %%rax\n"); printf(" cmp %%rcx,%%rax\n"); printf(" jge "); break; case T_GT: emittree(ntab[i].left); emittree(ntab[i].right); printf(" popq %%rcx\n"); printf(" popq %%rax\n"); printf(" cmp %%rcx,%%rax\n"); printf(" jle "); break; }}
ここから下は実行ファイルとその実行例です。
example.c
main { read x; read yee; print x; print x + yee; print yee; }
a.out
>./a.out x> 4 // readでxに代入 yee> 5 // readでxに代入 x=4 // 代入した変数と同時に値を表示 9 // 代入した変数がない場合は無表示 yee=5 // 代入した変数と同時に値を表示
変更すべき範囲がどのあたりなのかも検討がつかないので、ご教授いただけると幸いです。
0 コメント