%{ #include #include #include #include #include #include #include "ast.h" Program p; int yylex(void); void yyerror(char *msg,...); int errcnt; int yylineno; FILE *ast_fp; #define MAXCHAR 255 char lexeme[MAXCHAR+1]; /* current lexeme */ %} %token BODYDEF VARDECS TYPEDECS PROCDECS VARDEC TYPEDEC PROCDEC NAMEDTYP ARRAYTYP RECORDTYP NOTYP %token COMP PARAM ASSIGNST CALLST READST WRITEST IFST WHILEST LOOPST FORST EXITST RETST SEQST %token BINOPEXP UNOPEXP LVALEXP CALLEXP ARRAYEXP RECORDEXP INTCONST REALCONST STRINGCONST ARRAYINIT %token RECORDINIT VAR ARRAYDEREF RECORDDEREF %token ID %token STRING %token INTEGER %token BINOP %token UNOP %type program %type body %type declarationsL %type declarations %type var_decL %type var_dec %type type_decL %type type_dec %type compL %type comp %type proc_decL %type proc_dec %type type %type formal_paramL %type formal_param %type statement %type statementL %type expression %type expressionL %type array_init %type array_initL %type record_init %type record_initL %type lvalue %type lvalueL %type line %union { id id; string string; int ivalue; double rvalue; binop binop; unop unop; Program program; Body body; DecList declist; Dec dec; VarDecList vardeclist; VarDec vardec; TypeDecList typedeclist; TypeDec typedec; ComponentList componentlist; Component component; ProcDecList procdeclist; ProcDec procdec; Type type; FormalParamList formalparamlist; FormalParam formalparam; Stat stat; StatList statlist; Exp exp; ExpList explist; ArrayInit arrayinit; ArrayInitList arrayinitlist; RecordInit recordinit; RecordInitList recordinitlist; Lvalue lvalue; LvalueList lvaluelist; } %start program %% program : body {p = $$ = mk_Program($1);} ; body : '(' BODYDEF line '(' declarationsL ')' statement ')' {$$ = mk_Body($3,$5,$7);} ; declarationsL: {$$ = NULL;} | declarations declarationsL {$$ = mk_DecList($1,$2);} ; declarations : '(' VARDECS '(' var_decL ')' ')' {$$ = mk_VarDecs($4);} | '(' TYPEDECS '(' type_decL ')' ')' {$$ = mk_TypeDecs($4);} | '(' PROCDECS '(' proc_decL ')' ')' {$$ = mk_ProcDecs($4);} ; var_decL : {$$ = NULL;} | var_dec var_decL {$$ = mk_VarDecList($1,$2);} ; var_dec : '(' VARDEC line ID type expression ')' {$$ = mk_VarDec($3,$4,$5,$6);} ; type_decL : {$$ = NULL;} | type_dec type_decL {$$ = mk_TypeDecList($1,$2);} ; type_dec : '(' TYPEDEC line ID type ')' {$$ = mk_TypeDec($3,$4,$5);} ; proc_decL : {$$ = NULL;} | proc_dec proc_decL {$$ = mk_ProcDecList($1,$2);} ; proc_dec : '(' PROCDEC line ID '(' formal_paramL ')' type body ')' {$$ = mk_ProcDec($3,$4,$6,$8,$9);} ; type : '(' NAMEDTYP line ID ')' {$$ = mk_NamedType($3,$4);} | '(' ARRAYTYP line type ')' {$$ = mk_ArrayType($3,$4);} | '(' RECORDTYP line '(' compL ')' ')' {$$ = mk_RecordType($3,$5);} | '(' NOTYP ')' {$$ = NULL;} ; compL : {$$ = NULL;} | comp compL {$$ = mk_ComponentList($1,$2);} ; comp : '(' COMP line ID type ')' {$$ = mk_Component($3,$4,$5);} ; formal_paramL : {$$ = NULL;} | formal_param formal_paramL {$$ = mk_FormalParamList($1,$2);} ; formal_param : '(' PARAM line ID type ')' {$$ = mk_FormalParam($3,$4,$5);} ; statement : '(' ASSIGNST line lvalue expression ')' {$$ = mk_AssignStat($3,$4,$5);} | '(' CALLST line ID '(' expressionL ')' ')' {$$ = mk_CallStat($3,$4,$6);} | '(' READST line '(' lvalueL ')' ')' {$$ = mk_ReadStat($3,$5);} | '(' WRITEST line '(' expressionL ')' ')' {$$ = mk_WriteStat($3,$5);} | '(' IFST line expression statement statement ')' {$$ = mk_IfStat($3,$4,$5,$6);} | '(' WHILEST line expression statement ')' {$$ = mk_WhileStat($3,$4,$5);} | '(' LOOPST line statement ')' {$$ = mk_LoopStat($3,$4);} | '(' FORST line ID expression expression expression statement ')' {$$ = mk_ForStat($3,$4,$5,$6,$7,$8);} | '(' EXITST line ')' {$$ = mk_ExitStat($3);} | '(' RETST line expression ')' {$$ = mk_RetStat($3,$4);} | '(' RETST line ')' {$$ = mk_RetStat($3,NULL);} | '(' SEQST '(' statementL ')' ')' {$$ = mk_SeqStat($4);} ; statementL : {$$ = NULL;} | statement statementL {$$ = mk_StatList($1,$2);} ; expression : '(' BINOPEXP line BINOP expression expression ')' {$$ = mk_BinOpExp($3,$4,$5,$6);} | '(' UNOPEXP line UNOP expression ')' {$$ = mk_UnOpExp($3,$4,$5);} | '(' LVALEXP lvalue ')' {$$ = mk_LvalExp(0,$3);} | '(' CALLEXP line ID '(' expressionL ')' ')' {$$ = mk_CallExp($3,$4,$6);} | '(' RECORDEXP line ID '(' record_initL ')' ')' {$$ = mk_RecordExp($3,$4,$6);} | '(' ARRAYEXP line ID '(' array_initL ')' ')' {$$ = mk_ArrayExp($3,$4,$6);} | '(' INTCONST line INTEGER ')' {$$ = mk_IntConstExp($3,$4);} | '(' REALCONST line STRING ')' {$$ = mk_RealConstExp($3,$4);} | '(' STRINGCONST line STRING ')' {$$ = mk_StringConstExp($3,$4);} ; expressionL : {$$ = NULL;} | expression expressionL {$$ = mk_ExpList($1,$2);} ; array_init : '(' ARRAYINIT expression expression ')' {$$ = mk_ArrayInit($3,$4);} ; array_initL : {$$ = NULL;} | array_init array_initL {$$ = mk_ArrayInitList($1,$2);} ; record_init : '(' RECORDINIT ID expression ')' {$$ = mk_RecordInit($3,$4);} ; record_initL : {$$ = NULL;} | record_init record_initL {$$ = mk_RecordInitList($1,$2);} ; lvalue : '(' VAR line ID ')' {$$ = mk_VarLvalue($3,$4);} | '(' ARRAYDEREF line lvalue expression ')' {$$ = mk_ArrayDerefLvalue($3,$4,$5);} | '(' RECORDDEREF line lvalue ID ')' {$$ = mk_RecordDerefLvalue($3,$4,$5);} ; lvalueL : {$$ = NULL;} | lvalue lvalueL {$$ = mk_LvalueList($1,$2);} ; line : INTEGER {$$ = $1;} ; %% void yyerror(char *msg, ...) { va_list args; va_start(args,msg); errcnt++; fprintf(stderr, "AST error line %d :", yylineno); vfprintf(stderr, msg, args); fprintf(stderr,"\n"); va_end(args); } /* Lexing routines. */ /* Utility routine to append to end of current lexeme, checking for overflow.*/ void append(char x,int i) { if (i >= MAXCHAR) { lexeme[MAXCHAR] = '\0'; yyerror("Token too long:\n%s",lexeme); }; lexeme[i] = x; } /* Order of these must agree with %token declarations in yacc spec above, and these must be the first %token's declared. */ char *nodes[] = {"BodyDef", "VarDecs", "TypeDecs", "ProcDecs", "VarDec", "TypeDec", "ProcDec", "NamedTyp", "ArrayTyp", "RecordTyp", "NoTyp", "Comp", "Param", "AssignSt", "CallSt", "ReadSt", "WriteSt", "IfSt", "WhileSt", "LoopSt", "ForSt", "ExitSt", "RetSt", "SeqSt", "BinOpExp", "UnOpExp", "LvalExp", "CallExp", "ArrayExp", "RecordExp", "IntConst", "RealConst", "StringConst", "ArrayInit", "RecordInit", "Var", "ArrayDeref", "RecordDeref"}; /* Order of these must agree with enum declaration in ast.h */ char *binops[] = {"GT","LT","EQ","GE","LE","NE","PLUS","MINUS","TIMES","SLASH", "DIV","MOD","AND","OR"}; char *unops[] = {"UPLUS","UMINUS","NOT"}; int yylex() { int c; int i; while (1) { c = getc(ast_fp); if (c == EOF) return 0; else if (c == '\n') { yylineno++; continue; } else if (isspace(c)) continue; else if (c == '(') return c; else if (c == ')') return c; else if (c == '"') { i = 0; c = getc(ast_fp); while (c != '"') { if (c == EOF) { lexeme[i] = '\0'; yyerror ("Unterminated string:\n%s",lexeme); }; append(c,i++); c = getc(ast_fp); }; lexeme[i] = '\0'; yylval.string = strsave(lexeme); return STRING; } else if (isalpha(c)) { int k; i = 0; append(c,i++); c = getc(ast_fp); while (isalnum(c)) { append(c,i++); c = getc(ast_fp); } lexeme[i] = '\0'; ungetc(c,ast_fp); for (k = 0; k < (sizeof(nodes)/sizeof(nodes[0])); k++) if (!strcmp(lexeme,nodes[k])) return (BODYDEF+k); for (k = 0; k < (sizeof(binops)/sizeof(binops[0])); k++) if (!strcmp(lexeme,binops[k])) { yylval.binop = k; return BINOP; } for (k = 0; k < (sizeof(unops)/sizeof(unops[0])); k++) if (!strcmp(lexeme,unops[k])) { yylval.unop = k; return UNOP; }; yylval.id = strsave(lexeme); return ID; } else if (isdigit(c)) { i = 0; append(c,i++); c = getc(ast_fp); while (isdigit(c)) { append(c,i++); c = getc(ast_fp); }; lexeme[i] = '\0'; ungetc(c,ast_fp); yylval.ivalue = atoi(lexeme); return INTEGER; } else yyerror ("Invalid character %c", c); }; } Program parse_Program(FILE *fp) { ast_fp = fp; yylineno = 1; yyparse(); return p; }