Commit 379107bd authored by bbguimaraes's avatar bbguimaraes
Browse files

flex & bison: chapter 2

parent 404fe621
SUBDIRS = wc0 wc1 include concordance cross ex1 ex2 ex3
.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 = concordance
.PHONY: all clean
all: $(BIN)
concordance.c: ref.h
clean:
rm -f $(BIN) concordance.c
%option noyywrap nodefault yylineno case-insensitive
%{
char *curfilename;
#include "ref.h"
%}
%%
a |
an |
and |
are |
as |
at |
be |
but |
for |
in |
is |
it |
of |
on |
or |
that |
the |
this |
to
[a-z]+(\'(s|t))? { addref(yylineno, curfilename, yytext, 0); }
.|\n
%%
int main(int argc, char **argv) {
if(argc < 2) {
curfilename = "(stdin)";
yylineno = 1;
yylex();
} else while(*++argv) {
FILE *f = fopen(*argv, "r");
if(!f) {
perror(*argv);
return 1;
}
curfilename = *argv;
yyrestart(f);
yylineno = 1;
yylex();
fclose(f);
}
printrefs();
}
struct symbol {
char *name;
struct ref *reflist;
};
struct ref {
struct ref *next;
char *filename;
int flags;
int lineno;
};
#define NHASH 9997
struct symbol symtab[NHASH];
static struct symbol *lookup(char *sym);
static void addref(int lineno, char *filename, char *word, int flags);
static void printrefs(void);
static unsigned symhash(char *sym) {
unsigned int hash = 0;
for(unsigned c; c = *sym++;)
hash = hash * 9 ^ c;
return hash;
}
static struct symbol *lookup(char *sym) {
struct symbol *sp = &symtab[symhash(sym) % NHASH];
int scount = NHASH;
while(--scount >= 0) {
if(sp->name && strcmp(sp->name, sym) == 0)
return sp;
if(!sp->name) {
sp->name = strdup(sym);
sp->reflist = 0;
return sp;
}
if(++sp >= symtab + NHASH)
sp = symtab;
}
fputs("symbol table overflow\n", stderr);
abort();
}
static void addref(int lineno, char *filename, char *word, int flags) {
struct symbol *sp = lookup(word);
if(sp->reflist)
if(sp->reflist->lineno == lineno && sp->reflist->filename == filename)
return;
struct ref *r = malloc(sizeof(struct ref));
if(!r) {
fputs("out of space\n", stderr);
abort();
}
*r = (struct ref){
.next = sp->reflist,
.filename = filename,
.flags = flags,
.lineno = lineno,
};
sp->reflist = r;
}
static int symcompare(const void *xa, const void *xb) {
const struct symbol *a = xa;
const struct symbol *b = xb;
if(!a->name) {
if(!b->name)
return 0;
return 1;
}
if(!b->name)
return -1;
return strcmp(a->name, b->name);
}
static void printrefs(void) {
qsort(symtab, NHASH, sizeof(*symtab), symcompare);
for(struct symbol *sp = symtab; sp->name && sp < symtab + NHASH; ++sp) {
char *prevfn = NULL;
struct ref *rp = sp->reflist;
struct ref *rpp = NULL;
do {
struct ref *rpn = rp->next;
rp->next = rpp;
rpp = rp;
rp = rpn;
} while(rp);
printf("%10s", sp->name);
for(rp = rpp; rp; rp = rp->next) {
if(rp->filename == prevfn)
printf(" %d", rp->lineno);
else {
printf(" %s:%d", rp->filename, rp->lineno);
prevfn = rp->filename;
}
if(rp->flags & 1)
putchar('*');
}
putchar('\n');
}
}
BIN = cross
.PHONY: all clean
all: $(BIN)
clean:
rm -f $(BIN)
%option noyywrap nodefault yylineno
%x COMMENT
%x IFILE
UCN (\\u[0-9a-fA-F]{4}|\\U[0-9a-fA-F]{8})
EXP ([Ee][-+]?[0-9]+)
ILEN ([Uu](L|l|LL|ll)?|(L|l|LL|ll)[Uu]?)
%{
struct bufstack {
struct bufstack *prev;
YY_BUFFER_STATE bs;
int lineno;
char *filename;
FILE *f;
} *curbs = NULL;
char *curfilename;
#include "../concordance/ref.h"
#include "../include/include.h"
int defining;
%}
%%
"/*" { BEGIN(COMMENT); }
<COMMENT>"*/" { BEGIN(INITIAL); }
<COMMENT>([^*]|\n)+|.
<COMMENT><<EOF>> {
printf("%s:%d: Unterminated comment\n", curfilename, yylineno);
return 0;
}
"//".*\n
_Bool |
_Complex |
_Imaginary |
auto |
char |
const |
double |
enum |
extern |
float |
inline |
int |
long |
register |
restrict |
short |
signed |
static |
struct |
typedef |
union |
unsigned |
void |
volatile { defining = 1; }
break
case
continue
default
do
else
for
goto
if
return
sizeof
switch
while
0[0-7]*{ILEN}?
[1-9][0-9]*{ILEN}?
0[Xx][0-9a-fA-F]+{ILEN}?
([0-9]*\.[0-9]+|[0-9]+\.){EXP}?[flFL]?
[0-9]+{EXP}[flFL]?
0[Xx]([0-9a-fA-F]*\.[0-9a-fA-F]+|[0-9a-fA-F]+\.?)[Pp][-+]?[0-9]+[flFL]?
\'([^'\\]|\\['"?\\abfnrtv]|\\[0-7]{1,3}|\\[Xx][0-9a-fA-F]+|{UCN})+\'
L?\"([^"\\]|\\['"?\\abfnrtv]|\\[0-7]{1,3}|\\[Xx][0-9a-fA-F]+|{UCN})*\"
"{"|"<%"|";" { defining = 0; }
"["|"]"|"("|")"|"{"|"}"|"."|"->"
"++"|"--"|"&"|"*"|"+"|"-"|"~"|"!"
"/"|"%"|"<<"|">>"|"<"|">"|"<="|">="|"=="|"!="|"^"|"|"|"&&"|"||"
"?"|":"|";"|"..."
"="|"*="|"/="|"%="|"+="|"-="|"<<="|">>="|"&="|"^="|"|="
","|"#"|"##"
"<:"|":>"|"%>"|"%:"|"%:%:"
([_a-zA-Z]|{UCN})([_a-zA-Z0-9]|{UCN})* {
addref(yylineno, curfilename, yytext, defining);
}
[ \t\n]+
\\$
"#"" "*if.*\n
"#"" "*else.*\n
"#"" "*endif.*\n
"#"" "*define.*\n
"#"" "*line.*\n
^"#"[ \t]*include[ \t]*[\"<] { BEGIN IFILE; }
<IFILE>[^>\"]+ {
for(int c; ((c = input()) && c != '\n'););
if(!newfile(strdup(yytext)))
yyterminate();
BEGIN INITIAL;
}
<IFILE>.|\n {
fprintf(stderr, "%s:%d bad include line\n", curfilename, yylineno);
yyterminate();
}
<<EOF>> { if(!popfile()) yyterminate(); }
. { printf("%s:%d: Mystery character '%s'\n", curfilename, yylineno, yytext); }
%%
int main(int argc, char **argv) {
if(argc < 2) {
fprintf(stderr, "need filename\n");
return 1;
}
while(*++argv)
if(newfile(*argv))
yylex();
printrefs();
}
BIN = ex1
LDLIBS = -lfl
.PHONY: all clean
all: $(BIN)
clean:
rm -f $(BIN)
%x LINE
%%
^. { printf("line\n %s", yytext); BEGIN LINE; }
^\n { puts("line"); }
<LINE>\n { putchar('\n'); BEGIN INITIAL; }
<LINE>.+ { printf("%s", yytext); }
../concordance/Makefile
\ No newline at end of file
../concordance/concordance.l
\ No newline at end of file
#include <ctype.h>
struct symbol {
char *name;
struct ref *reflist;
};
struct ref {
struct ref *next;
char *filename;
int flags;
int lineno;
};
#define NHASH 9997
struct symbol symtab[NHASH];
static struct symbol *lookup(char *sym);
static void addref(int lineno, char *filename, char *word, int flags);
static void printrefs(void);
static unsigned symhash(char *sym) {
unsigned int hash = 0;
for(unsigned c; c = *sym++;)
hash = hash * 9 ^ tolower(c);
return hash;
}
static struct symbol *lookup(char *sym) {
struct symbol *sp = &symtab[symhash(sym) % NHASH];
int scount = NHASH;
while(--scount >= 0) {
if(sp->name && strcasecmp(sp->name, sym) == 0)
return sp;
if(!sp->name) {
sp->name = strdup(sym);
for(char *p = sp->name; *p; ++p)
*p = tolower(*p);
sp->reflist = 0;
return sp;
}
if(++sp >= symtab + NHASH)
sp = symtab;
}
fputs("symbol table overflow\n", stderr);
abort();
}
static void addref(int lineno, char *filename, char *word, int flags) {
struct symbol *sp = lookup(word);
if(sp->reflist)
if(sp->reflist->lineno == lineno && sp->reflist->filename == filename)
return;
struct ref *r = malloc(sizeof(struct ref));
if(!r) {
fputs("out of space\n", stderr);
abort();
}
*r = (struct ref){
.next = sp->reflist,
.filename = filename,
.flags = flags,
.lineno = lineno,
};
sp->reflist = r;
}
static int symcompare(const void *xa, const void *xb) {
const struct symbol *a = xa;
const struct symbol *b = xb;
if(!a->name) {
if(!b->name)
return 0;
return 1;
}
if(!b->name)
return -1;
return strcasecmp(a->name, b->name);
}
static void printrefs(void) {
qsort(symtab, NHASH, sizeof(*symtab), symcompare);
for(struct symbol *sp = symtab; sp->name && sp < symtab + NHASH; ++sp) {
char *prevfn = NULL;
struct ref *rp = sp->reflist;
struct ref *rpp = NULL;
do {
struct ref *rpn = rp->next;
rp->next = rpp;
rpp = rp;
rp = rpn;
} while(rp);
printf("%10s", sp->name);
for(rp = rpp; rp; rp = rp->next) {
if(rp->filename == prevfn)
printf(" %d", rp->lineno);
else {
printf(" %s:%d", rp->filename, rp->lineno);
prevfn = rp->filename;
}
if(rp->flags & 1)
putchar('*');
}
putchar('\n');
}
}
../concordance/Makefile
\ No newline at end of file
../concordance/concordance.l
\ No newline at end of file
struct symbol {
char *name;
struct ref *reflist;
};
struct ref {
struct ref *next;
char *filename;
int flags;
int lineno;
};
size_t nhash;
struct symbol *symtab;
static void resize(void);
static struct symbol *lookup(char *sym);
static void addref(int lineno, char *filename, char *word, int flags);
static void printrefs(void);
static unsigned symhash(char *sym) {
unsigned int hash = 0;
for(unsigned c; c = *sym++;)
hash = hash * 9 ^ c;
return hash;
}
static struct symbol *lookup(char *sym) {
const size_t m = nhash - 1;
for(size_t i = symhash(sym), e = i + nhash; i != e; ++i) {
struct symbol *const p = symtab + (i & m);
if(!p->name || strcmp(p->name, sym) == 0)
return p;
}
resize();
return lookup(sym);
}
static void resize(void) {
const struct symbol *p = symtab, *const e = p + nhash;
nhash = nhash ? nhash * 2 : 1;
symtab = calloc(nhash, sizeof(*symtab));
for(; p != e; ++p)
if(p->name)
*lookup(p->name) = *p;
}
static void addref(int lineno, char *filename, char *word, int flags) {
struct symbol *sp = lookup(word);
if(!sp->name)
sp->name = strdup(word);
if(sp->reflist)
if(sp->reflist->lineno == lineno && sp->reflist->filename == filename)
return;
struct ref *r = malloc(sizeof(struct ref));
if(!r) {
fputs("out of space\n", stderr);
abort();
}
*r = (struct ref){
.next = sp->reflist,
.filename = filename,
.flags = flags,
.lineno = lineno,
};
sp->reflist = r;
}
static int symcompare(const void *xa, const void *xb) {
const struct symbol *a = xa;
const struct symbol *b = xb;
if(!a->name) {
if(!b->name)
return 0;
return 1;
}
if(!b->name)
return -1;
return strcmp(a->name, b->name);
}
static void printrefs(void) {
qsort(symtab, nhash, sizeof(*symtab), symcompare);
for(struct symbol *sp = symtab; sp->name && sp < symtab + nhash; ++sp) {
char *prevfn = NULL;
struct ref *rp = sp->reflist;
struct ref *rpp = NULL;
do {
struct ref *rpn = rp->next;
rp->next = rpp;
rpp = rp;
rp = rpn;
} while(rp);
printf("%10s", sp->name);
for(rp = rpp; rp; rp = rp->next) {
if(rp->filename == prevfn)
printf(" %d", rp->lineno);
else {
printf(" %s:%d", rp->filename, rp->lineno);
prevfn = rp->filename;
}
if(rp->flags & 1)
putchar('*');
}
putchar('\n');
}
}
/*
* 0.h
*/
void f0(void);
/*
* 1.h
*/
void f1(void);
BIN = include
.PHONY: all clean
all: $(BIN)
include.c: include.h
clean:
rm -f $(BIN) include.c
static int newfile(char *fn) {
FILE *f = fopen(fn, "r");
struct bufstack *bs = malloc(sizeof(*bs));
if(!f) {
perror(fn);
return 0;
}
if(!bs) {
perror("malloc");
exit(1);
}
if(curbs)
curbs->lineno = yylineno;
*bs = (struct bufstack){
.prev = curbs,
.bs = yy_create_buffer(f, YY_BUF_SIZE),
.filename = fn,
.f = f,
};
yy_switch_to_buffer(bs->bs);
curbs = bs;
yylineno = 1;
curfilename = fn;
return 1;
}
static int popfile(void) {