cobol-interpreter-lab/lab-5/parser.bison

190 lines
4.1 KiB
Plaintext

/*
Declare token types at the top of the bison file,
causing them to be automatically generated in parser.tab.h
for use by scanner.c.
*/
%debug
%define parse.error detailed
%token TOKEN_ASSIGNMENT
%token TOKEN_COMMA
%token TOKEN_DIV
%token TOKEN_EQUAL_EQUAL
%token TOKEN_GREATER_THAN
%token TOKEN_GREATER_THAN_OR_EQUAL
%token TOKEN_ID
%token TOKEN_INT
%token TOKEN_INTEGER
%token TOKEN_KEYWORD_ENDIF
%token TOKEN_KEYWORD_IF
%token TOKEN_KEYWORD_PRINT
%token TOKEN_KEYWORD_THEN
%token TOKEN_LBRACKET
%token TOKEN_LESS_THAN
%token TOKEN_LESS_THAN_OR_EQUAL
%token TOKEN_LPAREN
%token TOKEN_MINUS
%token TOKEN_MUL
%token TOKEN_NOT_EQUAL
%token TOKEN_PLUS
%token TOKEN_RBRACKET
%token TOKEN_RPAREN
%token TOKEN_SEMI
%union {
struct stmt *stmt;
struct expr *expr;
struct decl *decl;
};
%type <stmt> program statement_list statement print_statement assignment_statement if_statement block
%type <expr> expr term factor name sum array_subscript star_expr
%type <decl> declaration
%{
#define YYDEBUG 1
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "expr.h"
/*
Clunky: Manually declare the interface to the scanner generated by flex.
*/
extern int yylineno;
extern char *yytext;
extern int yylex();
extern void yyerror(const char*);
/*
Clunky: Keep the final result of the parse in a global variable,
so that it can be retrieved by main().
*/
struct stmt * parser_result = 0;
%}
%%
/* Here is the grammar: program is the start symbol. */
program : statement_list
{ parser_result = $1; return 0; }
;
statement_list : statement
{ $$ = $1; }
| statement statement_list
{ $$ = $1; $1->next = $2; }
;
block : statement
{ $$ = $1; }
| statement block
{ $$ = $1; $1->next = $2; }
;
statement : assignment_statement TOKEN_SEMI
{ $$ = $1; }
| print_statement TOKEN_SEMI
{ $$ = $1; }
| if_statement
{ $$ = $1; }
;
assignment_statement : declaration
{ $$ = stmt_create(STMT_DECL,$1,0,0,0,0,0,0); }
;
print_statement : TOKEN_KEYWORD_PRINT expr
{ $$ = stmt_create(STMT_PRINT,0,0,$2,0,0,0,0); }
;
if_statement : TOKEN_KEYWORD_IF expr TOKEN_KEYWORD_THEN block TOKEN_KEYWORD_ENDIF
{ $$ = stmt_create(STMT_IF,0,0,$2,0,$4,0,0); }
;
declaration : name TOKEN_ASSIGNMENT expr
{ $$ = decl_create($1,0,$3,0,0); }
| array_subscript TOKEN_ASSIGNMENT expr
{ $$ = decl_create($1,0,$3,0,0); }
;
name : TOKEN_ID
{ $$ = expr_create_name(yytext); }
;
array_subscript : name TOKEN_LBRACKET expr TOKEN_RBRACKET
{ $$ = expr_create(EXPR_SUBSCRIPT,$1,$3); }
;
star_expr : expr
{ $$ = expr_create(EXPR_ARRAY,$1,0); }
| expr TOKEN_COMMA star_expr
{ $$ = expr_create(EXPR_ARRAY,$1,$3); }
;
expr : sum TOKEN_LESS_THAN sum
{ $$ = expr_create(EXPR_LESS_THAN,$1,$3); }
| sum TOKEN_LESS_THAN_OR_EQUAL sum
{ $$ = expr_create(EXPR_LESS_THAN_OR_EQUAL,$1,$3); }
| sum TOKEN_GREATER_THAN sum
{ $$ = expr_create(EXPR_GREATER_THAN,$1,$3); }
| sum TOKEN_GREATER_THAN_OR_EQUAL sum
{ $$ = expr_create(EXPR_GREATER_THAN_OR_EQUAL,$1,$3); }
| sum TOKEN_EQUAL_EQUAL sum
{ $$ = expr_create(EXPR_EQUAL_EQUAL,$1,$3); }
| sum TOKEN_NOT_EQUAL sum
{ $$ = expr_create(EXPR_NOT_EQUAL,$1,$3); }
| sum
{ $$ = $1; }
;
sum : sum TOKEN_PLUS term
{ $$ = expr_create(EXPR_ADD,$1,$3); }
| sum TOKEN_MINUS term
{ $$ = expr_create(EXPR_SUBTRACT,$1,$3); }
| term
{ $$ = $1; }
;
term : term TOKEN_MUL factor
{ $$ = expr_create(EXPR_MULTIPLY,$1,$3); }
| term TOKEN_DIV factor
{ $$ = expr_create(EXPR_DIVIDE,$1,$3); }
| factor
{ $$ = $1; }
;
factor : TOKEN_LPAREN expr TOKEN_RPAREN
{ $$ = $2; }
| TOKEN_MINUS factor
{ $$ = expr_create(EXPR_SUBTRACT,expr_create_integer_literal(0),$2); }
| TOKEN_INT
{ $$ = expr_create_integer_literal(atoi(yytext)); }
| TOKEN_LBRACKET star_expr TOKEN_RBRACKET
{ $$ = $2; }
| array_subscript
{ $$ = $1; }
| name
{ $$ = $1; }
;
%%
/*
This function will be called by bison if the parse should
encounter an error. In principle, "str" will contain something
useful. In practice, it often does not.
*/
void yyerror(const char* msg) {
fprintf(stderr, "Error | Line: %d\n%s\n", yylineno, msg);
}