Commit f6fd2a1f authored by bbguimaraes's avatar bbguimaraes
Browse files

flex & bison: chapter 3

parent babd9451
SUBDIRS = calc0 calc1
.PHONY: all clean
all:
for x in $(SUBDIRS); do $(MAKE) -C "$$x"; done
clean:
for x in $(SUBDIRS); do $(MAKE) -C "$$x" clean; done
BIN = calc
LDLIBS = -lfl
%.tab.c %.tab.h: %.y
bison -d $<
.PHONY: all clean
all: $(BIN)
lex.c: calc.h calc.tab.h
calc_c.o: calc.h calc.tab.h
calc: lex.o calc_c.o
clean:
rm -f $(BIN) calc.c calc.tab.[hc] lex.[co] calc_c.o
extern int yylineno;
int yylex(void);
int yyparse(void);
void yyerror(char *s, ...);
struct ast {
int nodetype;
struct ast *l, *r;
};
struct numval {
int nodetype;
double number;
};
struct ast *newast(int nodetype, struct ast *l, struct ast *r);
struct ast *newnum(double d);
double eval(struct ast *a);
void treefree(struct ast *a);
%{
#include <stdio.h>
#include <stdlib.h>
#include "calc.h"
%}
%union {
struct ast *a;
double d;
}
%token <d> NUMBER
%token EOL
%type <a> exp factor term
%%
calclist:
| calclist exp EOL {
printf("= %4.4g\n", eval($2));
treefree($2);
printf("> ");
}
| calclist EOL { printf("> "); }
;
exp: factor
| exp '+' factor { $$ = newast('+', $1, $3); }
| exp '-' factor { $$ = newast('-', $1, $3); }
;
factor: term
| factor '*' term { $$ = newast('*', $1, $3); }
| factor '/' term { $$ = newast('/', $1, $3); }
;
term: NUMBER { $$ = newnum($1); }
| '|' term { $$ = newast('|', $2, NULL); }
| '(' exp ')' { $$ = $2; }
| '-' term { $$ = newast('M', $2, NULL); }
;
%%
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include "calc.h"
struct ast *newast(int nodetype, struct ast *l, struct ast *r) {
struct ast *ret = malloc(sizeof(*ret));
if(!ret) {
yyerror("out of space");
exit(1);
}
*ret = (struct ast){
.nodetype = nodetype,
.l = l,
.r = r,
};
return ret;
}
struct ast *newnum(double d) {
struct numval *ret = malloc(sizeof(*ret));
if(!ret) {
yyerror("out of space");
exit(1);
}
*ret = (struct numval){
.nodetype = 'K',
.number = d,
};
return (struct ast*)ret;
}
double eval(struct ast *a) {
switch(a->nodetype) {
case 'K': return ((struct numval*)a)->number;
case '+': return eval(a->l) + eval(a->r);
case '-': return eval(a->l) - eval(a->r);
case '*': return eval(a->l) * eval(a->r);
case '/': return eval(a->l) / eval(a->r);
case '|': double v = eval(a->l); return v < 0 ? -v : v;
case 'M': return -eval(a->l);
default:
fprintf(stderr, "internal error: bad node %c\n", a->nodetype);
return 0;
}
}
void treefree(struct ast *a) {
switch(a->nodetype) {
case '+':
case '-':
case '*':
case '/': treefree(a->r); [[fallthrough]]
case '|':
case 'M': treefree(a->l); [[fallthrough]]
case 'K': free(a); break;
default: fprintf(stderr, "internal error: free bad node %c\n", a->nodetype);
}
}
void yyerror(char *s, ...) {
va_list ap;
va_start(ap, s);
fprintf(stderr, "%d: error: ", yylineno);
vfprintf(stderr, s, ap);
fputc('\n', stderr);
}
int main(void) {
printf("> ");
return yyparse();
}
%option noyywrap nodefault yylineno
%{
#include "calc.h"
#include "calc.tab.h"
%}
EXP ([Ee][+-]?[0-9]+)
%%
"+" |
"-" |
"*" |
"/" |
"|" |
"(" |
")" { return *yytext; }
[0-9]+"."[0-9]*{EXP}? |
"."?[0-9]+{EXP}? { yylval.d = atof(yytext); return NUMBER; }
\n { return EOL; }
"//".*
[ \t]
. { yyerror("Mystery character %c\n", *yytext); }
%%
../calc0/Makefile
\ No newline at end of file
../calc0/calc.h
\ No newline at end of file
%{
#include <stdio.h>
#include <stdlib.h>
#include "calc.h"
%}
%union {
struct ast *a;
double d;
}
%token <d> NUMBER
%token EOL
%left '+' '-'
%left '*' '/'
%nonassoc '|' UMINUS
%type <a> exp
%%
calclist:
| calclist exp EOL {
printf("= %4.4g\n", eval($2));
treefree($2);
printf("> ");
}
| calclist EOL { printf("> "); }
;
exp: exp '+' exp { $$ = newast('+', $1, $3); }
| exp '-' exp { $$ = newast('-', $1, $3); }
| exp '*' exp { $$ = newast('*', $1, $3); }
| exp '/' exp { $$ = newast('/', $1, $3); }
| '|' exp { $$ = newast('|', $2, NULL); }
| NUMBER { $$ = newnum($1); }
| '-' exp %prec UMINUS { $$ = newast('M', $2, NULL); }
| '(' exp ')' { $$ = $2; }
;
%%
../calc0/calc_c.c
\ No newline at end of file
../calc0/lex.l
\ No newline at end of file
SUBDIRS = 1 2
SUBDIRS = 1 2 3
.PHONY: all clean
all:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment