345 lines
7.7 KiB
Plaintext
345 lines
7.7 KiB
Plaintext
/****************************************************/
|
|
/* File: tiny.y */
|
|
/* The TINY Yacc/Bison specification file */
|
|
/* Compiler Construction: Principles and Practice */
|
|
/* Kenneth C. Louden */
|
|
/****************************************************/
|
|
%{
|
|
#define YYPARSER /* distinguishes Yacc output from other code files */
|
|
|
|
#include "globals.h"
|
|
#include "util.h"
|
|
#include "scan.h"
|
|
#include "parse.h"
|
|
|
|
#define YYSTYPE TreeNode *
|
|
static char * savedName; /* for use in assignments */
|
|
static int savedNumber;
|
|
static int savedLineNo; /* ditto */
|
|
static TreeNode * savedTree; /* stores syntax tree for later return */
|
|
static int yylex(void); // added 11/2/11 to ensure no conflict with lex
|
|
int yyerror(char * message);
|
|
%}
|
|
|
|
%token IF ELSE WHILE RETURN INT VOID
|
|
%token EQ NE LT LE GT GE LPAREN RPAREN LBRACE LCURLY RBRACE RCURLY SEMI COMMA
|
|
%token ID NUM
|
|
|
|
%left PLUS MINUS
|
|
%left TIMES OVER
|
|
%right ASSIGN
|
|
|
|
%nonassoc THEN
|
|
%nonassoc ELSE
|
|
|
|
%token ERROR
|
|
|
|
%% /* Grammar for C-MINUS */
|
|
|
|
program : declaration_list
|
|
{savedTree = $1;};
|
|
|
|
declaration_list : declaration_list declaration {
|
|
YYSTYPE t = $1;
|
|
if (t != NULL) {
|
|
while (t->sibling != NULL) {
|
|
t = t->sibling;
|
|
}
|
|
t->sibling = $2;
|
|
$$ = $1;
|
|
} else { $$ = $2; };
|
|
}
|
|
| declaration { $$ = $1; }
|
|
;
|
|
|
|
declaration : var_declaration {$$ = $1; } | func_declaration { $$ = $1; };
|
|
|
|
name_specifier : ID {
|
|
savedName = copyString(tokenString);
|
|
savedLineNo = lineno;
|
|
};
|
|
|
|
number_specifier : NUM {
|
|
savedNumber = atoi(tokenString);
|
|
savedLineNo = lineno;
|
|
};
|
|
|
|
var_declaration : type_specifier name_specifier SEMI {
|
|
$$ = newDeclNode(VarK);
|
|
$$->lineno = savedLineNo;
|
|
$$->attr.name = savedName;
|
|
$$->type = $1->type;
|
|
free($1);
|
|
} | type_specifier name_specifier LBRACE number_specifier RBRACE SEMI {
|
|
$$ = newDeclNode(ArrVarK);
|
|
$$->lineno = savedLineNo;
|
|
if ($1->type == Integer)
|
|
$$->type = IntegerArray;
|
|
else
|
|
$$->type = Void;
|
|
$$->attr.name = savedName;
|
|
free($1);
|
|
$$->child[0] = newExpNode(ConstK);
|
|
$$->child[0]->type = Integer;
|
|
$$->child[0]->attr.val = savedNumber;
|
|
};
|
|
|
|
type_specifier : INT {
|
|
$$ = newTypeNode(TypeNameK);
|
|
$$->type = Integer;
|
|
}
|
|
| VOID {
|
|
$$ = newTypeNode(TypeNameK);
|
|
$$->type = Void;
|
|
};
|
|
|
|
func_declaration : type_specifier name_specifier {
|
|
$$ = newDeclNode(FuncK);
|
|
$$->lineno = savedLineNo;
|
|
$$->attr.name = savedName;
|
|
$$->type = $1->type; /* 타입 바로 복사 */
|
|
} LPAREN params RPAREN compound_stmt {
|
|
$$ = $3;
|
|
$$->child[0] = $5; /* params */
|
|
$$->child[1] = $7; /* compound_stmt */
|
|
};
|
|
|
|
params : param_list { $$ = $1; } | VOID {
|
|
$$ = newDeclNode(NonArrParamK);
|
|
$$->type = Void;
|
|
};
|
|
|
|
param_list : param_list COMMA param {
|
|
YYSTYPE t = $1;
|
|
if (t != NULL) {
|
|
while (t->sibling != NULL) {
|
|
t = t->sibling;
|
|
}
|
|
t->sibling = $3;
|
|
$$ = $1;
|
|
} else {
|
|
$$ = $3;
|
|
};
|
|
} | param {$$ = $1; };
|
|
|
|
param : type_specifier name_specifier {
|
|
$$ = newDeclNode(NonArrParamK);
|
|
$$->attr.name = savedName;
|
|
$$->type = $1->type;
|
|
} | type_specifier name_specifier LBRACE RBRACE {
|
|
$$ = newDeclNode(ArrParamK);
|
|
$$->attr.name = savedName;
|
|
if ($1->type == Integer)
|
|
$$->type = IntegerArray;
|
|
else
|
|
$$->type = Void;
|
|
};
|
|
|
|
compound_stmt : LCURLY local_declarations statement_list RCURLY {
|
|
$$ = newStmtNode(CompK);
|
|
$$->lineno = lineno;
|
|
$$->child[0] = $2;
|
|
$$->child[1] = $3;
|
|
};
|
|
|
|
local_declarations : local_declarations var_declaration {
|
|
YYSTYPE t = $1;
|
|
if (t != NULL) {
|
|
while (t->sibling != NULL)
|
|
t = t->sibling;
|
|
t->sibling = $2;
|
|
$$ = $1;
|
|
} else $$ = $2;
|
|
} | { $$ = NULL; };
|
|
|
|
statement_list : statement_list statement {
|
|
YYSTYPE t = $1;
|
|
if (t != NULL) {
|
|
while (t->sibling != NULL)
|
|
t = t->sibling;
|
|
t->sibling = $2;
|
|
$$ = $1;
|
|
} else $$ = $2;
|
|
} | { $$ = NULL; };
|
|
|
|
statement : expression_stmt { $$ = $1; }
|
|
| compound_stmt { $$ = $1; }
|
|
| selection_stmt { $$ = $1; }
|
|
| iteration_stmt { $$ = $1; }
|
|
| return_stmt { $$ = $1; }
|
|
;
|
|
|
|
expression_stmt : expression SEMI { $$ = $1; }
|
|
| SEMI { $$ = NULL; }
|
|
;
|
|
selection_stmt : IF LPAREN expression RPAREN statement %prec THEN {
|
|
$$ = newStmtNode(IfK);
|
|
$$->lineno = lineno;
|
|
$$->child[0] = $3;
|
|
$$->child[1] = $5;
|
|
} | IF LPAREN expression RPAREN statement ELSE statement {
|
|
$$ = newStmtNode(IfK);
|
|
$$->lineno = lineno;
|
|
$$->child[0] = $3;
|
|
$$->child[1] = $5;
|
|
$$->child[2] = $7;
|
|
};
|
|
|
|
iteration_stmt : WHILE LPAREN expression RPAREN statement {
|
|
$$ = newStmtNode(IterK);
|
|
$$->lineno = lineno;
|
|
$$->child[0] = $3;
|
|
$$->child[1] = $5;
|
|
};
|
|
|
|
return_stmt : RETURN SEMI {
|
|
$$ = newStmtNode(ReturnK);
|
|
$$->lineno = lineno;
|
|
} | RETURN expression SEMI {
|
|
$$ = newStmtNode(ReturnK);
|
|
$$->lineno = lineno;
|
|
$$->child[0] = $2;
|
|
};
|
|
|
|
expression : var ASSIGN expression {
|
|
$$ = newExpNode(AssignK);
|
|
$$->lineno = lineno;
|
|
$$->type = $3->type;
|
|
$$->child[0] = $1;
|
|
$$->child[1] = $3;
|
|
} | simple_expression { $$ = $1; };
|
|
|
|
var : name_specifier {
|
|
$$ = newExpNode(IdK);
|
|
$$->attr.name = savedName;
|
|
} | name_specifier {
|
|
$$ = newExpNode(ArrIdK);
|
|
$$->attr.name = savedName;
|
|
} LBRACE expression RBRACE {
|
|
$$ = $2;
|
|
$$->child[0] = $4;
|
|
};
|
|
|
|
simple_expression : additive_expression relop additive_expression {
|
|
$$ = $2;
|
|
$$->lineno = $2->lineno;
|
|
$$->child[0] = $1;
|
|
$$->child[1] = $3;
|
|
$$->type = Integer;
|
|
} | additive_expression { $$ = $1; };
|
|
|
|
relop : LE {
|
|
$$ = newExpNode(OpK);
|
|
$$->lineno = lineno;
|
|
$$->attr.op = LE;
|
|
} | LT {
|
|
$$ = newExpNode(OpK);
|
|
$$->lineno = lineno;
|
|
$$->attr.op = LT;
|
|
} | GT {
|
|
$$ = newExpNode(OpK);
|
|
$$->lineno = lineno;
|
|
$$->attr.op = GT;
|
|
} | GE {
|
|
$$ = newExpNode(OpK);
|
|
$$->lineno = lineno;
|
|
$$->attr.op = GE;
|
|
} | EQ {
|
|
$$ = newExpNode(OpK);
|
|
$$->lineno = lineno;
|
|
$$->attr.op = EQ;
|
|
} | NE {
|
|
$$ = newExpNode(OpK);
|
|
$$->lineno = lineno;
|
|
$$->attr.op = NE;
|
|
};
|
|
|
|
additive_expression : additive_expression addop term {
|
|
$$ = $2;
|
|
$$->lineno = $2->lineno;
|
|
$$->child[0] = $1;
|
|
$$->child[1] = $3;
|
|
} | term { $$ = $1; };
|
|
|
|
addop : PLUS {
|
|
$$ = newExpNode(OpK);
|
|
$$->lineno = lineno;
|
|
$$->attr.op = PLUS;
|
|
} | MINUS {
|
|
$$ = newExpNode(OpK);
|
|
$$->lineno = lineno;
|
|
$$->attr.op = MINUS;
|
|
};
|
|
|
|
term : term mulop factor {
|
|
$$ = $2;
|
|
$$->lineno = $2->lineno;
|
|
$$->child[0] = $1;
|
|
$$->child[1] = $3;
|
|
} | factor { $$ = $1; };
|
|
|
|
mulop : TIMES {
|
|
$$ = newExpNode(OpK);
|
|
$$->lineno = lineno;
|
|
$$->attr.op = TIMES;
|
|
} | OVER {
|
|
$$ = newExpNode(OpK);
|
|
$$->lineno = lineno;
|
|
$$->attr.op = OVER;
|
|
};
|
|
|
|
factor : LPAREN expression RPAREN { $$ = $2; }
|
|
| var { $$ = $1; }
|
|
| call { $$ = $1; }
|
|
| NUM {
|
|
$$ = newExpNode(ConstK);
|
|
$$->lineno = lineno;
|
|
$$->type = Integer;
|
|
$$->attr.val = atoi(tokenString);
|
|
}
|
|
;
|
|
|
|
call : name_specifier {
|
|
$$ = newExpNode(CallK);
|
|
$$->lineno = lineno;
|
|
$$->attr.name = savedName;
|
|
} LPAREN args RPAREN {
|
|
$$ = $2;
|
|
$$->child[0] = $4;
|
|
};
|
|
|
|
args : arg_list { $$ = $1; } | { $$ = NULL; } ;
|
|
|
|
arg_list : arg_list COMMA expression {
|
|
YYSTYPE t = $1;
|
|
if (t != NULL) {
|
|
while (t->sibling != NULL)
|
|
t = t->sibling;
|
|
t->sibling = $3;
|
|
$$ = $1;
|
|
} else $$ = $3;
|
|
} | expression { $$ = $1; } ;
|
|
|
|
|
|
%%
|
|
|
|
int yyerror(char * message)
|
|
{ fprintf(listing,"Syntax error at line %d: %s\n",lineno,message);
|
|
fprintf(listing,"Current token: ");
|
|
printToken(yychar,tokenString);
|
|
Error = TRUE;
|
|
return 0;
|
|
}
|
|
|
|
/* yylex calls getToken to make Yacc/Bison output
|
|
* compatible with ealier versions of the TINY scanner
|
|
*/
|
|
static int yylex(void)
|
|
{ return getToken(); }
|
|
|
|
TreeNode * parse(void)
|
|
{ yyparse();
|
|
return savedTree;
|
|
}
|
|
|