1 /*-
2 * Copyright (c) 2007,2008 Igor Serikov
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. The copyright holders make no representations about the
9 * suitability of this software for any purpose. It is provided "as is"
10 * without express or implied warranty.
11 *
12 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
13 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
14 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
15 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
16 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
17 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
18 * PERFORMANCE OF THIS SOFTWARE.
19 */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <limits.h>
25 #include <ctype.h>
26 #include <stdarg.h>
27 #include <sys/param.h>
28
29 #include "scanner.h"
30 #include "util.h"
31
32 char Token [MAXPATHLEN + 1];
33 int Number;
34
35 typedef struct SOURCE SOURCE;
36
37 struct SOURCE {
38 SOURCE* Prev;
39 FILE* File;
40 char * FileName;
41 int Line;
42 };
43
44 static SOURCE * Src = NULL;
45 static int TokenType, Expected = 0, Reinit = 0;
46
47 /* Mind prefetched token. */
OpenScanner(char * Fn)48 void OpenScanner (char * Fn) {
49 SOURCE * tsrc;
50
51 if (!Reinit) {
52 tsrc = (SOURCE*) Alloc (sizeof (SOURCE));
53 tsrc->Prev = Src;
54 Src = tsrc;
55 } else {
56 Reinit = 0;
57 Expected = 0;
58 free (Src->FileName);
59 }
60 Src->FileName = DupStr (Fn);
61 Src->Line = 1;
62 Src->File = fopen (Src->FileName, "r");
63 if (!Src->File)
64 Err ("cannot open %s", Src->FileName);
65 }
66
GetToken(void)67 static inline void GetToken (void) {
68 int i, c;
69 char ** wa;
70 SOURCE * tsrc;
71
72 do {
73 again:
74 c = fgetc (Src->File);
75 if (ferror (Src->File))
76 have_error: Err ("error reading %s", Src->FileName);
77 if (c == -1) {
78 have_eof:
79 fclose (Src->File);
80 if (Src->Prev) {
81 free (Src->FileName);
82 tsrc = Src;
83 Src = Src->Prev;
84 free (tsrc);
85 goto again;
86 }
87 Reinit = 1;
88 TokenType = w_eof;
89 return;
90 }
91 if (c == '\n') {
92 Src->Line ++;
93 goto again;
94 }
95 if (c == '#') {
96 do {
97 c = fgetc (Src->File);
98 if (ferror (Src->File))
99 goto have_error;
100 if (c == -1)
101 goto have_eof;
102 } while (c != '\n');
103 Src->Line ++;
104 goto again;
105 }
106 } while (isspace (c));
107
108 if (c >= '0' && c <= '9') {
109 Number = c - '0';
110 for (;;) {
111 c = fgetc (Src->File);
112 if (ferror (Src->File))
113 goto have_error;
114 if (c < '0' || c > '9') {
115 if (c != -1 && (c == '_' || isalpha (c)))
116 Syntax ("invalid integer");
117 ungetc (c, Src->File);
118 TokenType = w_number;
119 return;
120 }
121 if (Number > INT_MAX / 10)
122 iover: Syntax ("integer overflow");
123 Number *= 10;
124 c -= '0';
125 Number += c;
126 if (Number < 0)
127 goto iover;
128 }
129 }
130
131 if (c == '"') {
132 i = 0;
133 for (;;) {
134 c = fgetc (Src->File);
135 if (ferror (Src->File))
136 goto have_error;
137 if (c == -1 || c == '\n')
138 have_unterm: Syntax ("unterminated quoted string");
139 if (c == '"') {
140 Token [i] = 0;
141 TokenType = w_string;
142 return;
143 }
144 if (i > (int) sizeof Token - 1)
145 Syntax ("too long quoted string");
146 if (c == '\\') {
147 c = fgetc (Src->File);
148 if (ferror (Src->File))
149 goto have_error;
150 switch (c) {
151 case -1:
152 case '\n':
153 goto have_unterm;
154 case '\\':
155 c = '\\';
156 break;
157 case '"':
158 c = '"';
159 break;
160 case 't':
161 c = '\t';
162 break;
163 case 'r':
164 c = '\r';
165 break;
166 case 'n':
167 c = '\n';
168 break;
169 case 'b':
170 c = '\b';
171 break;
172 default:
173 Syntax ("invalid escape sequence");
174 }
175 }
176 Token [i] = (char) c;
177 i ++;
178 }
179 }
180
181 if (c != '_' && !isalpha (c)) {
182 for (wa = SymbolTable, TokenType = w_app; *wa; wa ++, TokenType ++)
183 if ((*wa) [0] == c)
184 return;
185 Syntax ("invalid character '%c'", c);
186 }
187
188 i = 0;
189
190 do {
191 if (i > (int) sizeof Token - 1)
192 Syntax ("too long token");
193 Token [i] = (char) c;
194 i ++;
195 c = fgetc (Src->File);
196 if (ferror (Src->File))
197 goto have_error;
198 } while (c == '_' || (c >= '0' && c <= '9') || isalpha (c));
199
200 ungetc (c, Src->File);
201
202 Token [i] = 0;
203
204 for (wa = SymbolTable, TokenType = w_app; *wa; wa ++, TokenType ++)
205 if (strcmp (*wa, Token) == 0)
206 return;
207
208 TokenType = w_name;
209 }
210
Expect(int Type)211 int Expect (int Type) {
212 if (Expected == 0)
213 GetToken ();
214 if (Type != TokenType) {
215 Expected |= (int) 1 << Type;
216 return 0;
217 }
218 Expected = 0;
219 return 1;
220 }
221
MustBe(int Type)222 void MustBe (int Type) {
223 if (!Expect (Type))
224 Unexpected ();
225 }
226
Syntax(char * Str,...)227 void __attribute__((__noreturn__)) Syntax (char * Str, ...) {
228 va_list args;
229
230 fprintf (stderr, "%s: %s(%u): ", GetProgName (), Src->FileName, Src->Line);
231
232 va_start (args, Str);
233 vfprintf (stderr, Str, args);
234
235 fputc ('\n', stderr);
236
237 exit (1);
238 }
239
Unexpected(void)240 void __attribute__((__noreturn__)) Unexpected (void) {
241 static char * strs [] = { "end of file", "numeral", "quoted string", "name"};
242
243 int nf, n;
244 char c;
245
246 fprintf (stderr, "%s: %s(%u): expected: ", GetProgName (), Src->FileName, Src->Line);
247
248 nf = n = 0;
249 for (n = 0; Expected; n ++, Expected >>= 1)
250 if (Expected & 1) {
251 if (nf)
252 fputc (' ', stderr);
253 nf = 1;
254 if (n < w_app)
255 fprintf (stderr, "%s", strs [n]);
256 else {
257 c = SymbolTable [n - w_app] [0];
258 if (c != '_' && !isalpha (c))
259 fprintf (stderr, "'%c'", c);
260 else
261 fprintf (stderr, "\"%s\"", SymbolTable [n - w_app]);
262 }
263 }
264
265 fputc ('\n', stderr);
266
267 exit (1);
268 }
269