diff options
author | Pavel Labath <pavelo@centrum.sk> | 2011-05-16 10:58:21 (GMT) |
---|---|---|
committer | Pavel Labath <pavelo@centrum.sk> | 2011-06-15 15:33:48 (GMT) |
commit | d4c5d99bcbf614e31e4f724319437e82d7f2a208 (patch) | |
tree | 84028219313ee62cc4bcccec2e3e2604e56c9dac /libs/lua/src/llex.c | |
parent | db243c1d343781a1466e1b863e174427cd37e37f (diff) | |
download | fluxbox_pavel-d4c5d99bcbf614e31e4f724319437e82d7f2a208.zip fluxbox_pavel-d4c5d99bcbf614e31e4f724319437e82d7f2a208.tar.bz2 |
Add lua as an internal library in libs/lua
Diffstat (limited to 'libs/lua/src/llex.c')
-rw-r--r-- | libs/lua/src/llex.c | 461 |
1 files changed, 461 insertions, 0 deletions
diff --git a/libs/lua/src/llex.c b/libs/lua/src/llex.c new file mode 100644 index 0000000..6dc3193 --- /dev/null +++ b/libs/lua/src/llex.c | |||
@@ -0,0 +1,461 @@ | |||
1 | /* | ||
2 | ** $Id: llex.c,v 2.20.1.1 2007/12/27 13:02:25 roberto Exp $ | ||
3 | ** Lexical Analyzer | ||
4 | ** See Copyright Notice in lua.h | ||
5 | */ | ||
6 | |||
7 | |||
8 | #include <ctype.h> | ||
9 | #include <locale.h> | ||
10 | #include <string.h> | ||
11 | |||
12 | #define llex_c | ||
13 | #define LUA_CORE | ||
14 | |||
15 | #include "lua.h" | ||
16 | |||
17 | #include "ldo.h" | ||
18 | #include "llex.h" | ||
19 | #include "lobject.h" | ||
20 | #include "lparser.h" | ||
21 | #include "lstate.h" | ||
22 | #include "lstring.h" | ||
23 | #include "ltable.h" | ||
24 | #include "lzio.h" | ||
25 | |||
26 | |||
27 | |||
28 | #define next(ls) (ls->current = zgetc(ls->z)) | ||
29 | |||
30 | |||
31 | |||
32 | |||
33 | #define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r') | ||
34 | |||
35 | |||
36 | /* ORDER RESERVED */ | ||
37 | const char *const luaX_tokens [] = { | ||
38 | "and", "break", "do", "else", "elseif", | ||
39 | "end", "false", "for", "function", "if", | ||
40 | "in", "local", "nil", "not", "or", "repeat", | ||
41 | "return", "then", "true", "until", "while", | ||
42 | "..", "...", "==", ">=", "<=", "~=", | ||
43 | "<number>", "<name>", "<string>", "<eof>", | ||
44 | NULL | ||
45 | }; | ||
46 | |||
47 | |||
48 | #define save_and_next(ls) (save(ls, ls->current), next(ls)) | ||
49 | |||
50 | |||
51 | static void save (LexState *ls, int c) { | ||
52 | Mbuffer *b = ls->buff; | ||
53 | if (b->n + 1 > b->buffsize) { | ||
54 | size_t newsize; | ||
55 | if (b->buffsize >= MAX_SIZET/2) | ||
56 | luaX_lexerror(ls, "lexical element too long", 0); | ||
57 | newsize = b->buffsize * 2; | ||
58 | luaZ_resizebuffer(ls->L, b, newsize); | ||
59 | } | ||
60 | b->buffer[b->n++] = cast(char, c); | ||
61 | } | ||
62 | |||
63 | |||
64 | void luaX_init (lua_State *L) { | ||
65 | int i; | ||
66 | for (i=0; i<NUM_RESERVED; i++) { | ||
67 | TString *ts = luaS_new(L, luaX_tokens[i]); | ||
68 | luaS_fix(ts); /* reserved words are never collected */ | ||
69 | lua_assert(strlen(luaX_tokens[i])+1 <= TOKEN_LEN); | ||
70 | ts->tsv.reserved = cast_byte(i+1); /* reserved word */ | ||
71 | } | ||
72 | } | ||
73 | |||
74 | |||
75 | #define MAXSRC 80 | ||
76 | |||
77 | |||
78 | const char *luaX_token2str (LexState *ls, int token) { | ||
79 | if (token < FIRST_RESERVED) { | ||
80 | lua_assert(token == cast(unsigned char, token)); | ||
81 | return (iscntrl(token)) ? luaO_pushfstring(ls->L, "char(%d)", token) : | ||
82 | luaO_pushfstring(ls->L, "%c", token); | ||
83 | } | ||
84 | else | ||
85 | return luaX_tokens[token-FIRST_RESERVED]; | ||
86 | } | ||
87 | |||
88 | |||
89 | static const char *txtToken (LexState *ls, int token) { | ||
90 | switch (token) { | ||
91 | case TK_NAME: | ||
92 | case TK_STRING: | ||
93 | case TK_NUMBER: | ||
94 | save(ls, '\0'); | ||
95 | return luaZ_buffer(ls->buff); | ||
96 | default: | ||
97 | return luaX_token2str(ls, token); | ||
98 | } | ||
99 | } | ||
100 | |||
101 | |||
102 | void luaX_lexerror (LexState *ls, const char *msg, int token) { | ||
103 | char buff[MAXSRC]; | ||
104 | luaO_chunkid(buff, getstr(ls->source), MAXSRC); | ||
105 | msg = luaO_pushfstring(ls->L, "%s:%d: %s", buff, ls->linenumber, msg); | ||
106 | if (token) | ||
107 | luaO_pushfstring(ls->L, "%s near " LUA_QS, msg, txtToken(ls, token)); | ||
108 | luaD_throw(ls->L, LUA_ERRSYNTAX); | ||
109 | } | ||
110 | |||
111 | |||
112 | void luaX_syntaxerror (LexState *ls, const char *msg) { | ||
113 | luaX_lexerror(ls, msg, ls->t.token); | ||
114 | } | ||
115 | |||
116 | |||
117 | TString *luaX_newstring (LexState *ls, const char *str, size_t l) { | ||
118 | lua_State *L = ls->L; | ||
119 | TString *ts = luaS_newlstr(L, str, l); | ||
120 | TValue *o = luaH_setstr(L, ls->fs->h, ts); /* entry for `str' */ | ||
121 | if (ttisnil(o)) | ||
122 | setbvalue(o, 1); /* make sure `str' will not be collected */ | ||
123 | return ts; | ||
124 | } | ||
125 | |||
126 | |||
127 | static void inclinenumber (LexState *ls) { | ||
128 | int old = ls->current; | ||
129 | lua_assert(currIsNewline(ls)); | ||
130 | next(ls); /* skip `\n' or `\r' */ | ||
131 | if (currIsNewline(ls) && ls->current != old) | ||
132 | next(ls); /* skip `\n\r' or `\r\n' */ | ||
133 | if (++ls->linenumber >= MAX_INT) | ||
134 | luaX_syntaxerror(ls, "chunk has too many lines"); | ||
135 | } | ||
136 | |||
137 | |||
138 | void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source) { | ||
139 | ls->decpoint = '.'; | ||
140 | ls->L = L; | ||
141 | ls->lookahead.token = TK_EOS; /* no look-ahead token */ | ||
142 | ls->z = z; | ||
143 | ls->fs = NULL; | ||
144 | ls->linenumber = 1; | ||
145 | ls->lastline = 1; | ||
146 | ls->source = source; | ||
147 | luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */ | ||
148 | next(ls); /* read first char */ | ||
149 | } | ||
150 | |||
151 | |||
152 | |||
153 | /* | ||
154 | ** ======================================================= | ||
155 | ** LEXICAL ANALYZER | ||
156 | ** ======================================================= | ||
157 | */ | ||
158 | |||
159 | |||
160 | |||
161 | static int check_next (LexState *ls, const char *set) { | ||
162 | if (!strchr(set, ls->current)) | ||
163 | return 0; | ||
164 | save_and_next(ls); | ||
165 | return 1; | ||
166 | } | ||
167 | |||
168 | |||
169 | static void buffreplace (LexState *ls, char from, char to) { | ||
170 | size_t n = luaZ_bufflen(ls->buff); | ||
171 | char *p = luaZ_buffer(ls->buff); | ||
172 | while (n--) | ||
173 | if (p[n] == from) p[n] = to; | ||
174 | } | ||
175 | |||
176 | |||
177 | static void trydecpoint (LexState *ls, SemInfo *seminfo) { | ||
178 | /* format error: try to update decimal point separator */ | ||
179 | struct lconv *cv = localeconv(); | ||
180 | char old = ls->decpoint; | ||
181 | ls->decpoint = (cv ? cv->decimal_point[0] : '.'); | ||
182 | buffreplace(ls, old, ls->decpoint); /* try updated decimal separator */ | ||
183 | if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) { | ||
184 | /* format error with correct decimal point: no more options */ | ||
185 | buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */ | ||
186 | luaX_lexerror(ls, "malformed number", TK_NUMBER); | ||
187 | } | ||
188 | } | ||
189 | |||
190 | |||
191 | /* LUA_NUMBER */ | ||
192 | static void read_numeral (LexState *ls, SemInfo *seminfo) { | ||
193 | lua_assert(isdigit(ls->current)); | ||
194 | do { | ||
195 | save_and_next(ls); | ||
196 | } while (isdigit(ls->current) || ls->current == '.'); | ||
197 | if (check_next(ls, "Ee")) /* `E'? */ | ||
198 | check_next(ls, "+-"); /* optional exponent sign */ | ||
199 | while (isalnum(ls->current) || ls->current == '_') | ||
200 | save_and_next(ls); | ||
201 | save(ls, '\0'); | ||
202 | buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */ | ||
203 | if (!luaO_str2d(luaZ_buffer(ls->buff), &seminfo->r)) /* format error? */ | ||
204 | trydecpoint(ls, seminfo); /* try to update decimal point separator */ | ||
205 | } | ||
206 | |||
207 | |||
208 | static int skip_sep (LexState *ls) { | ||
209 | int count = 0; | ||
210 | int s = ls->current; | ||
211 | lua_assert(s == '[' || s == ']'); | ||
212 | save_and_next(ls); | ||
213 | while (ls->current == '=') { | ||
214 | save_and_next(ls); | ||
215 | count++; | ||
216 | } | ||
217 | return (ls->current == s) ? count : (-count) - 1; | ||
218 | } | ||
219 | |||
220 | |||
221 | static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { | ||
222 | int cont = 0; | ||
223 | (void)(cont); /* avoid warnings when `cont' is not used */ | ||
224 | save_and_next(ls); /* skip 2nd `[' */ | ||
225 | if (currIsNewline(ls)) /* string starts with a newline? */ | ||
226 | inclinenumber(ls); /* skip it */ | ||
227 | for (;;) { | ||
228 | switch (ls->current) { | ||
229 | case EOZ: | ||
230 | luaX_lexerror(ls, (seminfo) ? "unfinished long string" : | ||
231 | "unfinished long comment", TK_EOS); | ||
232 | break; /* to avoid warnings */ | ||
233 | #if defined(LUA_COMPAT_LSTR) | ||
234 | case '[': { | ||
235 | if (skip_sep(ls) == sep) { | ||
236 | save_and_next(ls); /* skip 2nd `[' */ | ||
237 | cont++; | ||
238 | #if LUA_COMPAT_LSTR == 1 | ||
239 | if (sep == 0) | ||
240 | luaX_lexerror(ls, "nesting of [[...]] is deprecated", '['); | ||
241 | #endif | ||
242 | } | ||
243 | break; | ||
244 | } | ||
245 | #endif | ||
246 | case ']': { | ||
247 | if (skip_sep(ls) == sep) { | ||
248 | save_and_next(ls); /* skip 2nd `]' */ | ||
249 | #if defined(LUA_COMPAT_LSTR) && LUA_COMPAT_LSTR == 2 | ||
250 | cont--; | ||
251 | if (sep == 0 && cont >= 0) break; | ||
252 | #endif | ||
253 | goto endloop; | ||
254 | } | ||
255 | break; | ||
256 | } | ||
257 | case '\n': | ||
258 | case '\r': { | ||
259 | save(ls, '\n'); | ||
260 | inclinenumber(ls); | ||
261 | if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */ | ||
262 | break; | ||
263 | } | ||
264 | default: { | ||
265 | if (seminfo) save_and_next(ls); | ||
266 | else next(ls); | ||
267 | } | ||
268 | } | ||
269 | } endloop: | ||
270 | if (seminfo) | ||
271 | seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep), | ||
272 | luaZ_bufflen(ls->buff) - 2*(2 + sep)); | ||
273 | } | ||
274 | |||
275 | |||
276 | static void read_string (LexState *ls, int del, SemInfo *seminfo) { | ||
277 | save_and_next(ls); | ||
278 | while (ls->current != del) { | ||
279 | switch (ls->current) { | ||
280 | case EOZ: | ||
281 | luaX_lexerror(ls, "unfinished string", TK_EOS); | ||
282 | continue; /* to avoid warnings */ | ||
283 | case '\n': | ||
284 | case '\r': | ||
285 | luaX_lexerror(ls, "unfinished string", TK_STRING); | ||
286 | continue; /* to avoid warnings */ | ||
287 | case '\\': { | ||
288 | int c; | ||
289 | next(ls); /* do not save the `\' */ | ||
290 | switch (ls->current) { | ||
291 | case 'a': c = '\a'; break; | ||
292 | case 'b': c = '\b'; break; | ||
293 | case 'f': c = '\f'; break; | ||
294 | case 'n': c = '\n'; break; | ||
295 | case 'r': c = '\r'; break; | ||
296 | case 't': c = '\t'; break; | ||
297 | case 'v': c = '\v'; break; | ||
298 | case '\n': /* go through */ | ||
299 | case '\r': save(ls, '\n'); inclinenumber(ls); continue; | ||
300 | case EOZ: continue; /* will raise an error next loop */ | ||
301 | default: { | ||
302 | if (!isdigit(ls->current)) | ||
303 | save_and_next(ls); /* handles \\, \", \', and \? */ | ||
304 | else { /* \xxx */ | ||
305 | int i = 0; | ||
306 | c = 0; | ||
307 | do { | ||
308 | c = 10*c + (ls->current-'0'); | ||
309 | next(ls); | ||
310 | } while (++i<3 && isdigit(ls->current)); | ||
311 | if (c > UCHAR_MAX) | ||
312 | luaX_lexerror(ls, "escape sequence too large", TK_STRING); | ||
313 | save(ls, c); | ||
314 | } | ||
315 | continue; | ||
316 | } | ||
317 | } | ||
318 | save(ls, c); | ||
319 | next(ls); | ||
320 | continue; | ||
321 | } | ||
322 | default: | ||
323 | save_and_next(ls); | ||
324 | } | ||
325 | } | ||
326 | save_and_next(ls); /* skip delimiter */ | ||
327 | seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1, | ||
328 | luaZ_bufflen(ls->buff) - 2); | ||
329 | } | ||
330 | |||
331 | |||
332 | static int llex (LexState *ls, SemInfo *seminfo) { | ||
333 | luaZ_resetbuffer(ls->buff); | ||
334 | for (;;) { | ||
335 | switch (ls->current) { | ||
336 | case '\n': | ||
337 | case '\r': { | ||
338 | inclinenumber(ls); | ||
339 | continue; | ||
340 | } | ||
341 | case '-': { | ||
342 | next(ls); | ||
343 | if (ls->current != '-') return '-'; | ||
344 | /* else is a comment */ | ||
345 | next(ls); | ||
346 | if (ls->current == '[') { | ||
347 | int sep = skip_sep(ls); | ||
348 | luaZ_resetbuffer(ls->buff); /* `skip_sep' may dirty the buffer */ | ||
349 | if (sep >= 0) { | ||
350 | read_long_string(ls, NULL, sep); /* long comment */ | ||
351 | luaZ_resetbuffer(ls->buff); | ||
352 | continue; | ||
353 | } | ||
354 | } | ||
355 | /* else short comment */ | ||
356 | while (!currIsNewline(ls) && ls->current != EOZ) | ||
357 | next(ls); | ||
358 | continue; | ||
359 | } | ||
360 | case '[': { | ||
361 | int sep = skip_sep(ls); | ||
362 | if (sep >= 0) { | ||
363 | read_long_string(ls, seminfo, sep); | ||
364 | return TK_STRING; | ||
365 | } | ||
366 | else if (sep == -1) return '['; | ||
367 | else luaX_lexerror(ls, "invalid long string delimiter", TK_STRING); | ||
368 | } | ||
369 | case '=': { | ||
370 | next(ls); | ||
371 | if (ls->current != '=') return '='; | ||
372 | else { next(ls); return TK_EQ; } | ||
373 | } | ||
374 | case '<': { | ||
375 | next(ls); | ||
376 | if (ls->current != '=') return '<'; | ||
377 | else { next(ls); return TK_LE; } | ||
378 | } | ||
379 | case '>': { | ||
380 | next(ls); | ||
381 | if (ls->current != '=') return '>'; | ||
382 | else { next(ls); return TK_GE; } | ||
383 | } | ||
384 | case '~': { | ||
385 | next(ls); | ||
386 | if (ls->current != '=') return '~'; | ||
387 | else { next(ls); return TK_NE; } | ||
388 | } | ||
389 | case '"': | ||
390 | case '\'': { | ||
391 | read_string(ls, ls->current, seminfo); | ||
392 | return TK_STRING; | ||
393 | } | ||
394 | case '.': { | ||
395 | save_and_next(ls); | ||
396 | if (check_next(ls, ".")) { | ||
397 | if (check_next(ls, ".")) | ||
398 | return TK_DOTS; /* ... */ | ||
399 | else return TK_CONCAT; /* .. */ | ||
400 | } | ||
401 | else if (!isdigit(ls->current)) return '.'; | ||
402 | else { | ||
403 | read_numeral(ls, seminfo); | ||
404 | return TK_NUMBER; | ||
405 | } | ||
406 | } | ||
407 | case EOZ: { | ||
408 | return TK_EOS; | ||
409 | } | ||
410 | default: { | ||
411 | if (isspace(ls->current)) { | ||
412 | lua_assert(!currIsNewline(ls)); | ||
413 | next(ls); | ||
414 | continue; | ||
415 | } | ||
416 | else if (isdigit(ls->current)) { | ||
417 | read_numeral(ls, seminfo); | ||
418 | return TK_NUMBER; | ||
419 | } | ||
420 | else if (isalpha(ls->current) || ls->current == '_') { | ||
421 | /* identifier or reserved word */ | ||
422 | TString *ts; | ||
423 | do { | ||
424 | save_and_next(ls); | ||
425 | } while (isalnum(ls->current) || ls->current == '_'); | ||
426 | ts = luaX_newstring(ls, luaZ_buffer(ls->buff), | ||
427 | luaZ_bufflen(ls->buff)); | ||
428 | if (ts->tsv.reserved > 0) /* reserved word? */ | ||
429 | return ts->tsv.reserved - 1 + FIRST_RESERVED; | ||
430 | else { | ||
431 | seminfo->ts = ts; | ||
432 | return TK_NAME; | ||
433 | } | ||
434 | } | ||
435 | else { | ||
436 | int c = ls->current; | ||
437 | next(ls); | ||
438 | return c; /* single-char tokens (+ - / ...) */ | ||
439 | } | ||
440 | } | ||
441 | } | ||
442 | } | ||
443 | } | ||
444 | |||
445 | |||
446 | void luaX_next (LexState *ls) { | ||
447 | ls->lastline = ls->linenumber; | ||
448 | if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */ | ||
449 | ls->t = ls->lookahead; /* use this one */ | ||
450 | ls->lookahead.token = TK_EOS; /* and discharge it */ | ||
451 | } | ||
452 | else | ||
453 | ls->t.token = llex(ls, &ls->t.seminfo); /* read next token */ | ||
454 | } | ||
455 | |||
456 | |||
457 | void luaX_lookahead (LexState *ls) { | ||
458 | lua_assert(ls->lookahead.token == TK_EOS); | ||
459 | ls->lookahead.token = llex(ls, &ls->lookahead.seminfo); | ||
460 | } | ||
461 | |||