diff options
author | David Walter Seikel | 2014-04-21 20:59:39 +1000 |
---|---|---|
committer | David Walter Seikel | 2014-04-21 20:59:39 +1000 |
commit | 9621add2918cc4943e6693b74ae85d51dd264fcf (patch) | |
tree | fff1edf2c69d7a08a0e12885eecc9b96ed847a6a /LuaSL/testLua/yueliang-0.4.1/nat-5.0.3/lparser_mk3.lua | |
parent | LuaSL_test's window doesn't need to be so huge. (diff) | |
download | SledjHamr-9621add2918cc4943e6693b74ae85d51dd264fcf.zip SledjHamr-9621add2918cc4943e6693b74ae85d51dd264fcf.tar.gz SledjHamr-9621add2918cc4943e6693b74ae85d51dd264fcf.tar.bz2 SledjHamr-9621add2918cc4943e6693b74ae85d51dd264fcf.tar.xz |
We don't need the testlua directory any more.
Diffstat (limited to 'LuaSL/testLua/yueliang-0.4.1/nat-5.0.3/lparser_mk3.lua')
-rw-r--r-- | LuaSL/testLua/yueliang-0.4.1/nat-5.0.3/lparser_mk3.lua | 1027 |
1 files changed, 0 insertions, 1027 deletions
diff --git a/LuaSL/testLua/yueliang-0.4.1/nat-5.0.3/lparser_mk3.lua b/LuaSL/testLua/yueliang-0.4.1/nat-5.0.3/lparser_mk3.lua deleted file mode 100644 index 17d6f64..0000000 --- a/LuaSL/testLua/yueliang-0.4.1/nat-5.0.3/lparser_mk3.lua +++ /dev/null | |||
@@ -1,1027 +0,0 @@ | |||
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) no variable management code! singlevar() always returns VLOCAL | ||
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 | fs.bl = bl | ||
209 | self:log(">> enterblock(isbreakable="..tostring(isbreakable)..")") | ||
210 | end | ||
211 | -------------------------------------------------------------------- | ||
212 | -- leaves a code unit, close any upvalues | ||
213 | -------------------------------------------------------------------- | ||
214 | function luaY:leaveblock() | ||
215 | local bl = fs.bl | ||
216 | fs.bl = bl.prev | ||
217 | self:log("<< leaveblock") | ||
218 | end | ||
219 | -------------------------------------------------------------------- | ||
220 | -- opening of a function | ||
221 | -------------------------------------------------------------------- | ||
222 | function luaY:open_func() | ||
223 | local new_fs -- per-function state | ||
224 | if not fs then -- top_fs is created early | ||
225 | new_fs = top_fs | ||
226 | else | ||
227 | new_fs = {} | ||
228 | end | ||
229 | new_fs.prev = fs -- linked list of function states | ||
230 | new_fs.bl = nil | ||
231 | fs = new_fs | ||
232 | self:log(">> open_func") | ||
233 | end | ||
234 | -------------------------------------------------------------------- | ||
235 | -- closing of a function | ||
236 | -------------------------------------------------------------------- | ||
237 | function luaY:close_func() | ||
238 | fs = fs.prev | ||
239 | self:log("<< close_func") | ||
240 | end | ||
241 | |||
242 | --[[-------------------------------------------------------------------- | ||
243 | -- variable (global|local|upvalue) handling | ||
244 | -- * does nothing for now, always returns "VLOCAL" | ||
245 | ----------------------------------------------------------------------]] | ||
246 | |||
247 | -------------------------------------------------------------------- | ||
248 | -- consume a name token, creates a variable (global|local|upvalue) | ||
249 | -- * used in prefixexp(), funcname() | ||
250 | -------------------------------------------------------------------- | ||
251 | function luaY:singlevar(v) | ||
252 | local varname = self:str_checkname() | ||
253 | v.k = "VLOCAL" | ||
254 | self:log(" singlevar: name='"..varname.."'") | ||
255 | end | ||
256 | |||
257 | --[[-------------------------------------------------------------------- | ||
258 | -- other parsing functions | ||
259 | -- * for table constructor, parameter list, argument list | ||
260 | ----------------------------------------------------------------------]] | ||
261 | |||
262 | -------------------------------------------------------------------- | ||
263 | -- parse a function name suffix, for function call specifications | ||
264 | -- * used in primaryexp(), funcname() | ||
265 | -------------------------------------------------------------------- | ||
266 | function luaY:field(v) | ||
267 | -- field -> ['.' | ':'] NAME | ||
268 | local key = {} | ||
269 | self:log(" field: operator="..tok) | ||
270 | self:next() -- skip the dot or colon | ||
271 | self:checkname(key) | ||
272 | v.k = "VINDEXED" | ||
273 | end | ||
274 | -------------------------------------------------------------------- | ||
275 | -- parse a table indexing suffix, for constructors, expressions | ||
276 | -- * used in recfield(), primaryexp() | ||
277 | -------------------------------------------------------------------- | ||
278 | function luaY:index(v) | ||
279 | -- index -> '[' expr ']' | ||
280 | self:log(">> index: begin '['") | ||
281 | self:next() -- skip the '[' | ||
282 | self:expr(v) | ||
283 | self:check("]") | ||
284 | self:log("<< index: end ']'") | ||
285 | end | ||
286 | -------------------------------------------------------------------- | ||
287 | -- parse a table record (hash) field | ||
288 | -- * used in constructor() | ||
289 | -------------------------------------------------------------------- | ||
290 | function luaY:recfield(cc) | ||
291 | -- recfield -> (NAME | '['exp1']') = exp1 | ||
292 | local key, val = {}, {} | ||
293 | if tok == "<name>" then | ||
294 | self:log("recfield: name") | ||
295 | self:checkname(key) | ||
296 | else-- tok == '[' | ||
297 | self:log("recfield: [ exp1 ]") | ||
298 | self:index(key) | ||
299 | end | ||
300 | self:check("=") | ||
301 | self:expr(val) | ||
302 | end | ||
303 | -------------------------------------------------------------------- | ||
304 | -- emit a set list instruction if enough elements (LFIELDS_PER_FLUSH) | ||
305 | -- * note: retained in this skeleton because it modifies cc.v.k | ||
306 | -- * used in constructor() | ||
307 | -------------------------------------------------------------------- | ||
308 | function luaY:closelistfield(cc) | ||
309 | if cc.v.k == "VVOID" then return end -- there is no list item | ||
310 | cc.v.k = "VVOID" | ||
311 | end | ||
312 | -------------------------------------------------------------------- | ||
313 | -- parse a table list (array) field | ||
314 | -- * used in constructor() | ||
315 | -------------------------------------------------------------------- | ||
316 | function luaY:listfield(cc) | ||
317 | self:log("listfield: expr") | ||
318 | self:expr(cc.v) | ||
319 | end | ||
320 | -------------------------------------------------------------------- | ||
321 | -- parse a table constructor | ||
322 | -- * used in funcargs(), simpleexp() | ||
323 | -------------------------------------------------------------------- | ||
324 | function luaY:constructor(t) | ||
325 | -- constructor -> '{' [ field { fieldsep field } [ fieldsep ] ] '}' | ||
326 | -- field -> recfield | listfield | ||
327 | -- fieldsep -> ',' | ';' | ||
328 | self:log(">> constructor: begin") | ||
329 | local line = luaX.ln | ||
330 | local cc = {} | ||
331 | cc.v = {} | ||
332 | cc.t = t | ||
333 | t.k = "VRELOCABLE" | ||
334 | cc.v.k = "VVOID" | ||
335 | self:check("{") | ||
336 | repeat | ||
337 | self:testnext(";") -- compatibility only | ||
338 | if tok == "}" then break end | ||
339 | -- closelistfield(cc) here | ||
340 | local c = tok | ||
341 | if c == "<name>" then -- may be listfields or recfields | ||
342 | if self:lookahead() ~= "=" then -- look ahead: expression? | ||
343 | self:listfield(cc) | ||
344 | else | ||
345 | self:recfield(cc) | ||
346 | end | ||
347 | elseif c == "[" then -- constructor_item -> recfield | ||
348 | self:recfield(cc) | ||
349 | else -- constructor_part -> listfield | ||
350 | self:listfield(cc) | ||
351 | end | ||
352 | until not self:testnext(",") and not self:testnext(";") | ||
353 | self:check_match("}", "{", line) | ||
354 | -- lastlistfield(cc) here | ||
355 | self:log("<< constructor: end") | ||
356 | end | ||
357 | -------------------------------------------------------------------- | ||
358 | -- parse the arguments (parameters) of a function declaration | ||
359 | -- * used in body() | ||
360 | -------------------------------------------------------------------- | ||
361 | function luaY:parlist() | ||
362 | -- parlist -> [ param { ',' param } ] | ||
363 | self:log(">> parlist: begin") | ||
364 | local dots = false | ||
365 | if tok ~= ")" then -- is 'parlist' not empty? | ||
366 | repeat | ||
367 | local c = tok | ||
368 | if c == "..." then | ||
369 | self:log("parlist: ... (dots)") | ||
370 | dots = true | ||
371 | self:next() | ||
372 | elseif c == "<name>" then | ||
373 | local str = self:str_checkname() | ||
374 | else | ||
375 | self:syntaxerror("<name> or '...' expected") | ||
376 | end | ||
377 | until dots or not self:testnext(",") | ||
378 | end | ||
379 | self:log("<< parlist: end") | ||
380 | end | ||
381 | -------------------------------------------------------------------- | ||
382 | -- parse the parameters of a function call | ||
383 | -- * contrast with parlist(), used in function declarations | ||
384 | -- * used in primaryexp() | ||
385 | -------------------------------------------------------------------- | ||
386 | function luaY:funcargs(f) | ||
387 | local args = {} | ||
388 | local line = luaX.ln | ||
389 | local c = tok | ||
390 | if c == "(" then -- funcargs -> '(' [ explist1 ] ')' | ||
391 | self:log(">> funcargs: begin '('") | ||
392 | if line ~= lastln then | ||
393 | self:syntaxerror("ambiguous syntax (function call x new statement)") | ||
394 | end | ||
395 | self:next() | ||
396 | if tok == ")" then -- arg list is empty? | ||
397 | args.k = "VVOID" | ||
398 | else | ||
399 | self:explist1(args) | ||
400 | end | ||
401 | self:check_match(")", "(", line) | ||
402 | elseif c == "{" then -- funcargs -> constructor | ||
403 | self:log(">> funcargs: begin '{'") | ||
404 | self:constructor(args) | ||
405 | elseif c == "<string>" then -- funcargs -> STRING | ||
406 | self:log(">> funcargs: begin <string>") | ||
407 | self:codestring(args, seminfo) | ||
408 | self:next() -- must use 'seminfo' before 'next' | ||
409 | else | ||
410 | self:syntaxerror("function arguments expected") | ||
411 | return | ||
412 | end--if c | ||
413 | f.k = "VCALL" | ||
414 | self:log("<< funcargs: end -- expr is a VCALL") | ||
415 | end | ||
416 | |||
417 | --[[-------------------------------------------------------------------- | ||
418 | -- mostly expression functions | ||
419 | ----------------------------------------------------------------------]] | ||
420 | |||
421 | -------------------------------------------------------------------- | ||
422 | -- parses an expression in parentheses or a single variable | ||
423 | -- * used in primaryexp() | ||
424 | -------------------------------------------------------------------- | ||
425 | function luaY:prefixexp(v) | ||
426 | -- prefixexp -> NAME | '(' expr ')' | ||
427 | local c = tok | ||
428 | if c == "(" then | ||
429 | self:log(">> prefixexp: begin ( expr ) ") | ||
430 | local line = self.ln | ||
431 | self:next() | ||
432 | self:expr(v) | ||
433 | self:check_match(")", "(", line) | ||
434 | self:log("<< prefixexp: end ( expr ) ") | ||
435 | elseif c == "<name>" then | ||
436 | self:log("prefixexp: <name>") | ||
437 | self:singlevar(v) | ||
438 | else | ||
439 | self:syntaxerror("unexpected symbol") | ||
440 | end--if c | ||
441 | end | ||
442 | -------------------------------------------------------------------- | ||
443 | -- parses a prefixexp (an expression in parentheses or a single | ||
444 | -- variable) or a function call specification | ||
445 | -- * used in simpleexp(), assignment(), expr_stat() | ||
446 | -------------------------------------------------------------------- | ||
447 | function luaY:primaryexp(v) | ||
448 | -- primaryexp -> | ||
449 | -- prefixexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } | ||
450 | self:prefixexp(v) | ||
451 | while true do | ||
452 | local c = tok | ||
453 | if c == "." then -- field | ||
454 | self:log("primaryexp: '.' field") | ||
455 | self:field(v) | ||
456 | elseif c == "[" then -- '[' exp1 ']' | ||
457 | self:log("primaryexp: [ exp1 ]") | ||
458 | local key = {} | ||
459 | self:index(key) | ||
460 | elseif c == ":" then -- ':' NAME funcargs | ||
461 | self:log("primaryexp: :<name> funcargs") | ||
462 | local key = {} | ||
463 | self:next() | ||
464 | self:checkname(key) | ||
465 | self:funcargs(v) | ||
466 | elseif c == "(" or c == "<string>" or c == "{" then -- funcargs | ||
467 | self:log("primaryexp: "..c.." funcargs") | ||
468 | self:funcargs(v) | ||
469 | else | ||
470 | return | ||
471 | end--if c | ||
472 | end--while | ||
473 | end | ||
474 | -------------------------------------------------------------------- | ||
475 | -- parses general expression types, constants handled here | ||
476 | -- * used in subexpr() | ||
477 | -------------------------------------------------------------------- | ||
478 | function luaY:simpleexp(v) | ||
479 | -- simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | constructor | ||
480 | -- | FUNCTION body | primaryexp | ||
481 | local c = tok | ||
482 | if c == "<number>" then | ||
483 | self:log("simpleexp: <number>="..seminfo) | ||
484 | v.k = "VK" | ||
485 | self:next() -- must use 'seminfo' before 'next' | ||
486 | elseif c == "<string>" then | ||
487 | self:log("simpleexp: <string>="..seminfo) | ||
488 | self:codestring(v, seminfo) | ||
489 | self:next() -- must use 'seminfo' before 'next' | ||
490 | elseif c == "nil" then | ||
491 | self:log("simpleexp: nil") | ||
492 | v.k = "VNIL" | ||
493 | self:next() | ||
494 | elseif c == "true" then | ||
495 | self:log("simpleexp: true") | ||
496 | v.k = "VTRUE" | ||
497 | self:next() | ||
498 | elseif c == "false" then | ||
499 | self:log("simpleexp: false") | ||
500 | v.k = "VFALSE" | ||
501 | self:next() | ||
502 | elseif c == "{" then -- constructor | ||
503 | self:log("simpleexp: constructor") | ||
504 | self:constructor(v) | ||
505 | elseif c == "function" then | ||
506 | self:log("simpleexp: function") | ||
507 | self:next() | ||
508 | self:body(v, false, luaX.ln) | ||
509 | else | ||
510 | self:primaryexp(v) | ||
511 | end--if c | ||
512 | end | ||
513 | ------------------------------------------------------------------------ | ||
514 | -- Parse subexpressions. Includes handling of unary operators and binary | ||
515 | -- operators. A subexpr is given the rhs priority level of the operator | ||
516 | -- immediately left of it, if any (limit is -1 if none,) and if a binop | ||
517 | -- is found, limit is compared with the lhs priority level of the binop | ||
518 | -- in order to determine which executes first. | ||
519 | -- * recursively called | ||
520 | -- * used in expr() | ||
521 | ------------------------------------------------------------------------ | ||
522 | function luaY:subexpr(v, limit) | ||
523 | -- subexpr -> (simpleexp | unop subexpr) { binop subexpr } | ||
524 | -- * where 'binop' is any binary operator with a priority | ||
525 | -- higher than 'limit' | ||
526 | local op = tok | ||
527 | local uop = unopr[op] | ||
528 | if uop then | ||
529 | self:log(" subexpr: uop='"..op.."'") | ||
530 | self:next() | ||
531 | self:subexpr(v, 8) -- UNARY_PRIORITY | ||
532 | else | ||
533 | self:simpleexp(v) | ||
534 | end | ||
535 | -- expand while operators have priorities higher than 'limit' | ||
536 | op = tok | ||
537 | local binop = binopr_left[op] | ||
538 | while binop and binop > limit do | ||
539 | local v2 = {} | ||
540 | self:log(">> subexpr: binop='"..op.."'") | ||
541 | self:next() | ||
542 | -- read sub-expression with higher priority | ||
543 | local nextop = self:subexpr(v2, binopr_right[op]) | ||
544 | self:log("<< subexpr: -- evaluate") | ||
545 | op = nextop | ||
546 | binop = binopr_left[op] | ||
547 | end | ||
548 | return op -- return first untreated operator | ||
549 | end | ||
550 | -------------------------------------------------------------------- | ||
551 | -- Expression parsing starts here. Function subexpr is entered with the | ||
552 | -- left operator (which is non-existent) priority of -1, which is lower | ||
553 | -- than all actual operators. Expr information is returned in parm v. | ||
554 | -- * used in cond(), explist1(), index(), recfield(), listfield(), | ||
555 | -- prefixexp(), while_stat(), exp1() | ||
556 | -------------------------------------------------------------------- | ||
557 | function luaY:expr(v) | ||
558 | -- expr -> subexpr | ||
559 | self:log("expr:") | ||
560 | self:subexpr(v, -1) | ||
561 | end | ||
562 | |||
563 | --[[-------------------------------------------------------------------- | ||
564 | -- third level parsing functions | ||
565 | ----------------------------------------------------------------------]] | ||
566 | |||
567 | -------------------------------------------------------------------- | ||
568 | -- parse a variable assignment sequence | ||
569 | -- * recursively called | ||
570 | -- * used in expr_stat() | ||
571 | -------------------------------------------------------------------- | ||
572 | function luaY:assignment(v) | ||
573 | local e = {} | ||
574 | local c = v.v.k | ||
575 | self:check_condition(c == "VLOCAL" or c == "VUPVAL" or c == "VGLOBAL" | ||
576 | or c == "VINDEXED", "syntax error") | ||
577 | if self:testnext(",") then -- assignment -> ',' primaryexp assignment | ||
578 | local nv = {} -- expdesc | ||
579 | nv.v = {} | ||
580 | self:log("assignment: ',' -- next LHS element") | ||
581 | self:primaryexp(nv.v) | ||
582 | -- lparser.c deals with some register usage conflict here | ||
583 | self:assignment(nv) | ||
584 | else -- assignment -> '=' explist1 | ||
585 | self:check("=") | ||
586 | self:log("assignment: '=' -- RHS elements follows") | ||
587 | self:explist1(e) | ||
588 | return -- avoid default | ||
589 | end | ||
590 | e.k = "VNONRELOC" | ||
591 | end | ||
592 | -------------------------------------------------------------------- | ||
593 | -- parse a for loop body for both versions of the for loop | ||
594 | -- * used in fornum(), forlist() | ||
595 | -------------------------------------------------------------------- | ||
596 | function luaY:forbody(line, isnum) | ||
597 | self:check("do") | ||
598 | self:enterblock(true) -- loop block | ||
599 | self:block() | ||
600 | self:leaveblock() | ||
601 | end | ||
602 | -------------------------------------------------------------------- | ||
603 | -- parse a numerical for loop, calls forbody() | ||
604 | -- * used in for_stat() | ||
605 | -------------------------------------------------------------------- | ||
606 | function luaY:fornum(line) | ||
607 | -- fornum -> NAME = exp1, exp1 [, exp1] DO body | ||
608 | self:log(">> fornum: begin") | ||
609 | self:check("=") | ||
610 | self:log("fornum: index start") | ||
611 | self:exp1() -- initial value | ||
612 | self:check(",") | ||
613 | self:log("fornum: index stop") | ||
614 | self:exp1() -- limit | ||
615 | if self:testnext(",") then | ||
616 | self:log("fornum: index step") | ||
617 | self:exp1() -- optional step | ||
618 | else | ||
619 | -- default step = 1 | ||
620 | end | ||
621 | self:log("fornum: body") | ||
622 | self:forbody(line, true) | ||
623 | self:log("<< fornum: end") | ||
624 | end | ||
625 | -------------------------------------------------------------------- | ||
626 | -- parse a generic for loop, calls forbody() | ||
627 | -- * used in for_stat() | ||
628 | -------------------------------------------------------------------- | ||
629 | function luaY:forlist() | ||
630 | -- forlist -> NAME {, NAME} IN explist1 DO body | ||
631 | self:log(">> forlist: begin") | ||
632 | local e = {} | ||
633 | while self:testnext(",") do | ||
634 | self:str_checkname() | ||
635 | end | ||
636 | self:check("in") | ||
637 | local line = line | ||
638 | self:log("forlist: explist1") | ||
639 | self:explist1(e) | ||
640 | self:log("forlist: body") | ||
641 | self:forbody(line, false) | ||
642 | self:log("<< forlist: end") | ||
643 | end | ||
644 | -------------------------------------------------------------------- | ||
645 | -- parse a function name specification | ||
646 | -- * used in func_stat() | ||
647 | -------------------------------------------------------------------- | ||
648 | function luaY:funcname(v) | ||
649 | -- funcname -> NAME {field} [':' NAME] | ||
650 | self:log(">> funcname: begin") | ||
651 | local needself = false | ||
652 | self:singlevar(v) | ||
653 | while tok == "." do | ||
654 | self:log("funcname: -- '.' field") | ||
655 | self:field(v) | ||
656 | end | ||
657 | if tok == ":" then | ||
658 | self:log("funcname: -- ':' field") | ||
659 | needself = true | ||
660 | self:field(v) | ||
661 | end | ||
662 | self:log("<< funcname: end") | ||
663 | return needself | ||
664 | end | ||
665 | -------------------------------------------------------------------- | ||
666 | -- parse the single expressions needed in numerical for loops | ||
667 | -- * used in fornum() | ||
668 | -------------------------------------------------------------------- | ||
669 | function luaY:exp1() | ||
670 | -- exp1 -> expr | ||
671 | local e = {} | ||
672 | self:log(">> exp1: begin") | ||
673 | self:expr(e) | ||
674 | self:log("<< exp1: end") | ||
675 | end | ||
676 | -------------------------------------------------------------------- | ||
677 | -- parse condition in a repeat statement or an if control structure | ||
678 | -- * used in repeat_stat(), test_then_block() | ||
679 | -------------------------------------------------------------------- | ||
680 | function luaY:cond(v) | ||
681 | -- cond -> expr | ||
682 | self:log(">> cond: begin") | ||
683 | self:expr(v) -- read condition | ||
684 | self:log("<< cond: end") | ||
685 | end | ||
686 | -------------------------------------------------------------------- | ||
687 | -- parse part of an if control structure, including the condition | ||
688 | -- * used in if_stat() | ||
689 | -------------------------------------------------------------------- | ||
690 | function luaY:test_then_block(v) | ||
691 | -- test_then_block -> [IF | ELSEIF] cond THEN block | ||
692 | self:next() -- skip IF or ELSEIF | ||
693 | self:log("test_then_block: test condition") | ||
694 | self:cond(v) | ||
695 | self:check("then") | ||
696 | self:log("test_then_block: then block") | ||
697 | self:block() -- 'then' part | ||
698 | end | ||
699 | -------------------------------------------------------------------- | ||
700 | -- parse a local function statement | ||
701 | -- * used in local_stat() | ||
702 | -------------------------------------------------------------------- | ||
703 | function luaY:localfunc() | ||
704 | -- localfunc -> NAME body | ||
705 | local v, b = {} | ||
706 | self:log("localfunc: begin") | ||
707 | local str = self:str_checkname() | ||
708 | v.k = "VLOCAL" | ||
709 | self:log("localfunc: body") | ||
710 | self:body(b, false, luaX.ln) | ||
711 | self:log("localfunc: end") | ||
712 | end | ||
713 | -------------------------------------------------------------------- | ||
714 | -- parse a local variable declaration statement | ||
715 | -- * used in local_stat() | ||
716 | -------------------------------------------------------------------- | ||
717 | function luaY:localstat() | ||
718 | -- localstat -> NAME {',' NAME} ['=' explist1] | ||
719 | self:log(">> localstat: begin") | ||
720 | local e = {} | ||
721 | repeat | ||
722 | local str = self:str_checkname() | ||
723 | until not self:testnext(",") | ||
724 | if self:testnext("=") then | ||
725 | self:log("localstat: -- assignment") | ||
726 | self:explist1(e) | ||
727 | else | ||
728 | e.k = "VVOID" | ||
729 | end | ||
730 | self:log("<< localstat: end") | ||
731 | end | ||
732 | -------------------------------------------------------------------- | ||
733 | -- parse a list of comma-separated expressions | ||
734 | -- * used in return_stat(), localstat(), funcargs(), assignment(), | ||
735 | -- forlist() | ||
736 | -------------------------------------------------------------------- | ||
737 | function luaY:explist1(e) | ||
738 | -- explist1 -> expr { ',' expr } | ||
739 | self:log(">> explist1: begin") | ||
740 | self:expr(e) | ||
741 | while self:testnext(",") do | ||
742 | self:log("explist1: ',' -- continuation") | ||
743 | self:expr(e) | ||
744 | end | ||
745 | self:log("<< explist1: end") | ||
746 | end | ||
747 | -------------------------------------------------------------------- | ||
748 | -- parse function declaration body | ||
749 | -- * used in simpleexp(), localfunc(), func_stat() | ||
750 | -------------------------------------------------------------------- | ||
751 | function luaY:body(e, needself, line) | ||
752 | -- body -> '(' parlist ')' chunk END | ||
753 | self:open_func() | ||
754 | self:log("body: begin") | ||
755 | self:check("(") | ||
756 | if needself then | ||
757 | -- handle 'self' processing here | ||
758 | end | ||
759 | self:log("body: parlist") | ||
760 | self:parlist() | ||
761 | self:check(")") | ||
762 | self:log("body: chunk") | ||
763 | self:chunk() | ||
764 | self:check_match("end", "function", line) | ||
765 | self:log("body: end") | ||
766 | self:close_func() | ||
767 | end | ||
768 | -------------------------------------------------------------------- | ||
769 | -- parse a code block or unit | ||
770 | -- * used in do_stat(), while_stat(), repeat_stat(), forbody(), | ||
771 | -- test_then_block(), if_stat() | ||
772 | -------------------------------------------------------------------- | ||
773 | function luaY:block() | ||
774 | -- block -> chunk | ||
775 | self:log("block: begin") | ||
776 | self:enterblock(false) | ||
777 | self:chunk() | ||
778 | self:leaveblock() | ||
779 | self:log("block: end") | ||
780 | end | ||
781 | |||
782 | --[[-------------------------------------------------------------------- | ||
783 | -- second level parsing functions, all with '_stat' suffix | ||
784 | -- * stat() -> *_stat() | ||
785 | ----------------------------------------------------------------------]] | ||
786 | |||
787 | -------------------------------------------------------------------- | ||
788 | -- initial parsing for a for loop, calls fornum() or forlist() | ||
789 | -- * used in stat() | ||
790 | -------------------------------------------------------------------- | ||
791 | function luaY:for_stat() | ||
792 | -- stat -> for_stat -> fornum | forlist | ||
793 | local line = line | ||
794 | self:log("for_stat: begin") | ||
795 | self:enterblock(false) -- block to control variable scope | ||
796 | self:next() -- skip 'for' | ||
797 | local str = self:str_checkname() -- first variable name | ||
798 | local c = tok | ||
799 | if c == "=" then | ||
800 | self:log("for_stat: numerical loop") | ||
801 | self:fornum(line) | ||
802 | elseif c == "," or c == "in" then | ||
803 | self:log("for_stat: list-based loop") | ||
804 | self:forlist() | ||
805 | else | ||
806 | self:syntaxerror("'=' or 'in' expected") | ||
807 | end | ||
808 | self:check_match("end", "for", line) | ||
809 | self:leaveblock() | ||
810 | self:log("for_stat: end") | ||
811 | end | ||
812 | -------------------------------------------------------------------- | ||
813 | -- parse a while-do control structure, body processed by block() | ||
814 | -- * used in stat() | ||
815 | -------------------------------------------------------------------- | ||
816 | function luaY:while_stat() | ||
817 | -- stat -> while_stat -> WHILE cond DO block END | ||
818 | local line = line | ||
819 | local v = {} | ||
820 | self:next() -- skip WHILE | ||
821 | self:log("while_stat: begin/condition") | ||
822 | self:expr(v) -- parse condition | ||
823 | self:enterblock(true) | ||
824 | self:check("do") | ||
825 | self:log("while_stat: block") | ||
826 | self:block() | ||
827 | self:check_match("end", "while", line) | ||
828 | self:leaveblock() | ||
829 | self:log("while_stat: end") | ||
830 | end | ||
831 | -------------------------------------------------------------------- | ||
832 | -- parse a repeat-until control structure, body parsed by block() | ||
833 | -- * used in stat() | ||
834 | -------------------------------------------------------------------- | ||
835 | function luaY:repeat_stat() | ||
836 | -- stat -> repeat_stat -> REPEAT block UNTIL cond | ||
837 | local line = line | ||
838 | local v = {} | ||
839 | self:log("repeat_stat: begin") | ||
840 | self:enterblock(true) | ||
841 | self:next() | ||
842 | self:block() | ||
843 | self:check_match("until", "repeat", line) | ||
844 | self:log("repeat_stat: condition") | ||
845 | self:cond(v) | ||
846 | self:leaveblock() | ||
847 | self:log("repeat_stat: end") | ||
848 | end | ||
849 | -------------------------------------------------------------------- | ||
850 | -- parse an if control structure | ||
851 | -- * used in stat() | ||
852 | -------------------------------------------------------------------- | ||
853 | function luaY:if_stat() | ||
854 | -- stat -> if_stat -> IF cond THEN block | ||
855 | -- {ELSEIF cond THEN block} [ELSE block] END | ||
856 | local line = line | ||
857 | local v = {} | ||
858 | self:log("if_stat: if...then") | ||
859 | self:test_then_block(v) -- IF cond THEN block | ||
860 | while tok == "elseif" do | ||
861 | self:log("if_stat: elseif...then") | ||
862 | self:test_then_block(v) -- ELSEIF cond THEN block | ||
863 | end | ||
864 | if tok == "else" then | ||
865 | self:log("if_stat: else...") | ||
866 | self:next() -- skip ELSE | ||
867 | self:block() -- 'else' part | ||
868 | end | ||
869 | self:check_match("end", "if", line) | ||
870 | self:log("if_stat: end") | ||
871 | end | ||
872 | -------------------------------------------------------------------- | ||
873 | -- parse a return statement | ||
874 | -- * used in stat() | ||
875 | -------------------------------------------------------------------- | ||
876 | function luaY:return_stat() | ||
877 | -- stat -> return_stat -> RETURN explist | ||
878 | local e = {} | ||
879 | self:next() -- skip RETURN | ||
880 | local c = tok | ||
881 | if block_follow[c] or c == ";" then | ||
882 | -- return no values | ||
883 | self:log("return_stat: no return values") | ||
884 | else | ||
885 | self:log("return_stat: begin") | ||
886 | self:explist1(e) -- optional return values | ||
887 | self:log("return_stat: end") | ||
888 | end | ||
889 | end | ||
890 | -------------------------------------------------------------------- | ||
891 | -- parse a break statement | ||
892 | -- * used in stat() | ||
893 | -------------------------------------------------------------------- | ||
894 | function luaY:break_stat() | ||
895 | -- stat -> break_stat -> BREAK | ||
896 | local bl = fs.bl | ||
897 | self:next() -- skip BREAK | ||
898 | while bl and not bl.isbreakable do -- find a breakable block | ||
899 | bl = bl.prev | ||
900 | end | ||
901 | if not bl then | ||
902 | self:syntaxerror("no loop to break") | ||
903 | end | ||
904 | self:log("break_stat: -- break out of loop") | ||
905 | end | ||
906 | -------------------------------------------------------------------- | ||
907 | -- parse a function call with no returns or an assignment statement | ||
908 | -- * the struct with .prev is used for name searching in lparse.c, | ||
909 | -- so it is retained for now; present in assignment() also | ||
910 | -- * used in stat() | ||
911 | -------------------------------------------------------------------- | ||
912 | function luaY:expr_stat() | ||
913 | -- stat -> expr_stat -> func | assignment | ||
914 | local v = {} | ||
915 | v.v = {} | ||
916 | self:primaryexp(v.v) | ||
917 | if v.v.k == "VCALL" then -- stat -> func | ||
918 | -- call statement uses no results | ||
919 | self:log("expr_stat: function call k='"..v.v.k.."'") | ||
920 | else -- stat -> assignment | ||
921 | self:log("expr_stat: assignment k='"..v.v.k.."'") | ||
922 | v.prev = nil | ||
923 | self:assignment(v) | ||
924 | end | ||
925 | end | ||
926 | -------------------------------------------------------------------- | ||
927 | -- parse a function statement | ||
928 | -- * used in stat() | ||
929 | -------------------------------------------------------------------- | ||
930 | function luaY:function_stat() | ||
931 | -- stat -> function_stat -> FUNCTION funcname body | ||
932 | local line = line | ||
933 | local v, b = {}, {} | ||
934 | self:log("function_stat: begin") | ||
935 | self:next() -- skip FUNCTION | ||
936 | local needself = self:funcname(v) | ||
937 | self:log("function_stat: body needself='"..tostring(needself).."'") | ||
938 | self:body(b, needself, line) | ||
939 | self:log("function_stat: end") | ||
940 | end | ||
941 | -------------------------------------------------------------------- | ||
942 | -- parse a simple block enclosed by a DO..END pair | ||
943 | -- * used in stat() | ||
944 | -------------------------------------------------------------------- | ||
945 | function luaY:do_stat() | ||
946 | -- stat -> do_stat -> DO block END | ||
947 | self:next() -- skip DO | ||
948 | self:log("do_stat: begin") | ||
949 | self:block() | ||
950 | self:log("do_stat: end") | ||
951 | self:check_match("end", "do", line) | ||
952 | end | ||
953 | -------------------------------------------------------------------- | ||
954 | -- parse a statement starting with LOCAL | ||
955 | -- * used in stat() | ||
956 | -------------------------------------------------------------------- | ||
957 | function luaY:local_stat() | ||
958 | -- stat -> local_stat -> LOCAL FUNCTION localfunc | ||
959 | -- -> LOCAL localstat | ||
960 | self:next() -- skip LOCAL | ||
961 | if self:testnext("function") then -- local function? | ||
962 | self:log("local_stat: local function") | ||
963 | self:localfunc() | ||
964 | else | ||
965 | self:log("local_stat: local statement") | ||
966 | self:localstat() | ||
967 | end | ||
968 | end | ||
969 | |||
970 | --[[-------------------------------------------------------------------- | ||
971 | -- main function, top level parsing functions | ||
972 | -- * [entry] -> parser() -> chunk() -> stat() | ||
973 | ----------------------------------------------------------------------]] | ||
974 | |||
975 | -------------------------------------------------------------------- | ||
976 | -- initial parsing for statements, calls '_stat' suffixed functions | ||
977 | -- * used in chunk() | ||
978 | -------------------------------------------------------------------- | ||
979 | function luaY:stat() | ||
980 | line = luaX.ln | ||
981 | local c = tok | ||
982 | local fn = stat_call[c] | ||
983 | -- handles: if while do for repeat function local return break | ||
984 | if fn then | ||
985 | self:log("-- STATEMENT: begin '"..c.."' line="..line) | ||
986 | self[fn](self) | ||
987 | self:log("-- STATEMENT: end '"..c.."'") | ||
988 | -- return or break must be last statement | ||
989 | if c == "return" or c == "break" then return true end | ||
990 | else | ||
991 | self:log("-- STATEMENT: begin 'expr' line="..line) | ||
992 | self:expr_stat() | ||
993 | self:log("-- STATEMENT: end 'expr'") | ||
994 | end | ||
995 | self:log("") | ||
996 | return false | ||
997 | end | ||
998 | -------------------------------------------------------------------- | ||
999 | -- parse a chunk, which consists of a bunch of statements | ||
1000 | -- * used in parser(), body(), block() | ||
1001 | -------------------------------------------------------------------- | ||
1002 | function luaY:chunk() | ||
1003 | -- chunk -> { stat [';'] } | ||
1004 | self:log("chunk:") | ||
1005 | local islast = false | ||
1006 | while not islast and not block_follow[tok] do | ||
1007 | islast = self:stat() | ||
1008 | self:testnext(";") | ||
1009 | end | ||
1010 | end | ||
1011 | -------------------------------------------------------------------- | ||
1012 | -- performs parsing, returns parsed data structure | ||
1013 | -------------------------------------------------------------------- | ||
1014 | function luaY:parser() | ||
1015 | self:log("-- TOP: begin") | ||
1016 | self:open_func() | ||
1017 | self:log("") | ||
1018 | self:next() -- read first token | ||
1019 | self:chunk() | ||
1020 | self:check_condition(tok == "<eof>", "<eof> expected") | ||
1021 | self:close_func() | ||
1022 | self:log("-- TOP: end") | ||
1023 | return top_fs | ||
1024 | end | ||
1025 | -------------------------------------------------------------------- | ||
1026 | return luaY -- return actual module to user, done | ||
1027 | end | ||