diff options
Diffstat (limited to '')
-rw-r--r-- | LuaSL/testLua/yueliang-0.4.1/nat-5.0.3/lparser_mk3b.lua | 1121 |
1 files changed, 1121 insertions, 0 deletions
diff --git a/LuaSL/testLua/yueliang-0.4.1/nat-5.0.3/lparser_mk3b.lua b/LuaSL/testLua/yueliang-0.4.1/nat-5.0.3/lparser_mk3b.lua new file mode 100644 index 0000000..a46edc6 --- /dev/null +++ b/LuaSL/testLua/yueliang-0.4.1/nat-5.0.3/lparser_mk3b.lua | |||
@@ -0,0 +1,1121 @@ | |||
1 | --[[-------------------------------------------------------------------- | ||
2 | |||
3 | lparser.lua | ||
4 | Lua 5 parser in Lua | ||
5 | This file is part of Yueliang. | ||
6 | |||
7 | Copyright (c) 2008 Kein-Hong Man <khman@users.sf.net> | ||
8 | The COPYRIGHT file describes the conditions | ||
9 | under which this software may be distributed. | ||
10 | |||
11 | See the ChangeLog for more information. | ||
12 | |||
13 | ----------------------------------------------------------------------]] | ||
14 | |||
15 | --[[-------------------------------------------------------------------- | ||
16 | -- Notes: | ||
17 | -- * this is a Lua 5.0.x parser skeleton, for llex_mk3.lua lexer | ||
18 | -- * written as a module factory with recognizable lparser.c roots | ||
19 | -- * builds some data, performs logging for educational purposes | ||
20 | -- * target is to have relatively efficient and clear code | ||
21 | -- * needs one parameter, a lexer module that implements: | ||
22 | -- luaX:lex() - returns appropriate [token, semantic info] pairs | ||
23 | -- luaX.ln - current line number | ||
24 | -- luaX:errorline(s, [line]) - dies with error message | ||
25 | -- | ||
26 | -- Usage example: | ||
27 | -- lex_init = require("llex_mk3.lua") | ||
28 | -- parser_init = require("lparser_mk3.lua") | ||
29 | -- local luaX = lex_init(chunk, "=string") | ||
30 | -- local luaY = parser_init(luaX) | ||
31 | -- local fs = luaY:parser() | ||
32 | -- | ||
33 | -- Development notes: | ||
34 | -- * see test_parser-5.0.lua for grammar elements based on lparser.c | ||
35 | -- * lparser has a few extra items to help parsing/syntax checking | ||
36 | -- (a) line number (error reporting), lookahead token storage | ||
37 | -- (b) per-prototype states needs a storage list | ||
38 | -- (c) 'break' needs a per-block flag in a stack | ||
39 | -- (d) 'kind' (v.k) testing needed in expr_stat() and assignment() | ||
40 | -- for disambiguation, thus v.k manipulation is retained | ||
41 | -- (e) one line # var (lastln) for ambiguous (split line) function | ||
42 | -- call checking | ||
43 | -- (f) most line number function call args retained for future use | ||
44 | -- (g) Lua 4 compatibility code completely removed | ||
45 | -- (h) minimal variable management code to differentiate each type | ||
46 | -- * parsing starts from the end of this file in luaY:parser() | ||
47 | -- | ||
48 | ----------------------------------------------------------------------]] | ||
49 | |||
50 | return | ||
51 | function(luaX) | ||
52 | --[[-------------------------------------------------------------------- | ||
53 | -- structures and data initialization | ||
54 | ----------------------------------------------------------------------]] | ||
55 | |||
56 | local line -- start line # for error messages | ||
57 | local lastln -- last line # for ambiguous syntax chk | ||
58 | local tok, seminfo -- token, semantic info pair | ||
59 | local peek_tok, peek_sem -- ditto, for lookahead | ||
60 | local fs -- function state | ||
61 | local top_fs = {} -- top-level function state | ||
62 | local luaY = {} | ||
63 | -------------------------------------------------------------------- | ||
64 | local block_follow = {} -- lookahead check in chunk(), returnstat() | ||
65 | for v in string.gfind("else elseif end until <eof>", "%S+") do | ||
66 | block_follow[v] = true | ||
67 | end | ||
68 | -------------------------------------------------------------------- | ||
69 | local stat_call = {} -- lookup for calls in stat() | ||
70 | for v in string.gfind("if while do for repeat function local return break", "%S+") do | ||
71 | stat_call[v] = v.."_stat" | ||
72 | end | ||
73 | -------------------------------------------------------------------- | ||
74 | local binopr_left = {} -- binary operators, left priority | ||
75 | local binopr_right = {} -- binary operators, right priority | ||
76 | for op, lt, rt in string.gfind([[ | ||
77 | {+ 6 6}{- 6 6}{* 7 7}{/ 7 7}{^ 10 9}{.. 5 4} | ||
78 | {~= 3 3}{== 3 3}{< 3 3}{<= 3 3}{> 3 3}{>= 3 3} | ||
79 | {and 2 2}{or 1 1} | ||
80 | ]], "{(%S+)%s(%d+)%s(%d+)}") do | ||
81 | binopr_left[op] = lt + 0 | ||
82 | binopr_right[op] = rt + 0 | ||
83 | end | ||
84 | local unopr = { ["not"] = true, ["-"] = true, } -- unary operators | ||
85 | |||
86 | --[[-------------------------------------------------------------------- | ||
87 | -- logging: this logging function is for educational purposes | ||
88 | -- * logged data can be retrieved from the returned data structure | ||
89 | -- * or, replace self:log() instances with your custom code... | ||
90 | ----------------------------------------------------------------------]] | ||
91 | |||
92 | function luaY:log(msg) | ||
93 | local log = top_fs.log | ||
94 | if not log then log = {}; top_fs.log = log end | ||
95 | table.insert(top_fs.log, msg) | ||
96 | end | ||
97 | |||
98 | --[[-------------------------------------------------------------------- | ||
99 | -- support functions | ||
100 | ----------------------------------------------------------------------]] | ||
101 | |||
102 | -------------------------------------------------------------------- | ||
103 | -- reads in next token | ||
104 | -------------------------------------------------------------------- | ||
105 | function luaY:next() | ||
106 | lastln = luaX.ln | ||
107 | if peek_tok then -- is there a look-ahead token? if yes, use it | ||
108 | tok, seminfo = peek_tok, peek_sem | ||
109 | peek_tok = nil | ||
110 | else | ||
111 | tok, seminfo = luaX:lex() -- read next token | ||
112 | end | ||
113 | end | ||
114 | -------------------------------------------------------------------- | ||
115 | -- peek at next token (single lookahead for table constructor) | ||
116 | -------------------------------------------------------------------- | ||
117 | function luaY:lookahead() | ||
118 | peek_tok, peek_sem = luaX:lex() | ||
119 | return peek_tok | ||
120 | end | ||
121 | |||
122 | ------------------------------------------------------------------------ | ||
123 | -- throws a syntax error | ||
124 | ------------------------------------------------------------------------ | ||
125 | function luaY:syntaxerror(msg) | ||
126 | local tok = tok | ||
127 | if tok ~= "<number>" and tok ~= "<string>" then | ||
128 | if tok == "<name>" then tok = seminfo end | ||
129 | tok = "'"..tok.."'" | ||
130 | end | ||
131 | luaX:errorline(msg.." near "..tok) | ||
132 | end | ||
133 | -------------------------------------------------------------------- | ||
134 | -- throws a syntax error if token expected is not there | ||
135 | -------------------------------------------------------------------- | ||
136 | function luaY:error_expected(token) | ||
137 | self:syntaxerror("'"..token.."' expected") | ||
138 | end | ||
139 | |||
140 | -------------------------------------------------------------------- | ||
141 | -- verifies token conditions are met or else throw error | ||
142 | -------------------------------------------------------------------- | ||
143 | function luaY:check_match(what, who, where) | ||
144 | if not self:testnext(what) then | ||
145 | if where == luaX.ln then | ||
146 | self:error_expected(what) | ||
147 | else | ||
148 | self:syntaxerror("'"..what.."' expected (to close '"..who.."' at line "..where..")") | ||
149 | end | ||
150 | end | ||
151 | end | ||
152 | -------------------------------------------------------------------- | ||
153 | -- tests for a token, returns outcome | ||
154 | -- * return value changed to boolean | ||
155 | -------------------------------------------------------------------- | ||
156 | function luaY:testnext(c) | ||
157 | if tok == c then self:next(); return true end | ||
158 | end | ||
159 | -------------------------------------------------------------------- | ||
160 | -- throws error if condition not matched | ||
161 | -------------------------------------------------------------------- | ||
162 | function luaY:check_condition(c, msg) | ||
163 | if not c then self:syntaxerror(msg) end | ||
164 | end | ||
165 | -------------------------------------------------------------------- | ||
166 | -- check for existence of a token, throws error if not found | ||
167 | -------------------------------------------------------------------- | ||
168 | function luaY:check(c) | ||
169 | if not self:testnext(c) then self:error_expected(c) end | ||
170 | end | ||
171 | |||
172 | -------------------------------------------------------------------- | ||
173 | -- expect that token is a name, return the name | ||
174 | -------------------------------------------------------------------- | ||
175 | function luaY:str_checkname() | ||
176 | self:check_condition(tok == "<name>", "<name> expected") | ||
177 | local ts = seminfo | ||
178 | self:next() | ||
179 | self:log(" str_checkname: '"..ts.."'") | ||
180 | return ts | ||
181 | end | ||
182 | -------------------------------------------------------------------- | ||
183 | -- adds given string s in string pool, sets e as VK | ||
184 | -------------------------------------------------------------------- | ||
185 | function luaY:codestring(e, s) | ||
186 | e.k = "VK" | ||
187 | self:log(" codestring: "..string.format("%q", s)) | ||
188 | end | ||
189 | -------------------------------------------------------------------- | ||
190 | -- consume a name token, adds it to string pool | ||
191 | -------------------------------------------------------------------- | ||
192 | function luaY:checkname(e) | ||
193 | self:log(" checkname:") | ||
194 | self:codestring(e, self:str_checkname()) | ||
195 | end | ||
196 | |||
197 | --[[-------------------------------------------------------------------- | ||
198 | -- state management functions with open/close pairs | ||
199 | ----------------------------------------------------------------------]] | ||
200 | |||
201 | -------------------------------------------------------------------- | ||
202 | -- enters a code unit, initializes elements | ||
203 | -------------------------------------------------------------------- | ||
204 | function luaY:enterblock(isbreakable) | ||
205 | local bl = {} -- per-block state | ||
206 | bl.isbreakable = isbreakable | ||
207 | bl.prev = fs.bl | ||
208 | bl.locallist = {} | ||
209 | fs.bl = bl | ||
210 | self:log(">> enterblock(isbreakable="..tostring(isbreakable)..")") | ||
211 | end | ||
212 | -------------------------------------------------------------------- | ||
213 | -- leaves a code unit, close any upvalues | ||
214 | -------------------------------------------------------------------- | ||
215 | function luaY:leaveblock() | ||
216 | local bl = fs.bl | ||
217 | fs.bl = bl.prev | ||
218 | self:log("<< leaveblock") | ||
219 | end | ||
220 | -------------------------------------------------------------------- | ||
221 | -- opening of a function | ||
222 | -------------------------------------------------------------------- | ||
223 | function luaY:open_func() | ||
224 | local new_fs -- per-function state | ||
225 | if not fs then -- top_fs is created early | ||
226 | new_fs = top_fs | ||
227 | else | ||
228 | new_fs = {} | ||
229 | end | ||
230 | new_fs.prev = fs -- linked list of function states | ||
231 | new_fs.bl = nil | ||
232 | new_fs.locallist = {} | ||
233 | fs = new_fs | ||
234 | self:log(">> open_func") | ||
235 | end | ||
236 | -------------------------------------------------------------------- | ||
237 | -- closing of a function | ||
238 | -------------------------------------------------------------------- | ||
239 | function luaY:close_func() | ||
240 | fs = fs.prev | ||
241 | self:log("<< close_func") | ||
242 | end | ||
243 | |||
244 | --[[-------------------------------------------------------------------- | ||
245 | -- variable (global|local|upvalue) handling | ||
246 | -- * a pure parser does not really need this, but if we want to produce | ||
247 | -- useful output, might as well write minimal code to manage this... | ||
248 | -- * entry point is singlevar() for variable lookups | ||
249 | -- * three entry points for local variable creation, in order to keep | ||
250 | -- to original C calls, but the extra arguments such as positioning | ||
251 | -- are removed as we are not allocating registers -- we are only | ||
252 | -- doing simple classification | ||
253 | -- * lookup tables (bl.locallist) are maintained awkwardly in the basic | ||
254 | -- block data structures, PLUS the function data structure (this is | ||
255 | -- an inelegant hack, since bl is nil for the top level of a function) | ||
256 | ----------------------------------------------------------------------]] | ||
257 | |||
258 | -------------------------------------------------------------------- | ||
259 | -- register a local variable, set in active variable list | ||
260 | -- * used in new_localvarstr(), parlist(), fornum(), forlist(), | ||
261 | -- localfunc(), localstat() | ||
262 | -------------------------------------------------------------------- | ||
263 | function luaY:new_localvar(name) | ||
264 | local bl = fs.bl | ||
265 | local locallist | ||
266 | if bl then | ||
267 | locallist = bl.locallist | ||
268 | else | ||
269 | locallist = fs.locallist | ||
270 | end | ||
271 | locallist[name] = true | ||
272 | self:log(" new_localvar: '"..name.."'") | ||
273 | end | ||
274 | -------------------------------------------------------------------- | ||
275 | -- creates a new local variable given a name | ||
276 | -- * used in fornum(), forlist() for loop variables; in create_local() | ||
277 | -------------------------------------------------------------------- | ||
278 | function luaY:new_localvarstr(name) | ||
279 | self:new_localvar(name) | ||
280 | end | ||
281 | -------------------------------------------------------------------- | ||
282 | -- creates a single local variable and activates it | ||
283 | -- * used only in code_params() for "arg", body() for "self" | ||
284 | -------------------------------------------------------------------- | ||
285 | function luaY:create_local(name) | ||
286 | self:new_localvarstr(name) | ||
287 | end | ||
288 | |||
289 | -------------------------------------------------------------------- | ||
290 | -- search the local variable namespace of the given fs for a match | ||
291 | -- * a simple lookup only, no active variable list kept, so no useful | ||
292 | -- index value can be returned by this function | ||
293 | -- * used only in singlevaraux() | ||
294 | -------------------------------------------------------------------- | ||
295 | function luaY:searchvar(fs, n) | ||
296 | local bl = fs.bl | ||
297 | if bl then | ||
298 | locallist = bl.locallist | ||
299 | while locallist do | ||
300 | if locallist[n] then return 1 end -- found | ||
301 | bl = bl.prev | ||
302 | locallist = bl and bl.locallist | ||
303 | end | ||
304 | end | ||
305 | locallist = fs.locallist | ||
306 | if locallist[n] then return 1 end -- found | ||
307 | return -1 -- not found | ||
308 | end | ||
309 | -------------------------------------------------------------------- | ||
310 | -- handle locals, globals and upvalues and related processing | ||
311 | -- * search mechanism is recursive, calls itself to search parents | ||
312 | -- * used only in singlevar() | ||
313 | -------------------------------------------------------------------- | ||
314 | function luaY:singlevaraux(fs, n, var, base) | ||
315 | if fs == nil then -- no more levels? | ||
316 | var.k = "VGLOBAL" -- default is global variable | ||
317 | else | ||
318 | local v = self:searchvar(fs, n) -- look up at current level | ||
319 | if v >= 0 then | ||
320 | var.k = "VLOCAL" | ||
321 | else -- not found at current level; try upper one | ||
322 | self:singlevaraux(fs.prev, n, var, 0) | ||
323 | if var.k == "VGLOBAL" then | ||
324 | -- handle global var processing here | ||
325 | else -- LOCAL or UPVAL | ||
326 | var.k = "VUPVAL" | ||
327 | end | ||
328 | end--if v | ||
329 | end--if fs | ||
330 | end | ||
331 | -------------------------------------------------------------------- | ||
332 | -- consume a name token, creates a variable (global|local|upvalue) | ||
333 | -- * used in prefixexp(), funcname() | ||
334 | -------------------------------------------------------------------- | ||
335 | function luaY:singlevar(v) | ||
336 | local varname = self:str_checkname() | ||
337 | self:singlevaraux(fs, varname, v, 1) | ||
338 | self:log(" singlevar(kind): '"..v.k.."'") | ||
339 | end | ||
340 | |||
341 | --[[-------------------------------------------------------------------- | ||
342 | -- other parsing functions | ||
343 | -- * for table constructor, parameter list, argument list | ||
344 | ----------------------------------------------------------------------]] | ||
345 | |||
346 | -------------------------------------------------------------------- | ||
347 | -- parse a function name suffix, for function call specifications | ||
348 | -- * used in primaryexp(), funcname() | ||
349 | -------------------------------------------------------------------- | ||
350 | function luaY:field(v) | ||
351 | -- field -> ['.' | ':'] NAME | ||
352 | local key = {} | ||
353 | self:log(" field: operator="..tok) | ||
354 | self:next() -- skip the dot or colon | ||
355 | self:checkname(key) | ||
356 | v.k = "VINDEXED" | ||
357 | end | ||
358 | -------------------------------------------------------------------- | ||
359 | -- parse a table indexing suffix, for constructors, expressions | ||
360 | -- * used in recfield(), primaryexp() | ||
361 | -------------------------------------------------------------------- | ||
362 | function luaY:index(v) | ||
363 | -- index -> '[' expr ']' | ||
364 | self:log(">> index: begin '['") | ||
365 | self:next() -- skip the '[' | ||
366 | self:expr(v) | ||
367 | self:check("]") | ||
368 | self:log("<< index: end ']'") | ||
369 | end | ||
370 | -------------------------------------------------------------------- | ||
371 | -- parse a table record (hash) field | ||
372 | -- * used in constructor() | ||
373 | -------------------------------------------------------------------- | ||
374 | function luaY:recfield(cc) | ||
375 | -- recfield -> (NAME | '['exp1']') = exp1 | ||
376 | local key, val = {}, {} | ||
377 | if tok == "<name>" then | ||
378 | self:log("recfield: name") | ||
379 | self:checkname(key) | ||
380 | else-- tok == '[' | ||
381 | self:log("recfield: [ exp1 ]") | ||
382 | self:index(key) | ||
383 | end | ||
384 | self:check("=") | ||
385 | self:expr(val) | ||
386 | end | ||
387 | -------------------------------------------------------------------- | ||
388 | -- emit a set list instruction if enough elements (LFIELDS_PER_FLUSH) | ||
389 | -- * note: retained in this skeleton because it modifies cc.v.k | ||
390 | -- * used in constructor() | ||
391 | -------------------------------------------------------------------- | ||
392 | function luaY:closelistfield(cc) | ||
393 | if cc.v.k == "VVOID" then return end -- there is no list item | ||
394 | cc.v.k = "VVOID" | ||
395 | end | ||
396 | -------------------------------------------------------------------- | ||
397 | -- parse a table list (array) field | ||
398 | -- * used in constructor() | ||
399 | -------------------------------------------------------------------- | ||
400 | function luaY:listfield(cc) | ||
401 | self:log("listfield: expr") | ||
402 | self:expr(cc.v) | ||
403 | end | ||
404 | -------------------------------------------------------------------- | ||
405 | -- parse a table constructor | ||
406 | -- * used in funcargs(), simpleexp() | ||
407 | -------------------------------------------------------------------- | ||
408 | function luaY:constructor(t) | ||
409 | -- constructor -> '{' [ field { fieldsep field } [ fieldsep ] ] '}' | ||
410 | -- field -> recfield | listfield | ||
411 | -- fieldsep -> ',' | ';' | ||
412 | self:log(">> constructor: begin") | ||
413 | local line = luaX.ln | ||
414 | local cc = {} | ||
415 | cc.v = {} | ||
416 | cc.t = t | ||
417 | t.k = "VRELOCABLE" | ||
418 | cc.v.k = "VVOID" | ||
419 | self:check("{") | ||
420 | repeat | ||
421 | self:testnext(";") -- compatibility only | ||
422 | if tok == "}" then break end | ||
423 | -- closelistfield(cc) here | ||
424 | local c = tok | ||
425 | if c == "<name>" then -- may be listfields or recfields | ||
426 | if self:lookahead() ~= "=" then -- look ahead: expression? | ||
427 | self:listfield(cc) | ||
428 | else | ||
429 | self:recfield(cc) | ||
430 | end | ||
431 | elseif c == "[" then -- constructor_item -> recfield | ||
432 | self:recfield(cc) | ||
433 | else -- constructor_part -> listfield | ||
434 | self:listfield(cc) | ||
435 | end | ||
436 | until not self:testnext(",") and not self:testnext(";") | ||
437 | self:check_match("}", "{", line) | ||
438 | -- lastlistfield(cc) here | ||
439 | self:log("<< constructor: end") | ||
440 | end | ||
441 | -------------------------------------------------------------------- | ||
442 | -- parse the arguments (parameters) of a function declaration | ||
443 | -- * used in body() | ||
444 | -------------------------------------------------------------------- | ||
445 | function luaY:parlist() | ||
446 | -- parlist -> [ param { ',' param } ] | ||
447 | self:log(">> parlist: begin") | ||
448 | local dots = false | ||
449 | if tok ~= ")" then -- is 'parlist' not empty? | ||
450 | repeat | ||
451 | local c = tok | ||
452 | if c == "..." then | ||
453 | self:log("parlist: ... (dots)") | ||
454 | dots = true | ||
455 | self:next() | ||
456 | elseif c == "<name>" then | ||
457 | self:new_localvar(self:str_checkname()) | ||
458 | else | ||
459 | self:syntaxerror("<name> or '...' expected") | ||
460 | end | ||
461 | until dots or not self:testnext(",") | ||
462 | end | ||
463 | -- was code_params() | ||
464 | if dots then | ||
465 | self:create_local("arg") | ||
466 | end | ||
467 | self:log("<< parlist: end") | ||
468 | end | ||
469 | -------------------------------------------------------------------- | ||
470 | -- parse the parameters of a function call | ||
471 | -- * contrast with parlist(), used in function declarations | ||
472 | -- * used in primaryexp() | ||
473 | -------------------------------------------------------------------- | ||
474 | function luaY:funcargs(f) | ||
475 | local args = {} | ||
476 | local line = luaX.ln | ||
477 | local c = tok | ||
478 | if c == "(" then -- funcargs -> '(' [ explist1 ] ')' | ||
479 | self:log(">> funcargs: begin '('") | ||
480 | if line ~= lastln then | ||
481 | self:syntaxerror("ambiguous syntax (function call x new statement)") | ||
482 | end | ||
483 | self:next() | ||
484 | if tok == ")" then -- arg list is empty? | ||
485 | args.k = "VVOID" | ||
486 | else | ||
487 | self:explist1(args) | ||
488 | end | ||
489 | self:check_match(")", "(", line) | ||
490 | elseif c == "{" then -- funcargs -> constructor | ||
491 | self:log(">> funcargs: begin '{'") | ||
492 | self:constructor(args) | ||
493 | elseif c == "<string>" then -- funcargs -> STRING | ||
494 | self:log(">> funcargs: begin <string>") | ||
495 | self:codestring(args, seminfo) | ||
496 | self:next() -- must use 'seminfo' before 'next' | ||
497 | else | ||
498 | self:syntaxerror("function arguments expected") | ||
499 | return | ||
500 | end--if c | ||
501 | f.k = "VCALL" | ||
502 | self:log("<< funcargs: end -- expr is a VCALL") | ||
503 | end | ||
504 | |||
505 | --[[-------------------------------------------------------------------- | ||
506 | -- mostly expression functions | ||
507 | ----------------------------------------------------------------------]] | ||
508 | |||
509 | -------------------------------------------------------------------- | ||
510 | -- parses an expression in parentheses or a single variable | ||
511 | -- * used in primaryexp() | ||
512 | -------------------------------------------------------------------- | ||
513 | function luaY:prefixexp(v) | ||
514 | -- prefixexp -> NAME | '(' expr ')' | ||
515 | local c = tok | ||
516 | if c == "(" then | ||
517 | self:log(">> prefixexp: begin ( expr ) ") | ||
518 | local line = self.ln | ||
519 | self:next() | ||
520 | self:expr(v) | ||
521 | self:check_match(")", "(", line) | ||
522 | self:log("<< prefixexp: end ( expr ) ") | ||
523 | elseif c == "<name>" then | ||
524 | self:log("prefixexp: <name>") | ||
525 | self:singlevar(v) | ||
526 | else | ||
527 | self:syntaxerror("unexpected symbol") | ||
528 | end--if c | ||
529 | end | ||
530 | -------------------------------------------------------------------- | ||
531 | -- parses a prefixexp (an expression in parentheses or a single | ||
532 | -- variable) or a function call specification | ||
533 | -- * used in simpleexp(), assignment(), expr_stat() | ||
534 | -------------------------------------------------------------------- | ||
535 | function luaY:primaryexp(v) | ||
536 | -- primaryexp -> | ||
537 | -- prefixexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } | ||
538 | self:prefixexp(v) | ||
539 | while true do | ||
540 | local c = tok | ||
541 | if c == "." then -- field | ||
542 | self:log("primaryexp: '.' field") | ||
543 | self:field(v) | ||
544 | elseif c == "[" then -- '[' exp1 ']' | ||
545 | self:log("primaryexp: [ exp1 ]") | ||
546 | local key = {} | ||
547 | self:index(key) | ||
548 | elseif c == ":" then -- ':' NAME funcargs | ||
549 | self:log("primaryexp: :<name> funcargs") | ||
550 | local key = {} | ||
551 | self:next() | ||
552 | self:checkname(key) | ||
553 | self:funcargs(v) | ||
554 | elseif c == "(" or c == "<string>" or c == "{" then -- funcargs | ||
555 | self:log("primaryexp: "..c.." funcargs") | ||
556 | self:funcargs(v) | ||
557 | else | ||
558 | return | ||
559 | end--if c | ||
560 | end--while | ||
561 | end | ||
562 | -------------------------------------------------------------------- | ||
563 | -- parses general expression types, constants handled here | ||
564 | -- * used in subexpr() | ||
565 | -------------------------------------------------------------------- | ||
566 | function luaY:simpleexp(v) | ||
567 | -- simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | constructor | ||
568 | -- | FUNCTION body | primaryexp | ||
569 | local c = tok | ||
570 | if c == "<number>" then | ||
571 | self:log("simpleexp: <number>="..seminfo) | ||
572 | v.k = "VK" | ||
573 | self:next() -- must use 'seminfo' before 'next' | ||
574 | elseif c == "<string>" then | ||
575 | self:log("simpleexp: <string>="..seminfo) | ||
576 | self:codestring(v, seminfo) | ||
577 | self:next() -- must use 'seminfo' before 'next' | ||
578 | elseif c == "nil" then | ||
579 | self:log("simpleexp: nil") | ||
580 | v.k = "VNIL" | ||
581 | self:next() | ||
582 | elseif c == "true" then | ||
583 | self:log("simpleexp: true") | ||
584 | v.k = "VTRUE" | ||
585 | self:next() | ||
586 | elseif c == "false" then | ||
587 | self:log("simpleexp: false") | ||
588 | v.k = "VFALSE" | ||
589 | self:next() | ||
590 | elseif c == "{" then -- constructor | ||
591 | self:log("simpleexp: constructor") | ||
592 | self:constructor(v) | ||
593 | elseif c == "function" then | ||
594 | self:log("simpleexp: function") | ||
595 | self:next() | ||
596 | self:body(v, false, luaX.ln) | ||
597 | else | ||
598 | self:primaryexp(v) | ||
599 | end--if c | ||
600 | end | ||
601 | ------------------------------------------------------------------------ | ||
602 | -- Parse subexpressions. Includes handling of unary operators and binary | ||
603 | -- operators. A subexpr is given the rhs priority level of the operator | ||
604 | -- immediately left of it, if any (limit is -1 if none,) and if a binop | ||
605 | -- is found, limit is compared with the lhs priority level of the binop | ||
606 | -- in order to determine which executes first. | ||
607 | -- * recursively called | ||
608 | -- * used in expr() | ||
609 | ------------------------------------------------------------------------ | ||
610 | function luaY:subexpr(v, limit) | ||
611 | -- subexpr -> (simpleexp | unop subexpr) { binop subexpr } | ||
612 | -- * where 'binop' is any binary operator with a priority | ||
613 | -- higher than 'limit' | ||
614 | local op = tok | ||
615 | local uop = unopr[op] | ||
616 | if uop then | ||
617 | self:log(" subexpr: uop='"..op.."'") | ||
618 | self:next() | ||
619 | self:subexpr(v, 8) -- UNARY_PRIORITY | ||
620 | else | ||
621 | self:simpleexp(v) | ||
622 | end | ||
623 | -- expand while operators have priorities higher than 'limit' | ||
624 | op = tok | ||
625 | local binop = binopr_left[op] | ||
626 | while binop and binop > limit do | ||
627 | local v2 = {} | ||
628 | self:log(">> subexpr: binop='"..op.."'") | ||
629 | self:next() | ||
630 | -- read sub-expression with higher priority | ||
631 | local nextop = self:subexpr(v2, binopr_right[op]) | ||
632 | self:log("<< subexpr: -- evaluate") | ||
633 | op = nextop | ||
634 | binop = binopr_left[op] | ||
635 | end | ||
636 | return op -- return first untreated operator | ||
637 | end | ||
638 | -------------------------------------------------------------------- | ||
639 | -- Expression parsing starts here. Function subexpr is entered with the | ||
640 | -- left operator (which is non-existent) priority of -1, which is lower | ||
641 | -- than all actual operators. Expr information is returned in parm v. | ||
642 | -- * used in cond(), explist1(), index(), recfield(), listfield(), | ||
643 | -- prefixexp(), while_stat(), exp1() | ||
644 | -------------------------------------------------------------------- | ||
645 | function luaY:expr(v) | ||
646 | -- expr -> subexpr | ||
647 | self:log("expr:") | ||
648 | self:subexpr(v, -1) | ||
649 | end | ||
650 | |||
651 | --[[-------------------------------------------------------------------- | ||
652 | -- third level parsing functions | ||
653 | ----------------------------------------------------------------------]] | ||
654 | |||
655 | -------------------------------------------------------------------- | ||
656 | -- parse a variable assignment sequence | ||
657 | -- * recursively called | ||
658 | -- * used in expr_stat() | ||
659 | -------------------------------------------------------------------- | ||
660 | function luaY:assignment(v) | ||
661 | local e = {} | ||
662 | local c = v.v.k | ||
663 | self:check_condition(c == "VLOCAL" or c == "VUPVAL" or c == "VGLOBAL" | ||
664 | or c == "VINDEXED", "syntax error") | ||
665 | if self:testnext(",") then -- assignment -> ',' primaryexp assignment | ||
666 | local nv = {} -- expdesc | ||
667 | nv.v = {} | ||
668 | self:log("assignment: ',' -- next LHS element") | ||
669 | self:primaryexp(nv.v) | ||
670 | -- lparser.c deals with some register usage conflict here | ||
671 | self:assignment(nv) | ||
672 | else -- assignment -> '=' explist1 | ||
673 | self:check("=") | ||
674 | self:log("assignment: '=' -- RHS elements follows") | ||
675 | self:explist1(e) | ||
676 | return -- avoid default | ||
677 | end | ||
678 | e.k = "VNONRELOC" | ||
679 | end | ||
680 | -------------------------------------------------------------------- | ||
681 | -- parse a for loop body for both versions of the for loop | ||
682 | -- * used in fornum(), forlist() | ||
683 | -------------------------------------------------------------------- | ||
684 | function luaY:forbody(line, isnum) | ||
685 | self:check("do") | ||
686 | self:enterblock(true) -- loop block | ||
687 | self:block() | ||
688 | self:leaveblock() | ||
689 | end | ||
690 | -------------------------------------------------------------------- | ||
691 | -- parse a numerical for loop, calls forbody() | ||
692 | -- * used in for_stat() | ||
693 | -------------------------------------------------------------------- | ||
694 | function luaY:fornum(varname, line) | ||
695 | -- fornum -> NAME = exp1, exp1 [, exp1] DO body | ||
696 | self:new_localvar(varname) | ||
697 | self:new_localvarstr("(for limit)") | ||
698 | self:new_localvarstr("(for step)") | ||
699 | self:log(">> fornum: begin") | ||
700 | self:check("=") | ||
701 | self:log("fornum: index start") | ||
702 | self:exp1() -- initial value | ||
703 | self:check(",") | ||
704 | self:log("fornum: index stop") | ||
705 | self:exp1() -- limit | ||
706 | if self:testnext(",") then | ||
707 | self:log("fornum: index step") | ||
708 | self:exp1() -- optional step | ||
709 | else | ||
710 | -- default step = 1 | ||
711 | end | ||
712 | self:log("fornum: body") | ||
713 | self:forbody(line, true) | ||
714 | self:log("<< fornum: end") | ||
715 | end | ||
716 | -------------------------------------------------------------------- | ||
717 | -- parse a generic for loop, calls forbody() | ||
718 | -- * used in for_stat() | ||
719 | -------------------------------------------------------------------- | ||
720 | function luaY:forlist(indexname) | ||
721 | -- forlist -> NAME {, NAME} IN explist1 DO body | ||
722 | self:log(">> forlist: begin") | ||
723 | local e = {} | ||
724 | self:new_localvarstr("(for generator)") | ||
725 | self:new_localvarstr("(for state)") | ||
726 | self:new_localvar(indexname) | ||
727 | while self:testnext(",") do | ||
728 | self:new_localvar(self:str_checkname()) | ||
729 | end | ||
730 | self:check("in") | ||
731 | local line = line | ||
732 | self:log("forlist: explist1") | ||
733 | self:explist1(e) | ||
734 | self:log("forlist: body") | ||
735 | self:forbody(line, false) | ||
736 | self:log("<< forlist: end") | ||
737 | end | ||
738 | -------------------------------------------------------------------- | ||
739 | -- parse a function name specification | ||
740 | -- * used in func_stat() | ||
741 | -------------------------------------------------------------------- | ||
742 | function luaY:funcname(v) | ||
743 | -- funcname -> NAME {field} [':' NAME] | ||
744 | self:log(">> funcname: begin") | ||
745 | local needself = false | ||
746 | self:singlevar(v) | ||
747 | while tok == "." do | ||
748 | self:log("funcname: -- '.' field") | ||
749 | self:field(v) | ||
750 | end | ||
751 | if tok == ":" then | ||
752 | self:log("funcname: -- ':' field") | ||
753 | needself = true | ||
754 | self:field(v) | ||
755 | end | ||
756 | self:log("<< funcname: end") | ||
757 | return needself | ||
758 | end | ||
759 | -------------------------------------------------------------------- | ||
760 | -- parse the single expressions needed in numerical for loops | ||
761 | -- * used in fornum() | ||
762 | -------------------------------------------------------------------- | ||
763 | function luaY:exp1() | ||
764 | -- exp1 -> expr | ||
765 | local e = {} | ||
766 | self:log(">> exp1: begin") | ||
767 | self:expr(e) | ||
768 | self:log("<< exp1: end") | ||
769 | end | ||
770 | -------------------------------------------------------------------- | ||
771 | -- parse condition in a repeat statement or an if control structure | ||
772 | -- * used in repeat_stat(), test_then_block() | ||
773 | -------------------------------------------------------------------- | ||
774 | function luaY:cond(v) | ||
775 | -- cond -> expr | ||
776 | self:log(">> cond: begin") | ||
777 | self:expr(v) -- read condition | ||
778 | self:log("<< cond: end") | ||
779 | end | ||
780 | -------------------------------------------------------------------- | ||
781 | -- parse part of an if control structure, including the condition | ||
782 | -- * used in if_stat() | ||
783 | -------------------------------------------------------------------- | ||
784 | function luaY:test_then_block(v) | ||
785 | -- test_then_block -> [IF | ELSEIF] cond THEN block | ||
786 | self:next() -- skip IF or ELSEIF | ||
787 | self:log("test_then_block: test condition") | ||
788 | self:cond(v) | ||
789 | self:check("then") | ||
790 | self:log("test_then_block: then block") | ||
791 | self:block() -- 'then' part | ||
792 | end | ||
793 | -------------------------------------------------------------------- | ||
794 | -- parse a local function statement | ||
795 | -- * used in local_stat() | ||
796 | -------------------------------------------------------------------- | ||
797 | function luaY:localfunc() | ||
798 | -- localfunc -> NAME body | ||
799 | local v, b = {} | ||
800 | self:log("localfunc: begin") | ||
801 | self:new_localvar(self:str_checkname()) | ||
802 | v.k = "VLOCAL" | ||
803 | self:log("localfunc: body") | ||
804 | self:body(b, false, luaX.ln) | ||
805 | self:log("localfunc: end") | ||
806 | end | ||
807 | -------------------------------------------------------------------- | ||
808 | -- parse a local variable declaration statement | ||
809 | -- * used in local_stat() | ||
810 | -------------------------------------------------------------------- | ||
811 | function luaY:localstat() | ||
812 | -- localstat -> NAME {',' NAME} ['=' explist1] | ||
813 | self:log(">> localstat: begin") | ||
814 | local e = {} | ||
815 | repeat | ||
816 | self:new_localvar(self:str_checkname()) | ||
817 | until not self:testnext(",") | ||
818 | if self:testnext("=") then | ||
819 | self:log("localstat: -- assignment") | ||
820 | self:explist1(e) | ||
821 | else | ||
822 | e.k = "VVOID" | ||
823 | end | ||
824 | self:log("<< localstat: end") | ||
825 | end | ||
826 | -------------------------------------------------------------------- | ||
827 | -- parse a list of comma-separated expressions | ||
828 | -- * used in return_stat(), localstat(), funcargs(), assignment(), | ||
829 | -- forlist() | ||
830 | -------------------------------------------------------------------- | ||
831 | function luaY:explist1(e) | ||
832 | -- explist1 -> expr { ',' expr } | ||
833 | self:log(">> explist1: begin") | ||
834 | self:expr(e) | ||
835 | while self:testnext(",") do | ||
836 | self:log("explist1: ',' -- continuation") | ||
837 | self:expr(e) | ||
838 | end | ||
839 | self:log("<< explist1: end") | ||
840 | end | ||
841 | -------------------------------------------------------------------- | ||
842 | -- parse function declaration body | ||
843 | -- * used in simpleexp(), localfunc(), func_stat() | ||
844 | -------------------------------------------------------------------- | ||
845 | function luaY:body(e, needself, line) | ||
846 | -- body -> '(' parlist ')' chunk END | ||
847 | self:open_func() | ||
848 | self:log("body: begin") | ||
849 | self:check("(") | ||
850 | if needself then | ||
851 | self:create_local("self") | ||
852 | end | ||
853 | self:log("body: parlist") | ||
854 | self:parlist() | ||
855 | self:check(")") | ||
856 | self:log("body: chunk") | ||
857 | self:chunk() | ||
858 | self:check_match("end", "function", line) | ||
859 | self:log("body: end") | ||
860 | self:close_func() | ||
861 | end | ||
862 | -------------------------------------------------------------------- | ||
863 | -- parse a code block or unit | ||
864 | -- * used in do_stat(), while_stat(), repeat_stat(), forbody(), | ||
865 | -- test_then_block(), if_stat() | ||
866 | -------------------------------------------------------------------- | ||
867 | function luaY:block() | ||
868 | -- block -> chunk | ||
869 | self:log("block: begin") | ||
870 | self:enterblock(false) | ||
871 | self:chunk() | ||
872 | self:leaveblock() | ||
873 | self:log("block: end") | ||
874 | end | ||
875 | |||
876 | --[[-------------------------------------------------------------------- | ||
877 | -- second level parsing functions, all with '_stat' suffix | ||
878 | -- * stat() -> *_stat() | ||
879 | ----------------------------------------------------------------------]] | ||
880 | |||
881 | -------------------------------------------------------------------- | ||
882 | -- initial parsing for a for loop, calls fornum() or forlist() | ||
883 | -- * used in stat() | ||
884 | -------------------------------------------------------------------- | ||
885 | function luaY:for_stat() | ||
886 | -- stat -> for_stat -> fornum | forlist | ||
887 | local line = line | ||
888 | self:log("for_stat: begin") | ||
889 | self:enterblock(false) -- block to control variable scope | ||
890 | self:next() -- skip 'for' | ||
891 | local varname = self:str_checkname() -- first variable name | ||
892 | local c = tok | ||
893 | if c == "=" then | ||
894 | self:log("for_stat: numerical loop") | ||
895 | self:fornum(varname, line) | ||
896 | elseif c == "," or c == "in" then | ||
897 | self:log("for_stat: list-based loop") | ||
898 | self:forlist(varname) | ||
899 | else | ||
900 | self:syntaxerror("'=' or 'in' expected") | ||
901 | end | ||
902 | self:check_match("end", "for", line) | ||
903 | self:leaveblock() | ||
904 | self:log("for_stat: end") | ||
905 | end | ||
906 | -------------------------------------------------------------------- | ||
907 | -- parse a while-do control structure, body processed by block() | ||
908 | -- * used in stat() | ||
909 | -------------------------------------------------------------------- | ||
910 | function luaY:while_stat() | ||
911 | -- stat -> while_stat -> WHILE cond DO block END | ||
912 | local line = line | ||
913 | local v = {} | ||
914 | self:next() -- skip WHILE | ||
915 | self:log("while_stat: begin/condition") | ||
916 | self:expr(v) -- parse condition | ||
917 | self:enterblock(true) | ||
918 | self:check("do") | ||
919 | self:log("while_stat: block") | ||
920 | self:block() | ||
921 | self:check_match("end", "while", line) | ||
922 | self:leaveblock() | ||
923 | self:log("while_stat: end") | ||
924 | end | ||
925 | -------------------------------------------------------------------- | ||
926 | -- parse a repeat-until control structure, body parsed by block() | ||
927 | -- * used in stat() | ||
928 | -------------------------------------------------------------------- | ||
929 | function luaY:repeat_stat() | ||
930 | -- stat -> repeat_stat -> REPEAT block UNTIL cond | ||
931 | local line = line | ||
932 | local v = {} | ||
933 | self:log("repeat_stat: begin") | ||
934 | self:enterblock(true) | ||
935 | self:next() | ||
936 | self:block() | ||
937 | self:check_match("until", "repeat", line) | ||
938 | self:log("repeat_stat: condition") | ||
939 | self:cond(v) | ||
940 | self:leaveblock() | ||
941 | self:log("repeat_stat: end") | ||
942 | end | ||
943 | -------------------------------------------------------------------- | ||
944 | -- parse an if control structure | ||
945 | -- * used in stat() | ||
946 | -------------------------------------------------------------------- | ||
947 | function luaY:if_stat() | ||
948 | -- stat -> if_stat -> IF cond THEN block | ||
949 | -- {ELSEIF cond THEN block} [ELSE block] END | ||
950 | local line = line | ||
951 | local v = {} | ||
952 | self:log("if_stat: if...then") | ||
953 | self:test_then_block(v) -- IF cond THEN block | ||
954 | while tok == "elseif" do | ||
955 | self:log("if_stat: elseif...then") | ||
956 | self:test_then_block(v) -- ELSEIF cond THEN block | ||
957 | end | ||
958 | if tok == "else" then | ||
959 | self:log("if_stat: else...") | ||
960 | self:next() -- skip ELSE | ||
961 | self:block() -- 'else' part | ||
962 | end | ||
963 | self:check_match("end", "if", line) | ||
964 | self:log("if_stat: end") | ||
965 | end | ||
966 | -------------------------------------------------------------------- | ||
967 | -- parse a return statement | ||
968 | -- * used in stat() | ||
969 | -------------------------------------------------------------------- | ||
970 | function luaY:return_stat() | ||
971 | -- stat -> return_stat -> RETURN explist | ||
972 | local e = {} | ||
973 | self:next() -- skip RETURN | ||
974 | local c = tok | ||
975 | if block_follow[c] or c == ";" then | ||
976 | -- return no values | ||
977 | self:log("return_stat: no return values") | ||
978 | else | ||
979 | self:log("return_stat: begin") | ||
980 | self:explist1(e) -- optional return values | ||
981 | self:log("return_stat: end") | ||
982 | end | ||
983 | end | ||
984 | -------------------------------------------------------------------- | ||
985 | -- parse a break statement | ||
986 | -- * used in stat() | ||
987 | -------------------------------------------------------------------- | ||
988 | function luaY:break_stat() | ||
989 | -- stat -> break_stat -> BREAK | ||
990 | local bl = fs.bl | ||
991 | self:next() -- skip BREAK | ||
992 | while bl and not bl.isbreakable do -- find a breakable block | ||
993 | bl = bl.prev | ||
994 | end | ||
995 | if not bl then | ||
996 | self:syntaxerror("no loop to break") | ||
997 | end | ||
998 | self:log("break_stat: -- break out of loop") | ||
999 | end | ||
1000 | -------------------------------------------------------------------- | ||
1001 | -- parse a function call with no returns or an assignment statement | ||
1002 | -- * the struct with .prev is used for name searching in lparse.c, | ||
1003 | -- so it is retained for now; present in assignment() also | ||
1004 | -- * used in stat() | ||
1005 | -------------------------------------------------------------------- | ||
1006 | function luaY:expr_stat() | ||
1007 | -- stat -> expr_stat -> func | assignment | ||
1008 | local v = {} | ||
1009 | v.v = {} | ||
1010 | self:primaryexp(v.v) | ||
1011 | if v.v.k == "VCALL" then -- stat -> func | ||
1012 | -- call statement uses no results | ||
1013 | self:log("expr_stat: function call k='"..v.v.k.."'") | ||
1014 | else -- stat -> assignment | ||
1015 | self:log("expr_stat: assignment k='"..v.v.k.."'") | ||
1016 | v.prev = nil | ||
1017 | self:assignment(v) | ||
1018 | end | ||
1019 | end | ||
1020 | -------------------------------------------------------------------- | ||
1021 | -- parse a function statement | ||
1022 | -- * used in stat() | ||
1023 | -------------------------------------------------------------------- | ||
1024 | function luaY:function_stat() | ||
1025 | -- stat -> function_stat -> FUNCTION funcname body | ||
1026 | local line = line | ||
1027 | local v, b = {}, {} | ||
1028 | self:log("function_stat: begin") | ||
1029 | self:next() -- skip FUNCTION | ||
1030 | local needself = self:funcname(v) | ||
1031 | self:log("function_stat: body needself='"..tostring(needself).."'") | ||
1032 | self:body(b, needself, line) | ||
1033 | self:log("function_stat: end") | ||
1034 | end | ||
1035 | -------------------------------------------------------------------- | ||
1036 | -- parse a simple block enclosed by a DO..END pair | ||
1037 | -- * used in stat() | ||
1038 | -------------------------------------------------------------------- | ||
1039 | function luaY:do_stat() | ||
1040 | -- stat -> do_stat -> DO block END | ||
1041 | self:next() -- skip DO | ||
1042 | self:log("do_stat: begin") | ||
1043 | self:block() | ||
1044 | self:log("do_stat: end") | ||
1045 | self:check_match("end", "do", line) | ||
1046 | end | ||
1047 | -------------------------------------------------------------------- | ||
1048 | -- parse a statement starting with LOCAL | ||
1049 | -- * used in stat() | ||
1050 | -------------------------------------------------------------------- | ||
1051 | function luaY:local_stat() | ||
1052 | -- stat -> local_stat -> LOCAL FUNCTION localfunc | ||
1053 | -- -> LOCAL localstat | ||
1054 | self:next() -- skip LOCAL | ||
1055 | if self:testnext("function") then -- local function? | ||
1056 | self:log("local_stat: local function") | ||
1057 | self:localfunc() | ||
1058 | else | ||
1059 | self:log("local_stat: local statement") | ||
1060 | self:localstat() | ||
1061 | end | ||
1062 | end | ||
1063 | |||
1064 | --[[-------------------------------------------------------------------- | ||
1065 | -- main function, top level parsing functions | ||
1066 | -- * [entry] -> parser() -> chunk() -> stat() | ||
1067 | ----------------------------------------------------------------------]] | ||
1068 | |||
1069 | -------------------------------------------------------------------- | ||
1070 | -- initial parsing for statements, calls '_stat' suffixed functions | ||
1071 | -- * used in chunk() | ||
1072 | -------------------------------------------------------------------- | ||
1073 | function luaY:stat() | ||
1074 | line = luaX.ln | ||
1075 | local c = tok | ||
1076 | local fn = stat_call[c] | ||
1077 | -- handles: if while do for repeat function local return break | ||
1078 | if fn then | ||
1079 | self:log("-- STATEMENT: begin '"..c.."' line="..line) | ||
1080 | self[fn](self) | ||
1081 | self:log("-- STATEMENT: end '"..c.."'") | ||
1082 | -- return or break must be last statement | ||
1083 | if c == "return" or c == "break" then return true end | ||
1084 | else | ||
1085 | self:log("-- STATEMENT: begin 'expr' line="..line) | ||
1086 | self:expr_stat() | ||
1087 | self:log("-- STATEMENT: end 'expr'") | ||
1088 | end | ||
1089 | self:log("") | ||
1090 | return false | ||
1091 | end | ||
1092 | -------------------------------------------------------------------- | ||
1093 | -- parse a chunk, which consists of a bunch of statements | ||
1094 | -- * used in parser(), body(), block() | ||
1095 | -------------------------------------------------------------------- | ||
1096 | function luaY:chunk() | ||
1097 | -- chunk -> { stat [';'] } | ||
1098 | self:log("chunk:") | ||
1099 | local islast = false | ||
1100 | while not islast and not block_follow[tok] do | ||
1101 | islast = self:stat() | ||
1102 | self:testnext(";") | ||
1103 | end | ||
1104 | end | ||
1105 | -------------------------------------------------------------------- | ||
1106 | -- performs parsing, returns parsed data structure | ||
1107 | -------------------------------------------------------------------- | ||
1108 | function luaY:parser() | ||
1109 | self:log("-- TOP: begin") | ||
1110 | self:open_func() | ||
1111 | self:log("") | ||
1112 | self:next() -- read first token | ||
1113 | self:chunk() | ||
1114 | self:check_condition(tok == "<eof>", "<eof> expected") | ||
1115 | self:close_func() | ||
1116 | self:log("-- TOP: end") | ||
1117 | return top_fs | ||
1118 | end | ||
1119 | -------------------------------------------------------------------- | ||
1120 | return luaY -- return actual module to user, done | ||
1121 | end | ||