version 1.8, 2015/07/21 16:12:04 |
version 1.9, 2015/07/22 20:15:24 |
|
|
int |
int |
yylex(void) |
yylex(void) |
{ |
{ |
|
static int colno = 1, lineno = 1; |
|
|
char buf[1024], *ebuf, *p, *str; |
char buf[1024], *ebuf, *p, *str; |
int i, c, next; |
int i, c, quotes = 0, escape = 0, qpos = 0, nonkw = 0; |
|
|
p = buf; |
p = buf; |
ebuf = buf + sizeof(buf); |
ebuf = buf + sizeof(buf); |
|
|
repeat: |
repeat: |
c = getc(yyfp); |
/* skip whitespace first */ |
|
for (c = getc(yyfp); c == ' ' || c == '\t'; c = getc(yyfp)) |
|
colno++; |
|
|
|
/* check for special one-character constructions */ |
switch (c) { |
switch (c) { |
case ' ': |
case '\n': |
case '\t': |
colno = 1; |
goto repeat; /* skip spaces */ |
lineno++; |
case '\\': |
/* FALLTHROUGH */ |
next = getc(yyfp); |
case '{': |
if (next == '\n') |
case '}': |
goto repeat; |
return c; |
else |
case '#': |
c = next; |
/* skip comments; NUL is allowed; no continuation */ |
case '\n': |
while ((c = getc(yyfp)) != '\n') |
case '{': |
if (c == EOF) |
case '}': |
return 0; |
return c; |
colno = 1; |
case '#': |
lineno++; |
while ((c = getc(yyfp)) != '\n' && c != EOF) |
return c; |
; /* skip comments */ |
case EOF: |
if (c == EOF) |
|
return 0; |
return 0; |
return c; |
|
case EOF: |
|
return 0; |
|
} |
} |
while (1) { |
|
|
/* parsing next word */ |
|
for (;; c = getc(yyfp), colno++) { |
switch (c) { |
switch (c) { |
|
case '\0': |
|
yyerror("unallowed character NUL at " |
|
"line %d, column %d", lineno, colno); |
|
escape = 0; |
|
continue; |
|
case '\\': |
|
escape = !escape; |
|
if (escape) |
|
continue; |
|
break; |
case '\n': |
case '\n': |
|
if (quotes) |
|
yyerror("unterminated quotes at line %d, column %d", |
|
lineno, qpos); |
|
if (escape) { |
|
nonkw = 1; |
|
escape = 0; |
|
continue; |
|
} |
|
goto eow; |
|
case EOF: |
|
if (escape) |
|
yyerror("unterminated escape at line %d, column %d", |
|
lineno, colno - 1); |
|
if (quotes) |
|
yyerror("unterminated quotes at line %d, column %d", |
|
lineno, qpos); |
|
/* FALLTHROUGH */ |
case '{': |
case '{': |
case '}': |
case '}': |
case '#': |
case '#': |
case ' ': |
case ' ': |
case '\t': |
case '\t': |
case EOF: |
if (!escape && !quotes) |
goto eow; |
goto eow; |
|
break; |
|
case '"': |
|
if (!escape) { |
|
quotes = !quotes; |
|
if (quotes) { |
|
nonkw = 1; |
|
qpos = colno; |
|
} |
|
continue; |
|
} |
} |
} |
*p++ = c; |
*p++ = c; |
if (p == ebuf) |
if (p == ebuf) |
yyerror("too much stuff"); |
yyerror("too long line %d", lineno); |
c = getc(yyfp); |
escape = 0; |
} |
} |
|
|
eow: |
eow: |
*p = 0; |
*p = 0; |
if (c != EOF) |
if (c != EOF) |
ungetc(c, yyfp); |
ungetc(c, yyfp); |
for (i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) { |
if (p == buf) { |
if (strcmp(buf, keywords[i].word) == 0) |
/* |
return keywords[i].token; |
* There could be a number of reasons for empty buffer, and we handle |
|
* all of them here, to avoid cluttering the main loop. |
|
*/ |
|
if (c == EOF) |
|
return 0; |
|
else if (!qpos) /* accept, e.g., empty args: cmd foo args "" */ |
|
goto repeat; |
|
} |
|
if (!nonkw) { |
|
for (i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) { |
|
if (strcmp(buf, keywords[i].word) == 0) |
|
return keywords[i].token; |
|
} |
} |
} |
if ((str = strdup(buf)) == NULL) |
if ((str = strdup(buf)) == NULL) |
err(1, "strdup"); |
err(1, "strdup"); |