Imported from ../lua-3.0.tar.gz.
[lua.git] / src / lex.c
blob5f19dd06d7928e778bd99a8795c93e608f95703f
1 char *rcs_lex = "$Id: lex.c,v 3.5 1997/06/16 16:50:22 roberto Exp $";
4 #include <ctype.h>
5 #include <string.h>
7 #include "auxlib.h"
8 #include "luamem.h"
9 #include "tree.h"
10 #include "table.h"
11 #include "lex.h"
12 #include "inout.h"
13 #include "luadebug.h"
14 #include "parser.h"
16 #define MINBUFF 250
18 static int current; /* look ahead character */
19 static ZIO *lex_z;
22 #define next() (current = zgetc(lex_z))
23 #define save(x) (yytext[tokensize++] = (x))
24 #define save_and_next() (save(current), next())
27 #define MAX_IFS 5
29 /* "ifstate" keeps the state of each nested $if the lexical is dealing with. */
31 static struct {
32 int elsepart; /* true if its in the $else part */
33 int condition; /* true if $if condition is true */
34 int skip; /* true if part must be skiped */
35 } ifstate[MAX_IFS];
37 static int iflevel; /* level of nested $if's */
40 void lua_setinput (ZIO *z)
42 current = '\n';
43 lua_linenumber = 0;
44 iflevel = 0;
45 ifstate[0].skip = 0;
46 ifstate[0].elsepart = 1; /* to avoid a free $else */
47 lex_z = z;
51 static void luaI_auxsyntaxerror (char *s)
53 luaL_verror("%s;\n> at line %d in file %s",
54 s, lua_linenumber, lua_parsedfile);
57 static void luaI_auxsynterrbf (char *s, char *token)
59 if (token[0] == 0)
60 token = "<eof>";
61 luaL_verror("%s;\n> last token read: \"%s\" at line %d in file %s",
62 s, token, lua_linenumber, lua_parsedfile);
65 void luaI_syntaxerror (char *s)
67 luaI_auxsynterrbf(s, luaI_buffer(1));
71 static struct
73 char *name;
74 int token;
75 } reserved [] = {
76 {"and", AND},
77 {"do", DO},
78 {"else", ELSE},
79 {"elseif", ELSEIF},
80 {"end", END},
81 {"function", FUNCTION},
82 {"if", IF},
83 {"local", LOCAL},
84 {"nil", NIL},
85 {"not", NOT},
86 {"or", OR},
87 {"repeat", REPEAT},
88 {"return", RETURN},
89 {"then", THEN},
90 {"until", UNTIL},
91 {"while", WHILE} };
94 #define RESERVEDSIZE (sizeof(reserved)/sizeof(reserved[0]))
97 void luaI_addReserved (void)
99 int i;
100 for (i=0; i<RESERVEDSIZE; i++)
102 TaggedString *ts = lua_createstring(reserved[i].name);
103 ts->marked = reserved[i].token; /* reserved word (always > 255) */
109 ** Pragma handling
112 #define PRAGMASIZE 20
114 static void skipspace (void)
116 while (current == ' ' || current == '\t') next();
120 static int checkcond (char *buff)
122 static char *opts[] = {"nil", "1"};
123 int i = luaI_findstring(buff, opts);
124 if (i >= 0) return i;
125 else if (isalpha((unsigned char)buff[0]) || buff[0] == '_')
126 return luaI_globaldefined(buff);
127 else {
128 luaI_auxsynterrbf("invalid $if condition", buff);
129 return 0; /* to avoid warnings */
134 static void readname (char *buff)
136 int i = 0;
137 skipspace();
138 while (isalnum((unsigned char)current) || current == '_') {
139 if (i >= PRAGMASIZE) {
140 buff[PRAGMASIZE] = 0;
141 luaI_auxsynterrbf("pragma too long", buff);
143 buff[i++] = current;
144 next();
146 buff[i] = 0;
150 static void inclinenumber (void);
153 static void ifskip (void)
155 while (ifstate[iflevel].skip) {
156 if (current == '\n')
157 inclinenumber();
158 else if (current == EOZ)
159 luaI_auxsyntaxerror("input ends inside a $if");
160 else next();
165 static void inclinenumber (void)
167 static char *pragmas [] =
168 {"debug", "nodebug", "endinput", "end", "ifnot", "if", "else", NULL};
169 next(); /* skip '\n' */
170 ++lua_linenumber;
171 if (current == '$') { /* is a pragma? */
172 char buff[PRAGMASIZE+1];
173 int ifnot = 0;
174 int skip = ifstate[iflevel].skip;
175 next(); /* skip $ */
176 readname(buff);
177 switch (luaI_findstring(buff, pragmas)) {
178 case 0: /* debug */
179 if (!skip) lua_debug = 1;
180 break;
181 case 1: /* nodebug */
182 if (!skip) lua_debug = 0;
183 break;
184 case 2: /* endinput */
185 if (!skip) {
186 current = EOZ;
187 iflevel = 0; /* to allow $endinput inside a $if */
189 break;
190 case 3: /* end */
191 if (iflevel-- == 0)
192 luaI_auxsyntaxerror("unmatched $endif");
193 break;
194 case 4: /* ifnot */
195 ifnot = 1;
196 /* go through */
197 case 5: /* if */
198 if (iflevel == MAX_IFS-1)
199 luaI_auxsyntaxerror("too many nested `$ifs'");
200 readname(buff);
201 iflevel++;
202 ifstate[iflevel].elsepart = 0;
203 ifstate[iflevel].condition = checkcond(buff) ? !ifnot : ifnot;
204 ifstate[iflevel].skip = skip || !ifstate[iflevel].condition;
205 break;
206 case 6: /* else */
207 if (ifstate[iflevel].elsepart)
208 luaI_auxsyntaxerror("unmatched $else");
209 ifstate[iflevel].elsepart = 1;
210 ifstate[iflevel].skip =
211 ifstate[iflevel-1].skip || ifstate[iflevel].condition;
212 break;
213 default:
214 luaI_auxsynterrbf("invalid pragma", buff);
216 skipspace();
217 if (current == '\n') /* pragma must end with a '\n' ... */
218 inclinenumber();
219 else if (current != EOZ) /* or eof */
220 luaI_auxsyntaxerror("invalid pragma format");
221 ifskip();
225 static int read_long_string (char *yytext, int buffsize)
227 int cont = 0;
228 int tokensize = 2; /* '[[' already stored */
229 while (1)
231 if (buffsize-tokensize <= 2) /* may read more than 1 char in one cicle */
232 yytext = luaI_buffer(buffsize *= 2);
233 switch (current)
235 case EOZ:
236 save(0);
237 return WRONGTOKEN;
238 case '[':
239 save_and_next();
240 if (current == '[')
242 cont++;
243 save_and_next();
245 continue;
246 case ']':
247 save_and_next();
248 if (current == ']')
250 if (cont == 0) goto endloop;
251 cont--;
252 save_and_next();
254 continue;
255 case '\n':
256 save('\n');
257 inclinenumber();
258 continue;
259 default:
260 save_and_next();
262 } endloop:
263 save_and_next(); /* pass the second ']' */
264 yytext[tokensize-2] = 0; /* erases ']]' */
265 luaY_lval.vWord = luaI_findconstantbyname(yytext+2);
266 yytext[tokensize-2] = ']'; /* restores ']]' */
267 save(0);
268 return STRING;
271 int luaY_lex (void)
273 static int linelasttoken = 0;
274 double a;
275 int buffsize = MINBUFF;
276 char *yytext = luaI_buffer(buffsize);
277 yytext[1] = yytext[2] = yytext[3] = 0;
278 if (lua_debug)
279 luaI_codedebugline(linelasttoken);
280 linelasttoken = lua_linenumber;
281 while (1)
283 int tokensize = 0;
284 switch (current)
286 case '\n':
287 inclinenumber();
288 linelasttoken = lua_linenumber;
289 continue;
291 case ' ': case '\t': case '\r': /* CR: to avoid problems with DOS */
292 next();
293 continue;
295 case '-':
296 save_and_next();
297 if (current != '-') return '-';
298 do { next(); } while (current != '\n' && current != EOZ);
299 continue;
301 case '[':
302 save_and_next();
303 if (current != '[') return '[';
304 else
306 save_and_next(); /* pass the second '[' */
307 return read_long_string(yytext, buffsize);
310 case '=':
311 save_and_next();
312 if (current != '=') return '=';
313 else { save_and_next(); return EQ; }
315 case '<':
316 save_and_next();
317 if (current != '=') return '<';
318 else { save_and_next(); return LE; }
320 case '>':
321 save_and_next();
322 if (current != '=') return '>';
323 else { save_and_next(); return GE; }
325 case '~':
326 save_and_next();
327 if (current != '=') return '~';
328 else { save_and_next(); return NE; }
330 case '"':
331 case '\'':
333 int del = current;
334 save_and_next();
335 while (current != del)
337 if (buffsize-tokensize <= 2) /* may read more than 1 char in one cicle */
338 yytext = luaI_buffer(buffsize *= 2);
339 switch (current)
341 case EOZ:
342 case '\n':
343 save(0);
344 return WRONGTOKEN;
345 case '\\':
346 next(); /* do not save the '\' */
347 switch (current)
349 case 'n': save('\n'); next(); break;
350 case 't': save('\t'); next(); break;
351 case 'r': save('\r'); next(); break;
352 case '\n': save('\n'); inclinenumber(); break;
353 default : save_and_next(); break;
355 break;
356 default:
357 save_and_next();
360 next(); /* skip delimiter */
361 save(0);
362 luaY_lval.vWord = luaI_findconstantbyname(yytext+1);
363 tokensize--;
364 save(del); save(0); /* restore delimiter */
365 return STRING;
368 case 'a': case 'b': case 'c': case 'd': case 'e':
369 case 'f': case 'g': case 'h': case 'i': case 'j':
370 case 'k': case 'l': case 'm': case 'n': case 'o':
371 case 'p': case 'q': case 'r': case 's': case 't':
372 case 'u': case 'v': case 'w': case 'x': case 'y':
373 case 'z':
374 case 'A': case 'B': case 'C': case 'D': case 'E':
375 case 'F': case 'G': case 'H': case 'I': case 'J':
376 case 'K': case 'L': case 'M': case 'N': case 'O':
377 case 'P': case 'Q': case 'R': case 'S': case 'T':
378 case 'U': case 'V': case 'W': case 'X': case 'Y':
379 case 'Z':
380 case '_':
382 TaggedString *ts;
383 do {
384 save_and_next();
385 } while (isalnum((unsigned char)current) || current == '_');
386 save(0);
387 ts = lua_createstring(yytext);
388 if (ts->marked > 2)
389 return ts->marked; /* reserved word */
390 luaY_lval.pTStr = ts;
391 ts->marked = 2; /* avoid GC */
392 return NAME;
395 case '.':
396 save_and_next();
397 if (current == '.')
399 save_and_next();
400 if (current == '.')
402 save_and_next();
403 return DOTS; /* ... */
405 else return CONC; /* .. */
407 else if (!isdigit((unsigned char)current)) return '.';
408 /* current is a digit: goes through to number */
409 a=0.0;
410 goto fraction;
412 case '0': case '1': case '2': case '3': case '4':
413 case '5': case '6': case '7': case '8': case '9':
414 a=0.0;
415 do {
416 a=10.0*a+(current-'0');
417 save_and_next();
418 } while (isdigit((unsigned char)current));
419 if (current == '.') {
420 save_and_next();
421 if (current == '.')
422 luaI_syntaxerror(
423 "ambiguous syntax (decimal point x string concatenation)");
425 fraction:
426 { double da=0.1;
427 while (isdigit((unsigned char)current))
429 a+=(current-'0')*da;
430 da/=10.0;
431 save_and_next();
433 if (current == 'e' || current == 'E')
435 int e=0;
436 int neg;
437 double ea;
438 save_and_next();
439 neg=(current=='-');
440 if (current == '+' || current == '-') save_and_next();
441 if (!isdigit((unsigned char)current)) {
442 save(0); return WRONGTOKEN; }
443 do {
444 e=10.0*e+(current-'0');
445 save_and_next();
446 } while (isdigit((unsigned char)current));
447 for (ea=neg?0.1:10.0; e>0; e>>=1)
449 if (e & 1) a*=ea;
450 ea*=ea;
453 luaY_lval.vFloat = a;
454 save(0);
455 return NUMBER;
458 case EOZ:
459 save(0);
460 if (iflevel > 0)
461 luaI_syntaxerror("missing $endif");
462 return 0;
464 default:
465 save_and_next();
466 return yytext[0];