| #include "parser.h" | |
| #include <stdarg.h> | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include "log.h" | |
| void parse_error(struct parse_state *state, const char *fmt, ...) | |
| { | |
| va_list ap; | |
| char buf[128]; | |
| int off; | |
| snprintf(buf, 128, "%s: %d: ", state->filename, state->line); | |
| buf[127] = 0; | |
| off = strlen(buf); | |
| va_start(ap, fmt); | |
| vsnprintf(buf + off, 128 - off, fmt, ap); | |
| va_end(ap); | |
| buf[127] = 0; | |
| ERROR("%s", buf); | |
| } | |
| int next_token(struct parse_state *state) | |
| { | |
| char *x = state->ptr; | |
| char *s; | |
| if (state->nexttoken) { | |
| int t = state->nexttoken; | |
| state->nexttoken = 0; | |
| return t; | |
| } | |
| for (;;) { | |
| switch (*x) { | |
| case 0: | |
| state->ptr = x; | |
| return T_EOF; | |
| case '\n': | |
| x++; | |
| state->ptr = x; | |
| return T_NEWLINE; | |
| case ' ': | |
| case '\t': | |
| case '\r': | |
| x++; | |
| continue; | |
| case '#': | |
| while (*x && (*x != '\n')) x++; | |
| if (*x == '\n') { | |
| state->ptr = x+1; | |
| return T_NEWLINE; | |
| } else { | |
| state->ptr = x; | |
| return T_EOF; | |
| } | |
| default: | |
| goto text; | |
| } | |
| } | |
| textdone: | |
| state->ptr = x; | |
| *s = 0; | |
| return T_TEXT; | |
| text: | |
| state->text = s = x; | |
| textresume: | |
| for (;;) { | |
| switch (*x) { | |
| case 0: | |
| goto textdone; | |
| case ' ': | |
| case '\t': | |
| case '\r': | |
| x++; | |
| goto textdone; | |
| case '\n': | |
| state->nexttoken = T_NEWLINE; | |
| x++; | |
| goto textdone; | |
| case '"': | |
| x++; | |
| for (;;) { | |
| switch (*x) { | |
| case 0: | |
| /* unterminated quoted thing */ | |
| state->ptr = x; | |
| return T_EOF; | |
| case '"': | |
| x++; | |
| goto textresume; | |
| default: | |
| *s++ = *x++; | |
| } | |
| } | |
| break; | |
| case '\\': | |
| x++; | |
| switch (*x) { | |
| case 0: | |
| goto textdone; | |
| case 'n': | |
| *s++ = '\n'; | |
| break; | |
| case 'r': | |
| *s++ = '\r'; | |
| break; | |
| case 't': | |
| *s++ = '\t'; | |
| break; | |
| case '\\': | |
| *s++ = '\\'; | |
| break; | |
| case '\r': | |
| /* \ <cr> <lf> -> line continuation */ | |
| if (x[1] != '\n') { | |
| x++; | |
| continue; | |
| } | |
| case '\n': | |
| /* \ <lf> -> line continuation */ | |
| state->line++; | |
| x++; | |
| /* eat any extra whitespace */ | |
| while((*x == ' ') || (*x == '\t')) x++; | |
| continue; | |
| default: | |
| /* unknown escape -- just copy */ | |
| *s++ = *x++; | |
| } | |
| continue; | |
| default: | |
| *s++ = *x++; | |
| } | |
| } | |
| return T_EOF; | |
| } |