tokin/tökin.y
2025-03-10 17:39:02 +02:00

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;
}