1 #include "parser.h"
2 
3 #include <stdarg.h>
4 #include <stdio.h>
5 #include <string.h>
6 
7 #include "log.h"
8 
parse_error(struct parse_state * state,const char * fmt,...)9 void parse_error(struct parse_state *state, const char *fmt, ...)
10 {
11     va_list ap;
12     char buf[128];
13     int off;
14 
15     snprintf(buf, 128, "%s: %d: ", state->filename, state->line);
16     buf[127] = 0;
17     off = strlen(buf);
18 
19     va_start(ap, fmt);
20     vsnprintf(buf + off, 128 - off, fmt, ap);
21     va_end(ap);
22     buf[127] = 0;
23     ERROR("%s", buf);
24 }
25 
next_token(struct parse_state * state)26 int next_token(struct parse_state *state)
27 {
28     char *x = state->ptr;
29     char *s;
30 
31     if (state->nexttoken) {
32         int t = state->nexttoken;
33         state->nexttoken = 0;
34         return t;
35     }
36 
37     for (;;) {
38         switch (*x) {
39         case 0:
40             state->ptr = x;
41             return T_EOF;
42         case '\n':
43             x++;
44             state->ptr = x;
45             return T_NEWLINE;
46         case ' ':
47         case '\t':
48         case '\r':
49             x++;
50             continue;
51         case '#':
52             while (*x && (*x != '\n')) x++;
53             if (*x == '\n') {
54                 state->ptr = x+1;
55                 return T_NEWLINE;
56             } else {
57                 state->ptr = x;
58                 return T_EOF;
59             }
60         default:
61             goto text;
62         }
63     }
64 
65 textdone:
66     state->ptr = x;
67     *s = 0;
68     return T_TEXT;
69 text:
70     state->text = s = x;
71 textresume:
72     for (;;) {
73         switch (*x) {
74         case 0:
75             goto textdone;
76         case ' ':
77         case '\t':
78         case '\r':
79             x++;
80             goto textdone;
81         case '\n':
82             state->nexttoken = T_NEWLINE;
83             x++;
84             goto textdone;
85         case '"':
86             x++;
87             for (;;) {
88                 switch (*x) {
89                 case 0:
90                         /* unterminated quoted thing */
91                     state->ptr = x;
92                     return T_EOF;
93                 case '"':
94                     x++;
95                     goto textresume;
96                 default:
97                     *s++ = *x++;
98                 }
99             }
100             break;
101         case '\\':
102             x++;
103             switch (*x) {
104             case 0:
105                 goto textdone;
106             case 'n':
107                 *s++ = '\n';
108                 break;
109             case 'r':
110                 *s++ = '\r';
111                 break;
112             case 't':
113                 *s++ = '\t';
114                 break;
115             case '\\':
116                 *s++ = '\\';
117                 break;
118             case '\r':
119                     /* \ <cr> <lf> -> line continuation */
120                 if (x[1] != '\n') {
121                     x++;
122                     continue;
123                 }
124             case '\n':
125                     /* \ <lf> -> line continuation */
126                 state->line++;
127                 x++;
128                     /* eat any extra whitespace */
129                 while((*x == ' ') || (*x == '\t')) x++;
130                 continue;
131             default:
132                     /* unknown escape -- just copy */
133                 *s++ = *x++;
134             }
135             continue;
136         default:
137             *s++ = *x++;
138         }
139     }
140     return T_EOF;
141 }
142