162 lines
3.2 KiB
Text
162 lines
3.2 KiB
Text
%{
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "tökin.h"
|
|
|
|
struct node *literal(char *text);
|
|
struct node *identifier(char *name);
|
|
struct node *operation(int operator, int arity, ...);
|
|
void free_node(struct node *p);
|
|
|
|
void print_tree(struct node *p, int nesting);
|
|
|
|
int yylex(void);
|
|
void yyerror(const char *);
|
|
%}
|
|
|
|
%union {
|
|
char *text;
|
|
struct node *node;
|
|
};
|
|
|
|
%token <text> NUMBER IDENTIFIER
|
|
%token GE LE EQ NE
|
|
%token ERROR APPLICATION
|
|
|
|
%type <node> statement place
|
|
%type <node> expr expr1 expr2 expr3 expr4 expr5 expr6
|
|
%type <node> term parenthesized parenthesized_statements
|
|
|
|
%%
|
|
|
|
toplevel:
|
|
toplevel statement '\n' { print_tree($2, 0); free_node($2); }
|
|
|
|
|
;
|
|
|
|
statement:
|
|
place '=' expr { $$ = operation('=', 2, $1, $3); }
|
|
| expr { $$ = $1; }
|
|
;
|
|
|
|
place:
|
|
IDENTIFIER { $$ = identifier($1); }
|
|
|
|
expr:
|
|
expr1 { $$ = $1; }
|
|
| expr '|' expr1 { $$ = operation('|', 2, $1, $3); }
|
|
;
|
|
|
|
expr1:
|
|
expr2 { $$ = $1; }
|
|
| expr1 '<' expr2 { $$ = operation('<', 2, $1, $3); }
|
|
| expr1 '>' expr2 { $$ = operation('>', 2, $1, $3); }
|
|
| expr1 GE expr2 { $$ = operation(GE, 2, $1, $3); }
|
|
| expr1 LE expr2 { $$ = operation(LE, 2, $1, $3); }
|
|
| expr1 NE expr2 { $$ = operation(NE, 2, $1, $3); }
|
|
| expr1 EQ expr2 { $$ = operation(EQ, 2, $1, $3); }
|
|
;
|
|
|
|
expr2:
|
|
expr3 { $$ = $1; }
|
|
| expr2 '+' expr3 { $$ = operation('+', 2, $1, $3); }
|
|
| expr2 '-' expr3 { $$ = operation('-', 2, $1, $3); }
|
|
;
|
|
|
|
expr3:
|
|
expr4 { $$ = $1; }
|
|
| expr3 '*' expr4 { $$ = operation('*', 2, $1, $3); }
|
|
| expr3 '/' expr4 { $$ = operation('/', 2, $1, $3); }
|
|
;
|
|
|
|
expr4:
|
|
expr5 { $$ = $1; }
|
|
| expr5 '^' expr4 { $$ = operation('^', 2, $1, $3); }
|
|
|
|
expr5:
|
|
expr6 { $$ = $1; }
|
|
| '-' expr6 { $$ = operation('-', 1, $2); }
|
|
;
|
|
|
|
expr6:
|
|
term { $$ = $1; }
|
|
| expr6 term { $$ = operation(APPLICATION, 2, $1, $2); }
|
|
;
|
|
|
|
term:
|
|
NUMBER { $$ = literal($1); }
|
|
| IDENTIFIER { $$ = identifier($1); }
|
|
| '(' parenthesized ')' { $$ = $2; }
|
|
;
|
|
|
|
parenthesized:
|
|
expr { $$ = $1; }
|
|
| parenthesized_statements ';' expr { $$ = operation(';', 2, $1, $3); }
|
|
;
|
|
|
|
parenthesized_statements:
|
|
statement { $$ = $1; }
|
|
| parenthesized_statements ';' statement { $$ = operation(';', 2, $1, $3); }
|
|
|
|
%%
|
|
|
|
struct node *literal(char *text) {
|
|
struct node *p = malloc(sizeof(struct node));
|
|
if (p == NULL)
|
|
yyerror("out of memory");
|
|
p->type = literal_node;
|
|
p->text = text;
|
|
return p;
|
|
}
|
|
|
|
struct node *identifier(char *name) {
|
|
struct node *p = malloc(sizeof(struct node));
|
|
if (p == NULL)
|
|
yyerror("out of memory");
|
|
p->type = identifier_node;
|
|
p->text = name;
|
|
return p;
|
|
}
|
|
|
|
struct node *operation(int operator, int arity, ...) {
|
|
struct node *p = malloc(sizeof(struct node) + arity * sizeof(struct node *));
|
|
if (p == NULL)
|
|
yyerror("out of memory");
|
|
p->type = operation_node;
|
|
p->op.operator = operator;
|
|
p->op.arity = arity;
|
|
|
|
va_list ap;
|
|
va_start(ap, arity);
|
|
for (int i = 0; i < arity; i++)
|
|
p->op.operands[i] = va_arg(ap, struct node *);
|
|
va_end(ap);
|
|
|
|
return p;
|
|
}
|
|
|
|
void free_node(struct node *p) {
|
|
if (p == NULL)
|
|
return;
|
|
switch (p->type) {
|
|
case literal_node:
|
|
case identifier_node:
|
|
free(p->text);
|
|
break;
|
|
case operation_node:
|
|
for (int i = 0; i < p->op.arity; i++)
|
|
free_node(p->op.operands[i]);
|
|
break;
|
|
}
|
|
free(p);
|
|
}
|
|
|
|
void yyerror(const char *s) {
|
|
fprintf(stderr, "%s\n", s);
|
|
}
|
|
|
|
int main(void) {
|
|
yyparse();
|
|
return 0;
|
|
}
|