On Wed, Jun 01, 2011 at 10:54:05AM +0200, Rafael Sadowski wrote: > Hello @tech, > > I hope anybody can help my with my yacc rules/grammer. I can't find bugs > in my grammer. I think the problem is in the lexer but I have no idea, > how debug it. GDB tells me: "No Source Available" for yyparse (). Any > advice, how debug it? This is my first experience with YACC! > > Maybe any yacc/lex hacker has a minute to look over my parse.y. I am > grateful for any advice. My parse.y based on ospfd and relayd.
Run yacc with -t and set yydebug = 1 in your code. That will reveal the tokens yacc sees and what it does with them. -Otto > > > My parse.y should parse stuff like this: > > network "private" { > ethernet "local-fake-lladdr" { > interface em0 > priority 2 > dhcp yes > # more options > } > > ethernet "local" { > interface em1 > priority 1 > # more options > } > > wireless "openhome" { > interface "iwn0" > priority 3 > > nwid "WLAN NAME" > bssid "00:21:6a:5f:11:92" > chan "6" > wpa { > wpakey="" > wpagroupcipher="" > wpaciphers="" > wpaakms="" > } > } > } > network "private" { > #... more ethernet and wireless stuff > } > > > But it crashed at my first "ethernet" area. "network "private" {" works, > but that is unfortunately all. > > ## parse.y > > /* > * Copyright (c) 2011 Rafael Sadowski <raf...@sizeofvoid.org> > * Copyright (c) 2010 Reyk Floeter <r...@vantronix.net> > * Copyright (c) 2004, 2005 Hans-Joerg Hoexer <hshoe...@openbsd.org> > * Copyright (c) 2002, 2003, 2004 Henning Brauer <henn...@openbsd.org> > * Copyright (c) 2001 Markus Friedl. All rights reserved. > * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. > * Copyright (c) 2001 Theo de Raadt. All rights reserved. > * > * Permission to use, copy, modify, and distribute this software for any > * purpose with or without fee is hereby granted, provided that the above > * copyright notice and this permission notice appear in all copies. > * > * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > */ > > %{ > #include <sys/types.h> > #include <sys/socket.h> > #include <sys/stat.h> > #include <sys/queue.h> > > #include <ctype.h> > #include <unistd.h> > #include <err.h> > #include <errno.h> > #include <stdio.h> > #include <string.h> > > #include "ifconfigd.h" > > TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); > static struct file { > TAILQ_ENTRY(file) entry; > FILE *stream; > char *name; > int lineno; > int errors; > } *file; > struct file *pushfile(const char *, int); > int popfile(void); > int check_file_secrecy(int, const char *); > int yyparse(void); > int yylex(void); > int yyerror(const char *, ...); > int yywarn(const char *, ...); > int kw_cmp(const void *, const void *); > int lookup(char *); > int lgetc(int); > int lungetc(int); > int findeol(void); > > TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); > struct sym { > TAILQ_ENTRY(sym) entry; > int used; > int persist; > char *nam; > char *val; > }; > int symset(const char *, const char *, int); > char *symget(const char *); > > > static struct ifconfigd_conf *conf; > static int errors = 0; > > typedef struct { > union { > int64_t number; > char *string; > } v; > int lineno; > } YYSTYPE; > %} > > /* > * BEGIN yacc Deklarationen > */ > %token BSSID CHANNEL DHCP DOMAINNAME DOMAINNAMESERVERS ETHERNET ERROR > %token INCLUDE INET INTERFACE YES > %token LLADDR MINSIGNAL NETMASK NETWORK NWID NO PRIORITY RUNDOWN RUNUP > %token UPDATEINTERVAL WEP WEPKEY WIRELESS > %token WPA WPAAKMS WPACIPHERS WPAGROUPCIPHER WPAKEY > > %token <v.string> STRING > %token <v.number> NUMBER > %type <v.string> string > %type <v.interface> interface > %type <v.number> yesno > > /* > * BEGIN yacc rules/grammer > */ > %% > grammar : /* empty */ > | grammar include '\n' > | grammar '\n' > | grammar global '\n' > | grammar varset '\n' > | grammar network '\n' > | grammar error '\n' { file->errors++; } > ; > > optnl : '\n' optnl > | > ; > > nl : '\n' optnl /* one newline or more */ > ; > > comma : ',' > | /*empty*/ > ; > > include : INCLUDE STRING { > struct file *nfile; > > if ((nfile = pushfile($2, 0)) == NULL) { > yyerror("failed to include file %s", $2); > free($2); > YYERROR; > } > free($2); > > file = nfile; > } > > varset : STRING '=' string > { > if (symset($1, $3, 0) == -1) > err(1, "cannot store variable"); > free($1); > free($3); > } > ; > > string : string STRING { > if (asprintf(&$$, "%s %s", $1, $2) == -1) { > free($1); > free($2); > yyerror("string: asprintf"); > YYERROR; > } > free($1); > free($2); > } > | STRING > ; > > yesno : YES { $$ = 1; } > | NO { $$ = 0; } > ; > > /* global configuration */ > global : UPDATEINTERVAL NUMBER { > } > ; > > /* NETWORK Section */ > network : NETWORK STRING { > } > '{' optnl networkopts_l '}' { > } > ; > > networkopts_l : networkopts_l networkoptsl nl > | networkoptsl optnl > ; > > networkoptsl : ethernet > | wireless > ; > > /* ETHERNET Section */ > ethernet : ETHERNET STRING { > } > ethernet_block { > } > ; > > ethernet_block : '{' optnl ethernetopts_l '}' > | '{' optnl '}' > | > ; > > ethernetopts_l : ethernetopts_l ethernetoptsl nl > | ethernetoptsl > ; > > ethernetoptsl : PRIORITY NUMBER { > } > | interface > | DHCP yesno { > /*if ($2 == 0) > NO > else > YES*/ > } > | staticopts > | running > ; > > /* WIRELESS Section */ > wirelessoptsl : PRIORITY NUMBER { > } > | INTERFACE STRING { > } > | BSSID STRING { > } > | CHANNEL NUMBER { > } > | MINSIGNAL NUMBER { > } > | DHCP yesno { > /*if ($2 == 0) > NO > else > YES*/ > } > | staticopts > | wpaopts > | wepopts > | running > ; > > wireless : WIRELESS STRING { > } wireless_block { > } > ; > > wireless_block : '{' optnl wirelessopts_l '}' > | '{' optnl '}' > | > ; > > wirelessopts_l : wirelessopts_l wirelessoptsl nl > | wirelessoptsl optnl > ; > > interface : INTERFACE STRING { > } > ; > running : RUNUP STRING { > } > | RUNDOWN STRING { > } > ; > staticopts : DOMAINNAME STRING { > } > | DOMAINNAMESERVERS STRING { > } > | INET STRING { > } > | NETMASK STRING { > } > | LLADDR STRING { > } > > wpaopts :WPAKEY STRING { > } > | WPAGROUPCIPHER { > } > | WPACIPHERS { > } > | WPAAKMS { > } > ; > > wepopts :WEPKEY STRING { > } > ; > > %% > struct keywords { > const char *k_name; > int k_val; > }; > > int > yyerror(const char *fmt, ...) > { > va_list ap; > > file->errors++; > va_start(ap, fmt); > fprintf(stderr, "%s: %d: ", file->name, yylval.lineno); > vfprintf(stderr, fmt, ap); > fprintf(stderr, "\n"); > va_end(ap); > return (0); > } > > int > yywarn(const char *fmt, ...) > { > va_list ap; > > va_start(ap, fmt); > fprintf(stderr, "%s: %d: ", file->name, yylval.lineno); > vfprintf(stderr, fmt, ap); > fprintf(stderr, "\n"); > va_end(ap); > return (0); > } > > int > kw_cmp(const void *k, const void *e) > { > return (strcmp(k, ((const struct keywords *)e)->k_name)); > } > > int > lookup(char *s) > { > /* this has to be sorted always */ > static const struct keywords keywords[] = { > { "bssid", BSSID }, > { "channel", CHANNEL }, > { "dhcp", DHCP }, > { "domain-name", DOMAINNAME }, > { "domain-name-servers", DOMAINNAMESERVERS }, > { "ethernet", ETHERNET }, > { "error", ERROR }, > { "include", INCLUDE }, > { "inet", INET }, > { "interface", INTERFACE }, > { "yes", YES }, > { "lladdr", LLADDR }, > { "minsignal", MINSIGNAL }, > { "netmask", NETMASK }, > { "network", NETWORK }, > { "no", NO }, > { "priority", PRIORITY }, > { "run-down", RUNDOWN }, > { "run-up", RUNUP }, > { "update_interval", UPDATEINTERVAL }, > { "wep", WEP}, > { "wepkey", WEPKEY}, > { "wpa", WPA}, > { "wpaakms", WPAAKMS }, > { "wpaciphers", WPACIPHERS }, > { "wpagroupcipher", WPAGROUPCIPHER }, > { "wpakey", WPAKEY } > }; > const struct keywords *p; > > p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), > sizeof(keywords[0]), kw_cmp); > > if (p) > return (p->k_val); > else > return (STRING); > } > > #define MAXPUSHBACK 128 > > char *parsebuf; > int parseindex; > char pushback_buffer[MAXPUSHBACK]; > int pushback_index = 0; > > int > lgetc(int quotec) > { > int c, next; > > if (parsebuf) { > /* Read character from the parsebuffer instead of input. */ > if (parseindex >= 0) { > c = parsebuf[parseindex++]; > if (c != '\0') > return (c); > parsebuf = NULL; > } else > parseindex++; > } > > if (pushback_index) > return (pushback_buffer[--pushback_index]); > > if (quotec) { > if ((c = getc(file->stream)) == EOF) { > yyerror("reached end of file while parsing quoted > string"); > if (popfile() == EOF) > return (EOF); > return (quotec); > } > return (c); > } > > while ((c = getc(file->stream)) == '\\') { > next = getc(file->stream); > if (next != '\n') { > c = next; > break; > } > yylval.lineno = file->lineno; > file->lineno++; > } > > while (c == EOF) { > if (popfile() == EOF) > return (EOF); > c = getc(file->stream); > } > return (c); > } > > int > lungetc(int c) > { > if (c == EOF) > return (EOF); > if (parsebuf) { > parseindex--; > if (parseindex >= 0) > return (c); > } > if (pushback_index < MAXPUSHBACK-1) > return (pushback_buffer[pushback_index++] = c); > else > return (EOF); > } > > int > findeol(void) > { > int c; > > parsebuf = NULL; > > /* skip to either EOF or the first real EOL */ > while (1) { > if (pushback_index) > c = pushback_buffer[--pushback_index]; > else > c = lgetc(0); > if (c == '\n') { > file->lineno++; > break; > } > if (c == EOF) > break; > } > return (ERROR); > } > > > int > yylex(void) > { > char buf[8096]; > char *p, *val; > int quotec, next, c; > int token; > > top: > p = buf; > while ((c = lgetc(0)) == ' ' || c == '\t') > ; /* nothing */ > > yylval.lineno = file->lineno; > if (c == '#') > while ((c = lgetc(0)) != '\n' && c != EOF) > ; /* nothing */ > if (c == '$' && parsebuf == NULL) { > while (1) { > if ((c = lgetc(0)) == EOF) > return (0); > > if (p + 1 >= buf + sizeof(buf) - 1) { > yyerror("string too long"); > return (findeol()); > } > if (isalnum(c) || c == '_') { > *p++ = (char)c; > continue; > } > *p = '\0'; > lungetc(c); > break; > } > val = symget(buf); > if (val == NULL) { > yyerror("macro '%s' not defined", buf); > return (findeol()); > } > parsebuf = val; > parseindex = 0; > goto top; > } > > switch (c) { > case '\'': > case '"': > quotec = c; > while (1) { > if ((c = lgetc(quotec)) == EOF) > return (0); > if (c == '\n') { > file->lineno++; > continue; > } else if (c == '\\') { > if ((next = lgetc(quotec)) == EOF) > return (0); > if (next == quotec || c == ' ' || c == '\t') > c = next; > else if (next == '\n') { > file->lineno++; > continue; > } else > lungetc(next); > } else if (c == quotec) { > *p = '\0'; > break; > } > if (p + 1 >= buf + sizeof(buf) - 1) { > yyerror("string too long"); > return (findeol()); > } > *p++ = (char)c; > } > yylval.v.string = strdup(buf); > if (yylval.v.string == NULL) > err(1, "yylex: strdup"); > return (STRING); > } > > #define allowed_to_end_number(x) \ > (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') > > if (c == '-' || isdigit(c)) { > do { > *p++ = c; > if ((unsigned)(p-buf) >= sizeof(buf)) { > yyerror("string too long"); > return (findeol()); > } > } while ((c = lgetc(0)) != EOF && isdigit(c)); > lungetc(c); > if (p == buf + 1 && buf[0] == '-') > goto nodigits; > if (c == EOF || allowed_to_end_number(c)) { > const char *errstr = NULL; > > *p = '\0'; > yylval.v.number = strtonum(buf, LLONG_MIN, > LLONG_MAX, &errstr); > if (errstr) { > yyerror("\"%s\" invalid number: %s", > buf, errstr); > return (findeol()); > } > return (NUMBER); > } else { > nodigits: > while (p > buf + 1) > lungetc(*--p); > c = *--p; > if (c == '-') > return (c); > } > } > > #define allowed_in_string(x) \ > (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ > x != '{' && x != '}' && \ > x != '!' && x != '=' && x != '#' && \ > x != ',')) > > if (isalnum(c) || c == ':' || c == '_') { > do { > *p++ = c; > if ((unsigned)(p-buf) >= sizeof(buf)) { > yyerror("string too long"); > return (findeol()); > } > } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); > lungetc(c); > *p = '\0'; > if ((token = lookup(buf)) == STRING) > if ((yylval.v.string = strdup(buf)) == NULL) > err(1, "yylex: strdup"); > return (token); > } > if (c == '\n') { > yylval.lineno = file->lineno; > file->lineno++; > } > if (c == EOF) > return (0); > return (c); > } > > int > check_file_secrecy(int fd, const char *fname) > { > struct stat st; > > if (fstat(fd, &st)) { > warn("cannot stat %s", fname); > return (-1); > } > if (st.st_uid != 0 && st.st_uid != getuid()) { > warnx("%s: owner not root or current user", fname); > return (-1); > } > if (st.st_mode & (S_IRWXG | S_IRWXO)) { > warnx("%s: group/world readable/writeable", fname); > return (-1); > } > return (0); > } > > struct file * > pushfile(const char *name, int secret) > { > struct file *nfile; > > if ((nfile = calloc(1, sizeof(struct file))) == NULL) { > warn("malloc"); > return (NULL); > } > if ((nfile->name = strdup(name)) == NULL) { > warn("malloc"); > free(nfile); > return (NULL); > } > if (TAILQ_FIRST(&files) == NULL && strcmp(nfile->name, "-") == 0) { > nfile->stream = stdin; > free(nfile->name); > if ((nfile->name = strdup("stdin")) == NULL) { > warn("strdup"); > free(nfile); > return (NULL); > } > } else if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { > warn("%s", nfile->name); > free(nfile->name); > free(nfile); > return (NULL); > } else if (secret && > check_file_secrecy(fileno(nfile->stream), nfile->name)) { > fclose(nfile->stream); > free(nfile->name); > free(nfile); > return (NULL); > } > nfile->lineno = 1; > TAILQ_INSERT_TAIL(&files, nfile, entry); > return (nfile); > } > > int > popfile(void) > { > struct file *prev; > > if ((prev = TAILQ_PREV(file, files, entry)) != NULL) { > prev->errors += file->errors; > TAILQ_REMOVE(&files, file, entry); > fclose(file->stream); > free(file->name); > free(file); > file = prev; > return (0); > } > return (EOF); > } > > struct ifconfigd_conf * > parse_config(const char *filename, int opts) > { > /*struct sym *sym, *next;*/ > > if ((conf = calloc(1, sizeof(struct ifconfigd_conf))) == NULL) > return (NULL); > > if ((file = pushfile(filename, 0)) == NULL) { > free(conf); > return (NULL); > } > > yyparse(); > errors = file->errors; > popfile(); > > > if (errors) > return (NULL); > > return (conf); > } > > int > symset(const char *nam, const char *val, int persist) > { > struct sym *sym; > > for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam); > sym = TAILQ_NEXT(sym, entry)) > ; /* nothing */ > > if (sym != NULL) { > if (sym->persist == 1) > return (0); > else { > free(sym->nam); > free(sym->val); > TAILQ_REMOVE(&symhead, sym, entry); > free(sym); > } > } > if ((sym = calloc(1, sizeof(*sym))) == NULL) > return (-1); > > sym->nam = strdup(nam); > if (sym->nam == NULL) { > free(sym); > return (-1); > } > sym->val = strdup(val); > if (sym->val == NULL) { > free(sym->nam); > free(sym); > return (-1); > } > sym->used = 0; > sym->persist = persist; > TAILQ_INSERT_TAIL(&symhead, sym, entry); > return (0); > } > > int > cmdline_symset(char *s) > { > char *sym, *val; > int ret; > size_t len; > > if ((val = strrchr(s, '=')) == NULL) > return (-1); > > len = strlen(s) - strlen(val) + 1; > if ((sym = malloc(len)) == NULL) > errx(1, "cmdline_symset: malloc"); > > (void)strlcpy(sym, s, len); > > ret = symset(sym, val + 1, 1); > free(sym); > > return (ret); > } > > char * > symget(const char *nam) > { > struct sym *sym; > > TAILQ_FOREACH(sym, &symhead, entry) > if (strcmp(nam, sym->nam) == 0) { > sym->used = 1; > return (sym->val); > } > return (NULL); > } > > > Best regards > > Rafael > > -- > http://www.sizeofvoid.org - raf...@sizeofvoid.org > XMPP: z...@jabber.ccc.de > Key fingerprint: BDDD 91E9 28CB 3A52 3E99 61B0 C359 2691 BAC6 A3B1