www.pudn.com > lab3.rar > lab3.y
%{
#include "lab3.h"
#define YYERROR_VERBOSE 1
tablelen = 0;
level = 0;
right = 1;
typecount = 0;
typecheck = 0;
%}
%union {
char *id; /* identifier */
int value; /* value */
char op[3]; /* operator */
symbol *sign; /* symbol */
expr expn; /* expression */
}
%token IF ELSE WHILE RETURN VOID INT CHAR ID NUM
NE LT LE EQ GT GE CHAR_LITERAL STRING_LITERAL
CDECL STDCALL ELLIPSIS
%nonassoc IFX
%nonassoc ELSE
%start program
%right '='
%left '+' '-'
%left '*' '/'
%token ID
%token NUM
%token CHAR_LITERAL
%token STRING_LITERAL
%type type_specifer
%type var
%type additive_expression
%type call
%type expression
%type factor
%type simple_expression
%type term
%type unary_expression
%type addop
%type mulop
%type relop
%type unaryop
%%
program
: {
if (debug) {
printf("make symboltable[%d]\n",tablelen);
}
globaltable = MakeTable(NULL, 0);
symboltable[tablelen] = globaltable;
tablelen++;
if (0 == (argtemp.temp = (int *)malloc(50 * sizeof(int)))) {
printf("malloc for argument list buffer error\n");
exit(1);
}
argtemp.size = 50;
if (0 == (arg_in.temp = (int *)malloc(50 * sizeof(int)))) {
printf("malloc for argument check buffer error\n");
exit(1);
}
arg_in.size = 50;
}
declaration_list
{
if (debug) {
printf("program => declaration_list\n");
}
}
;
declaration_list
: declaration_list declaration
{/*
if (debug) {
printf("declaration_list => declaration_list declaration\n");
}*/
}
| declaration
{/*
if (debug) {
printf("declaration_list => declaration\n");
}*/
}
;
declaration
: var_declaration
{
if (debug) {
printf("declaration => var_declaration\n");
}
}
| fun_declaration
{
if (debug) {
printf("declaration => fun_declaration\n");
}
}
;
var_declaration
: type_specifer ID ';'
{
struct table *tp = symboltable[tablelen-1];
symbol *p = InsertSym($2, tp);
if (0 == p) {
printf("line %3d error: %s :redefinition\n", lineno, $2);
right = 0;
} else {
p->type = $1;
}
if (debug) {
printf("var_declaration => type_specifer ID ;\n");
}
}
| type_specifer ID '[' NUM ']' ';'
{
struct table *tp = symboltable[tablelen-1];
symbol *p = InsertSym($2, tp);
if (0 == p) {
printf("line %3d error: %s :redefinition\n", lineno, $2);
right = 0;
} else {
p->type = $1;
}
if (debug) {
printf("var_declaration => type_specifer ID [ NUM ] ;\n");
}
}
| type_specifer '*' ID ';'
{
struct table *tp = symboltable[tablelen-1];
symbol *p = InsertSym($3, tp);
if (0 == p) {
printf("line %3d error: %s :redefinition\n", lineno, $3);
right = 0;
} else {
p->type = $1 + 100;
}
if (debug) {
printf("var_declaration => type_specifer * ID ;\n");
}
}
| type_specifer '*' ID '[' NUM ']' ';'
{
struct table *tp = symboltable[tablelen-1];
symbol *p = InsertSym($3, tp);
if (0 == p) {
printf("line %3d error: %s :redefinition\n", lineno, $3);
right = 0;
} else {
p->type = $1 + 100;
}
if (debug) {
printf("var_declaration => type_specifer * ID [ NUM ] ;\n");
}
}
;
type_specifer
: INT
{
$$ = INT;
if (debug) {
printf("type_specifer => INT\n");
}
}
| VOID
{
$$ = VOID;
if (debug) {
printf("type_specifer => VOID\n");
}
}
| CHAR
{
$$ = CHAR;
if (debug) {
printf("type_specifer => CHAR\n");
}
}
;
fun_declaration
: fun_tag compound_stmt
{
tablelen--;
level--;
/* if (debug) {
printf("fun_declaration => fun_tag compound_stmt\n");
}*/
}
| fun_tag ';'
{
tablelen--;
level--;
/* if (debug) {
printf("fun_declaration => fun_tag ;\n");
}*/
}
;
fun_tag
: type_specifer calling_convention ID '(' params ')'
{
char *p = InsertFun($3, $1);
if (0 == p) {
printf("line %3d error: %s :function redefinition\n", lineno, $3);
right = 0;
free(argtemp.temp);
}
level++;
typecount = 0;
if (0 == (argtemp.temp = (int *)malloc(50 * sizeof(int)))) {
printf("malloc for argument list buffer error\n");
exit(1);
}
argtemp.size = 50;
if (debug) {
printf("fun_tag => type_specifer calling_convention ID\n");
}
}
| type_specifer ID '(' params ')'
{
char *p = InsertFun($2, $1);
if (0 == p) {
printf("line %3d error: %s :function redefinition\n", lineno, $2);
right = 0;
free(argtemp.temp);
}
level++;
typecount = 0;
if (0 == (argtemp.temp = (int *)malloc(50 * sizeof(int)))) {
printf("malloc for argument list buffer error\n");
exit(1);
}
argtemp.size = 50;
if (debug) {
printf("fun_tag => type_specifer ID\n");
}
}
;
params
: param_list
{/*
if (debug) {
printf("params => param_list\n");
}*/
}
| VOID
{
if (typecount + 1 > argtemp.size) {
argtemp.temp = (int *)realloc(argtemp.temp,(argtemp.size + BUFFINCREMENT) * sizeof(int));
if (0 == argtemp.temp) {
printf("realloc for argument list buffer error\n");
exit(1);
}
argtemp.size += BUFFINCREMENT;
}
argtemp.temp[typecount++] = VOID;
if (debug) {
printf("params => VOID\n");
}
}
;
param_list
: param_list ',' param
{/*
if (debug) {
printf("param_list => param_list , param\n");
}*/
}
| param
{/*
if (debug) {
printf("param_list => param\n");
}*/
}
;
param
: type_specifer ID
{
struct table *tp = symboltable[tablelen-1];
symbol *p;
level++;
p = InsertSym($2, tp);
if (0 == p) {
printf("line %3d error: %s :redefinition\n", lineno, $2);
right = 0;
} else {
p->type = $1;
}
level--;
if (typecount + 1 > argtemp.size) {
argtemp.temp = (int *)realloc(argtemp.temp,(argtemp.size + BUFFINCREMENT) * sizeof(int));
if (0 == argtemp.temp) {
printf("realloc for argument list buffer error\n");
exit(1);
}
argtemp.size += BUFFINCREMENT;
}
argtemp.temp[typecount++] = $1;
if (debug) {
printf("param => type_specifer ID\n");
}
}
| type_specifer '*' ID
{
struct table *tp = symboltable[tablelen-1];
symbol *p;
level++;
p = InsertSym($3, tp);
if (0 == p) {
printf("line %3d error: %s :redefinition\n", lineno, $3);
right = 0;
} else {
p->type = $1 + 100;
}
level--;
if (typecount + 1 > argtemp.size) {
argtemp.temp = (int *)realloc(argtemp.temp,(argtemp.size + BUFFINCREMENT) * sizeof(int));
if (0 == argtemp.temp) {
printf("realloc for argument list buffer error\n");
exit(1);
}
argtemp.size += BUFFINCREMENT;
}
argtemp.temp[typecount++] = $1 + 100;
if (debug) {
printf("param => type_specifer * ID\n");
}
}
| type_specifer ID '[' ']'
{
struct table *tp = symboltable[tablelen-1];
symbol *p;
level++;
p = InsertSym($2, tp);
if (0 == p) {
printf("line %3d error: %s :redefinition\n", lineno, $2);
right = 0;
} else {
p->type = $1;
}
level--;
if (typecount + 1 > argtemp.size) {
argtemp.temp = (int *)realloc(argtemp.temp,(argtemp.size + BUFFINCREMENT) * sizeof(int));
if (0 == argtemp.temp) {
printf("realloc for argument list buffer error\n");
exit(1);
}
argtemp.size += BUFFINCREMENT;
}
argtemp.temp[typecount++] = $1;
if (debug) {
printf("param => type_specifer ID [ ]\n");
}
}
| ELLIPSIS
{
if (typecount + 1 > argtemp.size) {
argtemp.temp = (int *)realloc(argtemp.temp,(argtemp.size + BUFFINCREMENT) * sizeof(int));
if (0 == argtemp.temp) {
printf("realloc for argument list buffer error\n");
exit(1);
}
argtemp.size += BUFFINCREMENT;
}
argtemp.temp[typecount++] = ELLIPSIS;
if (debug) {
printf("param => ELLIPSIS\n");
}
}
;
compound_stmt
: '{' local_declarations statement_list '}'
{/*
if (debug) {
printf("compound_stmt => { local_declarations statement_list }\n");
}*/
}
;
local_declarations
: local_declarations var_declaration
{/*
if (debug) {
printf("local_declarations =>local_declarations var_declaration\n");
}*/
}
| /* empty */
;
statement_list
: statement_list statement
{/*
if (debug) {
printf("statement_list => statement_list statement\n");
}*/
}
| /* empty */
;
statement
: expression_stmt
{/*
if (debug) {
printf("statement => expression_stmt\n");
}*/
}
| compound_stmt
{/*
if (debug) {
printf("statement => compound_stmt\n");
}*/
}
| if_stmt
{/*
if (debug) {
printf("statement => if_stmt\n");
}*/
}
| while_stmt
{/*
if (debug) {
printf("statement => while_stmt\n");
}*/
}
| return_stmt
{/*
if (debug) {
printf("statement => return_stmt\n");
}*/
}
;
expression_stmt
: expression ';'
{
if (debug) {
printf("expression_stmt => expression ;\n");
}
}
| ';'
{
if (debug) {
printf("expression_stmt => ;\n");
}
}
;
if_stmt
: IF '(' expression ')' statement %prec IFX
{
if (debug) {
printf("if_stmt => IF ( expression ) statement\n");
}
}
| IF '(' expression ')' statement ELSE statement
{
if (debug) {
printf("if_stmt => IF ( expression ) statement ELSE statement\n");
}
}
;
while_stmt
: WHILE '(' expression ')' statement
{
if (debug) {
printf("while_stmt => WHILE ( expression ) statement\n");
}
}
;
return_stmt
: RETURN ';'
{
if (debug) {
printf("return_stmt => RETURN ;\n");
}
}
| RETURN expression ';'
{
if (debug) {
printf("return_stmt => RETURN expression ;\n");
}
}
;
expression
: var '=' expression
{
if ($1 != 0) {
if ($1->type != $3.type) {
printf("line %3d error: = :the left and the right type does not match\n", lineno, $1);
right = 0;
}
$$.type = $1->type;
}
if (debug) {
printf("expression => var = expression\n");
}
}
| simple_expression
{
$$.type = $1.type;
/* if (debug) {
printf("expression => simple_expression\n");
}*/
}
;
var
: ID
{
$$ = LookUp($1, symboltable[tablelen-1]);
if (0 == $$) {
printf("line %3d error: %s :undeclared identifier\n", lineno, $1);
right = 0;
}
if (debug) {
printf("var => ID\n");
}
}
| ID '[' expression ']'
{
$$ = LookUp($1, symboltable[tablelen-1]);
if (0 == $$) {
printf("line %3d error: %s :undeclared identifier\n", lineno, $1);
right = 0;
}
if (debug) {
printf("var => ID [ expression ]\n");
}
}
;
simple_expression
: additive_expression relop additive_expression
{
$$.type = INT;
if (($1.type == INT || $1.type == CHAR) && ($3.type == INT || $3.type == CHAR)) {
if (0 == strcmp($2, "<")) {
if ($1.value < $3.value) {
$$.value = 1;
} else {
$$.value = 0;
}
} else if (0 == strcmp($2, "<=")) {
if ($1.value <= $3.value) {
$$.value = 1;
} else {
$$.value = 0;
}
} else if (0 == strcmp($2, ">")) {
if ($1.value > $3.value) {
$$.value = 1;
} else {
$$.value = 0;
}
} else if (0 == strcmp($2, ">=")) {
if ($1.value >= $3.value) {
$$.value = 1;
} else {
$$.value = 0;
}
} else if (0 == strcmp($2, "==")) {
if ($1.value == $3.value) {
$$.value = 1;
} else {
$$.value = 0;
}
} else {
if ($1.value != $3.value) {
$$.value = 1;
} else {
$$.value = 0;
}
}
}
if ($1.type != INT && $1.type != CHAR) {
printf("line %3d error: %s :illegal, left operand is not constant or character\n", lineno, $2);
right = 0;
}
if ($3.type != INT && $3.type != CHAR) {
printf("line %3d error: %s :illegal, right operand is not constant or character\n", lineno, $2);
right = 0;
}
if (debug) {
printf("simple_expression => additive_expression relop additive_expression\n");
}
}
| additive_expression
{
$$.type = $1.type;
/* if (debug) {
printf("simple_expression => additive_expression\n");
}*/
}
;
relop
: LE
{
if (debug) {
printf("relop => LE\n");
}
}
| LT
{
if (debug) {
printf("relop => LT\n");
}
}
| GT
{
if (debug) {
printf("relop => GT\n");
}
}
| GE
{
if (debug) {
printf("relop => GE\n");
}
}
| EQ
{
if (debug) {
printf("relop => EQ\n");
}
}
| NE
{
if (debug) {
printf("relop => NE\n");
}
}
;
additive_expression
: additive_expression addop term
{
$$.type = INT;
if ($1.type == INT && $3.type == INT) {
if ($2[0] == '+') {
$$.value = $1.value + $3.value;
} else {
$$.value = $1.value - $3.value;
}
}
if ($1.type != INT) {
printf("line %3d error: %c :illegal, left operand is not constant\n", lineno, $2[0]);
right = 0;
}
if ($3.type != INT) {
printf("line %3d error: %c :illegal, right operand is not constant\n", lineno, $2[0]);
right = 0;
}
if (debug) {
printf("additive_expression => additive_expression addop term\n");
}
}
| term
{
$$.type = $1.type;
/* if (debug) {
printf("additive_expression => term\n");
}*/
}
;
addop
: '+'
{
$$[0] = '+';
if (debug) {
printf("addop => +\n");
}
}
| '-'
{
$$[0] = '-';
if (debug) {
printf("addop => -\n");
}
}
;
term
: term mulop unary_expression
{
$$.type = INT;
if ($1.type == INT && $3.type == INT) {
if ($2[0] == '*') {
$$.value = $1.value * $3.value;
} else if ($2[0] == '/') {
$$.value = $1.value / $3.value;
} else {
$$.value = $1.value % $3.value;
}
}
if ($1.type != INT) {
printf("line %3d error: %c :illegal, left operand is not constant\n", lineno, $2[0]);
right = 0;
}
if ($3.type != INT) {
printf("line %3d error: %c :illegal, right operand is not constant\n", lineno, $2[0]);
right = 0;
}
if (debug) {
printf("term => term mulop unary_expression\n");
}
}
| unary_expression
{
$$.type = $1.type;
/* if (debug) {
printf("term => unary_expression\n");
}*/
}
;
mulop
: '*'
{
$$[0] = '*';
if (debug) {
printf("mulop => *\n");
}
}
| '/'
{
$$[0] = '/';
if (debug) {
printf("mulop => /\n");
}
}
| '%'
{
$$[0] = '%';
if (debug) {
printf("mulop => %\n");
}
}
;
unary_expression
: unaryop unary_expression
{
$$.type = INT;
if ($2.type == INT) {
if ($1[0] == '+') {
$$.value = $2.value;
} else {
$$.value = -$2.value;
}
}
if ($2.type != INT) {
printf("line %3d error: %c :illegal, right operand is not constant\n", lineno, $1[0]);
right = 0;
}
if (debug) {
printf("unary_expression => unaryop unary_expression\n");
}
}
| factor
{
$$.type = $1.type;
/* if (debug) {
printf("unary_expression => factor\n");
}*/
}
;
unaryop
: '+'
{
$$[0] = '+';
if (debug) {
printf("unaryop => +\n");
}
}
| '-'
{
$$[0] = '-';
if (debug) {
printf("unaryop => -\n");
}
}
;
factor
: '(' expression ')'
{
$$.type = $2.type;
if (debug) {
printf("factor => ( expression )\n");
}
}
| var
{
if ($1 != 0) {
$$.type = $1->type;
$$.symadd = $1;
}
if (debug) {
printf("factor => var\n");
}
}
| call
{
$$.type = $1.type;
if (debug) {
printf("factor => call\n");
}
}
| NUM
{
$$.type = INT;
$$.value = atoi($1);
if (debug) {
printf("factor => NUM\n");
}
}
| CHAR_LITERAL
{
$$.type = CHAR;
$$.value = $1[1];
if (debug) {
printf("factor => CHAR_LITERAL\n");
}
}
| STRING_LITERAL
{
$$.type = CHAR + 100;
$$.string = $1;
if (debug) {
printf("factor => STRING_LITERAL\n");
}
}
;
call
: ID '(' args ')'
{
$$.type = LookUpFun($1);
if (0 == $$.type) {
printf("line %3d error: %s :undeclared function\n", lineno, $1);
right = 0;
}
typecheck = 0;
free(arg_in.temp);
if (0 == (arg_in.temp = (int *)malloc(50 * sizeof(int)))) {
printf("malloc for argument check buffer error\n");
exit(1);
}
arg_in.size = 50;
if (debug) {
printf("call => ID ( args )\n");
}
}
;
args
: arg_list
{/*
if (debug) {
printf("args => arg_list\n");
}*/
}
| /* empty */
;
arg_list
: arg_list ',' expression
{
if (typecheck + 1 > arg_in.size) {
arg_in.temp = (int *)realloc(arg_in.temp,(arg_in.size + BUFFINCREMENT) * sizeof(int));
if (0 == arg_in.temp) {
printf("realloc for argument check buffer error\n");
exit(1);
}
arg_in.size += BUFFINCREMENT;
}
arg_in.temp[typecheck++] = $3.type;
/* if (debug) {
printf("arg_list => arg_list , expression\n");
}*/
}
| expression
{
if (typecheck + 1 > arg_in.size) {
arg_in.temp = (int *)realloc(arg_in.temp,(arg_in.size + BUFFINCREMENT) * sizeof(int));
if (0 == arg_in.temp) {
printf("realloc for argument check buffer error\n");
exit(1);
}
arg_in.size += BUFFINCREMENT;
}
arg_in.temp[typecheck++] = $1.type;
/* if (debug) {
printf("arg_list => expression\n");
}*/
}
;
calling_convention
: CDECL
{
if (debug) {
printf("calling_convention => CDECL\n");
}
}
| STDCALL
{
if (debug) {
printf("calling_convention => STDCALL\n");
}
}
;
%%
void info()
{
printf("lab3.exe -- Copyright (C) 2007 cj4 No.04120004\n");
printf("Usage: lab3 [-d] filename\n");
printf("----------------------------------------------------\n");
printf("filename specifies the name of input file\n");
printf("-d debug mode\n");
exit(1);
}
int yyerror(char *s)
{
fprintf(stderr, "line %3d error: %s\n", lineno, s);
right = 0;
return (0);
}
int main(int argc, char *argv[])
{
debug = 0;
switch (argc) {
case 3:
if (0 == strcmp(argv[1], "-d")) {
printf("============= debug mode =============\n");
debug = 1;
} else {
info();
}
if (NULL == (yyin = fopen(argv[2],"r"))) {
printf("file: %s open error!\n", argv[2]);
exit(1);
}
yyparse();
free(argtemp.temp);
free(arg_in.temp);
fclose(yyin);
break;
case 2:
if (NULL == (yyin = fopen(argv[1],"r"))) {
printf("file: %s open error!\n", argv[1]);
exit(1);
}
yyparse();
free(argtemp.temp);
free(arg_in.temp);
fclose(yyin);
break;
default:
info();
}
if (right) {
printf("Well done!\n");
}
return (0);
}