📄 vtc.y
字号:
%{/* vtc.y: VTC compiler and lexical analyzer */#include "vt.h"String ptext;int debug = 0;extern int iwidth[];#define ERR_PRMTNAME "Primitive name used as function name"#define ERR_RESERVED "Reserved word used as identifier"#define ERR_DUPGOTO "Duplicate goto label"#define ERR_MISBREAK "Misplaced break statement"#define ERR_MISCONT "Misplaced continue statement"#define ERR_DUPTAG "Duplicate parameter or local variable name"#define ERR_UDGOTO "One or more goto labels not defined"#define ERR_TOOMANY "Too many parameters or local variables"#define ERR_UNTERMCHAR "Unterminated character constant"#define ERR_UNTERMSTR "Unterminated string constant"#define ERR_BADBRACE "Illegal placement of right brace"#define ERR_ILLFUNC "Illegal placement of reserved word func"/* The intermediate program */#define INIT_CODE 256static Instr *icode;static int loc = 0, codesize;#define Check_code(n) Check(icode, Instr, codesize, loc + (n))#define Hexdigitvalue(a) (isdigit(a) ? a - '0' : ucase(a) - 'A' + 10)#define Code(t) if (1) { Check_code(1); icode[loc++].type = t; } else#define Code2(t, elem, val) if (1) { Check_code(2); icode[loc++].type = t; \ icode[loc++].elem = val; } else#define Code_iconst(val) Code2(I_ICONST, iconst, val)#define Code_pcall(pn, ac) if (1) { Check_code(2); \ icode[loc++].type = I_PCALL; \ icode[loc].pc.pnum = pn; \ icode[loc++].pc.argc = ac; } else#define Code_fcall(id, ac) if (1) { Check_code(2); \ icode[loc++].type = I_FCALL; \ icode[loc++].argc = ac; \ icode[loc++].ident = id; } elsetypedef struct label { char *name; int offset; struct label *next;} Label;#define MAXILEN 32static Label *lhead = NULL;#ifdef PROTOTYPESstatic void code_var(char *);static void code_goto(char *, int);static void free_labels(void);static void add_tag(char **, int *, char *);static int find_tag(char **, int, char *);static char *parse_token(char *);static int read_char(char **);static int enter_sconst(Cstr);static char *read_string(char *);static char *read_comment(char *);static void compile(void);static void scan(void);static void cleanup_parse();static void lexerror(char *);static void yyerror(char *);static int yylex(void);#elsestatic void compile(), scan(), cleanup_parse(), lexerror(), yyerror();static void code_var(), free_labels(), add_tag(), code_goto();static char *parse_token(), *read_string(), *read_comment();#endif#define INIT_JMP 64#define INIT_COND 16int *jmptab, jmpsize, jmppos;int *condstack, condsize, condpos;int *loopstack, loopsize, looppos;#define Incjmp(n) Check(jmptab, int, jmpsize, jmppos += (n))#define Pushcond(x) Push(condstack, int, condsize, condpos, x)#define Pushloop(x) Push(loopstack, int, loopsize, looppos, x)#define Peekloop (loopstack[looppos - 1])#define Incloop(n) if (1) { Pushloop(jmppos); Incjmp(n); } else#define Decloop looppos--#define Ljmp(l, t) Code2(t, offset, Peekloop + (l))#define Ldest(l) (jmptab[Peekloop + (l)] = loc)#define Break if (looppos) Code2(I_JMP, offset, Peekloop + 1); \ else yyerror(ERR_MISBREAK)#define Continue if (looppos) Code2(I_JMP, offset, Peekloop); \ else yyerror(ERR_MISCONT)#define Jmp(t) if (1) { Pushcond(jmppos); Code2(t, offset, jmppos); \ Incjmp(1); } else#define Dest (jmptab[condstack[--condpos]] = loc)#define Destnext (jmptab[condstack[--condpos]] = loc + 2)#define Return Code2(I_JMP, offset, 0)/* Local vars and array vars */#define MAX_TAGS 32static char *lvars[MAX_TAGS], *avars[MAX_TAGS];static int lvarc = 0, avarc = 0, reqargs = 0;static int lexline = -1; /* Line being analyzed */static int parseline = -1; /* Line being parsed */static int errflag; /* Error flag */static char *curfunc = ""; /* Name of current function */static char *curfile = ""; /* Name of current file */extern Prmt prmtab[];#define OP_BOR 0#define OP_BXOR 1#define OP_BAND 2#define OP_EQ 3#define OP_NE 4#define OP_LT 5#define OP_LE 6#define OP_GT 7#define OP_GE 8#define OP_SL 9#define OP_SR 10#define OP_ADD 11#define OP_SUB 12#define OP_MULT 13#define OP_DIV 14#define OP_MOD 15#define OP_POSTINC 16#define OP_POSTDEC 17#define OP_PREINC 18#define OP_PREDEC 19#define OP_NOT 20#define OP_COMPL 21#define OP_NEG 22#define OP_ASN 23#define PR_LOOKUP 102%}%union { int num; int index; void (*bobj)(); int str; char *s;}%token <num> ICONST%token <str> SCONST%token <bobj> BOBJ%token <s> IDENT%token FUNC FASSIGN DO WHILE IF ELSE FOR GOTO BREAK CONTINUE RETURN%type <num> exprv args asn_op%type <s> unreserved%left ';'%left ','%right '=' TA DA MA AA SA SLA SRA BAA BXA BOA CONDA%right '?' ':'%right DEREF%left OR%left AND%left '|'%left '^'%left '&'%left EQ NE%left '<' LE '>' GE%left SL SR%left '+' '-'%left '*' '/' '%'%right '!' '~' INC DEC%left '(' ')' '[' ']'%%directive : fdecl FASSIGN expr | fdecl tdecl compound { Code(I_NULL); } | tdecl command { Code(I_NULL); } ;command : stmt | command stmt ;fdecl : FUNC unreserved adecl { curfunc = $2; if (find_prmt($2) != -1) yyerror(ERR_PRMTNAME); } ;adecl : '(' optargs ')' | '(' params { reqargs = avarc; } optargs ')'tdecl : /* nothing */ | '[' ']' | '[' locals ']' ;optargs : /* nothing */ | '/' params ;params : unreserved { add_tag(avars, &avarc, $1); } | params ',' unreserved { add_tag(avars, &avarc, $3); } ;locals : unreserved { add_tag(lvars, &lvarc, $1); } | locals ',' unreserved { add_tag(lvars, &lvarc, $3); } ;post : postlval { Code(I_EVAL); } | postfix ;postlval: IDENT { code_var($1); } | BOBJ { Code2(I_BOBJ, bobj, $1); } | post DEREF IDENT { Code2(I_SCONST, sindex, enter_sconst(cstr_s($3))); Code_pcall(PR_LOOKUP, 2); } | post '[' expr ']' { Code_pcall(OP_ADD, 2); } | post '[' ICONST ']' { if ($3) { Code_iconst($3); Code_pcall(OP_ADD, 2); } } | '(' lval ')' ;lval : postlval | '*' unary ;atom : ICONST { Code_iconst($1); } | SCONST { Code2(I_SCONST, sindex, $1); } | '.' unreserved { int ind = find_prmt($2); if (ind != -1) Code2(I_PPTR, pnum, ind); else Code2(I_FPTR, ident, $2); } | IDENT '(' args ')' { int ind = find_prmt($1); if (ind != -1) Code_pcall(ind, $3); else Code_fcall($1, $3); } | '(' lval ')' '(' args ')' { Code2(I_EXEC, argc, $5); } | '(' expr ')' ;/* Can occur before [] */postfix : atom | postlval INC { Code_pcall(OP_POSTINC, 1); } | postlval DEC { Code_pcall(OP_POSTDEC, 1); } ;unary : postfix | lval { Code(I_EVAL); } | INC lval { Code_pcall(OP_PREINC, 1); } | DEC lval { Code_pcall(OP_PREDEC, 1); } | '!' unary { Code_pcall(OP_NOT, 1); } | '~' unary { Code_pcall(OP_COMPL, 1); } | '-' unary { Code_pcall(OP_NEG, 1); } | '+' unary | '&' lval ;binary : unary | binary OR { Code(I_CVTB); Jmp(I_JMPPT); } binary { Code(I_CVTB); Dest; } | binary AND { Code(I_CVTB); Jmp(I_JMPPF); } binary { Code(I_CVTB); Dest; } | binary '|' binary { Code_pcall(OP_BOR, 2); } | binary '^' binary { Code_pcall(OP_BXOR, 2); } | binary '&' binary { Code_pcall(OP_BAND, 2); } | binary EQ binary { Code_pcall(OP_EQ, 2); } | binary NE binary { Code_pcall(OP_NE, 2); } | binary '<' binary { Code_pcall(OP_LT, 2); } | binary LE binary { Code_pcall(OP_LE, 2); } | binary '>' binary { Code_pcall(OP_GT, 2); } | binary GE binary { Code_pcall(OP_GE, 2); } | binary SL binary { Code_pcall(OP_SL, 2); } | binary SR binary { Code_pcall(OP_SR, 2); } | binary '+' binary { Code_pcall(OP_ADD, 2); } | binary '-' binary { Code_pcall(OP_SUB, 2); } | binary '*' binary { Code_pcall(OP_MULT, 2); } | binary '/' binary { Code_pcall(OP_DIV, 2); } | binary '%' binary { Code_pcall(OP_MOD, 2); } | binary '?' { Jmp(I_JMPF); } binary ':' { Destnext; Jmp(I_JMP); } binary { Dest; } | binary '?' ':' { Jmp(I_JMPPT); } binary { Dest; } ;assign : binary | lval '=' assign { Code_pcall(OP_ASN, 2); } | lval asn_op { Code(I_DUP); Code(I_EVAL); } assign { Code_pcall($2, 2); Code_pcall(OP_ASN, 2); } | lval CONDA { Code(I_DUP); Code(I_EVAL); Jmp(I_JMPPT); } assign { Dest; Code_pcall(OP_ASN, 2); } ;asn_op : TA { $$ = OP_MULT; } | DA { $$ = OP_DIV; } | MA { $$ = OP_MOD; } | AA { $$ = OP_ADD; } | SA { $$ = OP_SUB; } | SLA { $$ = OP_SL; } | SRA { $$ = OP_SR; } | BAA { $$ = OP_BAND; } | BXA { $$ = OP_BXOR; } | BOA { $$ = OP_BOR; } ;/* Expression, value equal to last assignment-expression */expr : assign | expr ',' { Code(I_POP); } assign ;/* List of assignment-expressions, retaining values (arg list) */exprv : assign { $$ = 1; } | exprv ',' assign { $$ = $1 + 1; } ;args : /* nothing */ { $$ = 0; } | exprv ;/* Optional expression, no value */oexprn : /* nothing */ | expr { Code(I_POP); } ;/* Optional expression with value */oexprv : /* nothing */ { Code_iconst(1); } | expr ;compound: '{' stmtlist '}' ;stmtlist: /* nothing */ | stmtlist stmt ;ifcond : IF '(' expr ')' { Jmp(I_JMPF); } ;stmt : compound | oexprn ';' | ifcond stmt { Dest; } | ifcond stmt ELSE { Destnext; Jmp(I_JMP); } stmt { Dest; } | WHILE { Incloop(2); Ldest(0); } '(' expr ')' { Ljmp(1, I_JMPF); } stmt { Ljmp(0, I_JMP); Ldest(1); Decloop; } | DO { Incloop(3); Ldest(2); } stmt { Ldest(0); } WHILE '(' expr ')' { Ljmp(2, I_JMPT); Ldest(1); Decloop; } | FOR '(' oexprn ';' { Incloop(4); Ldest(3); } oexprv ';' { Ljmp(1, I_JMPF); Ljmp(2, I_JMP); Ldest(0); } oexprn ')' { Ljmp(3, I_JMP); Ldest(2); } stmt { Ljmp(0, I_JMP); Ldest(1); Decloop; } | IDENT ':' { code_goto($1, 0); } stmt | GOTO IDENT ';' { code_goto($2, 1); } | BREAK ';' { Break; } | CONTINUE ';' { Continue; } | RETURN ';' { Code(I_NULL); Return; } | RETURN expr ';' { Return; } ;/* Error if identifier is reserved */unreserved : IDENT | reserved { yyerror(ERR_RESERVED); $$ = ""; } ;reserved : BOBJ | DO | WHILE | IF | ELSE | FOR | FUNC | GOTO | BREAK | CONTINUE | RETURN | ICONST ;%%/* Auxiliary compiler functions */static void code_var(ident) char *ident;{ int tag; if ((tag = find_tag(avars, avarc, ident)) != -1) Code2(I_AVAR, tnum, tag); else if ((tag = find_tag(lvars, lvarc, ident)) != -1) Code2(I_LVAR, tnum, tag); else Code2(I_GVAR, ident, ident);}static void code_goto(name, to) char *name; int to;{ Label *label; for (label = lhead; label; label = label->next) { if (streq(label->name, name)) { if (to) Code2(I_JMP, offset, label->offset); else if (jmptab[label->offset] == -1) jmptab[label->offset] = loc; else yyerror(ERR_DUPGOTO); return; } } label = New(Label); label->name = name; label->offset = jmppos; Push(jmptab, int, jmpsize, jmppos, to ? -1 : loc); if (to) Code2(I_JMP, offset, label->offset); label->next = lhead; lhead = label;}static void free_labels(){ Label *label = lhead, *next; for (label = lhead; label; label = next) { next = label->next; if (jmptab[label->offset] == -1) yyerror(ERR_UDGOTO); Discard(label, Label); } lhead = NULL;}static void add_tag(table, pos, tag) char *table[], *tag; int *pos;{ int i; for (i = 0; i < *pos; i++) { if (!strcmp(table[i], tag)) { yyerror(ERR_DUPTAG); return; } } if (*pos == MAX_TAGS) yyerror(ERR_TOOMANY); else table[(*pos)++] = tag;}static int find_tag(table, num, ident) char *table[], *ident; int num;{ int i; for (i = 0; i < num; i++) { if (streq(table[i], ident)) return i; } return -1;}/* The lexical analyzer */typedef struct token { int type; YYSTYPE val;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -