| 1 | --[[-------------------------------------------------------------------- |
| 2 | |
| 3 | lparser.lua: Lua 5.1 parser in Lua |
| 4 | This file is part of LuaSrcDiet, based on Yueliang material. |
| 5 | |
| 6 | Copyright (c) 2008 Kein-Hong Man <khman@users.sf.net> |
| 7 | The COPYRIGHT file describes the conditions |
| 8 | under which this software may be distributed. |
| 9 | |
| 10 | See the ChangeLog for more information. |
| 11 | |
| 12 | ----------------------------------------------------------------------]] |
| 13 | |
| 14 | --[[-------------------------------------------------------------------- |
| 15 | -- NOTES: |
| 16 | -- * This is a version of the native 5.1.x parser from Yueliang 0.4.0, |
| 17 | -- with significant modifications to handle LuaSrcDiet's needs: |
| 18 | -- (1) needs pre-built token tables instead of a module.method |
| 19 | -- (2) lparser.error is an optional error handler (from llex) |
| 20 | -- (3) not full parsing, currently fakes raw/unlexed constants |
| 21 | -- (4) parser() returns globalinfo, localinfo tables |
| 22 | -- * Please read technotes.txt for more technical details. |
| 23 | -- * NO support for 'arg' vararg functions (LUA_COMPAT_VARARG) |
| 24 | -- * A lot of the parser is unused, but might later be useful for |
| 25 | -- full-on parsing and analysis for a few measly bytes saved. |
| 26 | ----------------------------------------------------------------------]] |
| 27 | |
| 28 | local base = _G |
| 29 | local string = require "string" |
| 30 | --2018-06-10: RH - The lparser return table is declared here to satisfy the stat function. Stat |
| 31 | -- must exist before chunk and parse so creating a placeholderis the easiest solution. |
| 32 | local lparser = {} |
| 33 | |
| 34 | |
| 35 | --[[-------------------------------------------------------------------- |
| 36 | -- variable and data structure initialization |
| 37 | ----------------------------------------------------------------------]] |
| 38 | |
| 39 | ---------------------------------------------------------------------- |
| 40 | -- initialization: main variables |
| 41 | ---------------------------------------------------------------------- |
| 42 | |
| 43 | local toklist, -- grammar-only token tables (token table, |
| 44 | seminfolist, -- semantic information table, line number |
| 45 | toklnlist, -- table, cross-reference table) |
| 46 | xreflist, |
| 47 | tpos, -- token position |
| 48 | |
| 49 | line, -- start line # for error messages |
| 50 | lastln, -- last line # for ambiguous syntax chk |
| 51 | tok, seminfo, ln, xref, -- token, semantic info, line |
| 52 | nameref, -- proper position of <name> token |
| 53 | fs, -- current function state |
| 54 | top_fs, -- top-level function state |
| 55 | |
| 56 | globalinfo, -- global variable information table |
| 57 | globallookup, -- global variable name lookup table |
| 58 | localinfo, -- local variable information table |
| 59 | ilocalinfo, -- inactive locals (prior to activation) |
| 60 | ilocalrefs -- corresponding references to activate |
| 61 | |
| 62 | -- forward references for local functions |
| 63 | local explist1, expr, block, exp1, body, chunk |
| 64 | |
| 65 | ---------------------------------------------------------------------- |
| 66 | -- initialization: data structures |
| 67 | ---------------------------------------------------------------------- |
| 68 | |
| 69 | local gmatch = string.gmatch |
| 70 | |
| 71 | local block_follow = {} -- lookahead check in chunk(), returnstat() |
| 72 | for v in gmatch("else elseif end until <eof>", "%S+") do |
| 73 | block_follow[v] = true |
| 74 | end |
| 75 | |
| 76 | local stat_call = {} -- lookup for calls in stat() |
| 77 | for v in gmatch("if while do for repeat function local return break", "%S+") do |
| 78 | stat_call[v] = v.."_stat" |
| 79 | end |
| 80 | |
| 81 | local binopr_left = {} -- binary operators, left priority |
| 82 | local binopr_right = {} -- binary operators, right priority |
| 83 | for op, lt, rt in gmatch([[ |
| 84 | {+ 6 6}{- 6 6}{* 7 7}{/ 7 7}{% 7 7} |
| 85 | {^ 10 9}{.. 5 4} |
| 86 | {~= 3 3}{== 3 3} |
| 87 | {< 3 3}{<= 3 3}{> 3 3}{>= 3 3} |
| 88 | {and 2 2}{or 1 1} |
| 89 | ]], "{(%S+)%s(%d+)%s(%d+)}") do |
| 90 | binopr_left[op] = lt + 0 |
| 91 | binopr_right[op] = rt + 0 |
| 92 | end |
| 93 | |
| 94 | local unopr = { ["not"] = true, ["-"] = true, |
| 95 | ["#"] = true, } -- unary operators |
| 96 | local UNARY_PRIORITY = 8 -- priority for unary operators |
| 97 | |
| 98 | --[[-------------------------------------------------------------------- |
| 99 | -- support functions |
| 100 | ----------------------------------------------------------------------]] |
| 101 | |
| 102 | ---------------------------------------------------------------------- |
| 103 | -- formats error message and throws error (duplicated from llex) |
| 104 | -- * a simplified version, does not report what token was responsible |
| 105 | ---------------------------------------------------------------------- |
| 106 | |
| 107 | local function errorline(s, line) |
| 108 | local e = error or base.error |
| 109 | e(string.format("(source):%d: %s", line or ln, s)) |
| 110 | end |
| 111 | |
| 112 | ---------------------------------------------------------------------- |
| 113 | -- handles incoming token, semantic information pairs |
| 114 | -- * NOTE: 'nextt' is named 'next' originally |
| 115 | ---------------------------------------------------------------------- |
| 116 | |
| 117 | -- reads in next token |
| 118 | local function nextt() |
| 119 | lastln = toklnlist[tpos] |
| 120 | tok, seminfo, ln, xref |
| 121 | = toklist[tpos], seminfolist[tpos], toklnlist[tpos], xreflist[tpos] |
| 122 | tpos = tpos + 1 |
| 123 | end |
| 124 | |
| 125 | -- peek at next token (single lookahead for table constructor) |
| 126 | local function lookahead() |
| 127 | return toklist[tpos] |
| 128 | end |
| 129 | |
| 130 | ---------------------------------------------------------------------- |
| 131 | -- throws a syntax error, or if token expected is not there |
| 132 | ---------------------------------------------------------------------- |
| 133 | |
| 134 | local function syntaxerror(msg) |
| 135 | local tok = tok |
| 136 | if tok ~= "<number>" and tok ~= "<string>" then |
| 137 | if tok == "<name>" then tok = seminfo end |
| 138 | tok = "'"..tok.."'" |
| 139 | end |
| 140 | errorline(msg.." near "..tok) |
| 141 | end |
| 142 | |
| 143 | local function error_expected(token) |
| 144 | syntaxerror("'"..token.."' expected") |
| 145 | end |
| 146 | |
| 147 | ---------------------------------------------------------------------- |
| 148 | -- tests for a token, returns outcome |
| 149 | -- * return value changed to boolean |
| 150 | ---------------------------------------------------------------------- |
| 151 | |
| 152 | local function testnext(c) |
| 153 | if tok == c then nextt(); return true end |
| 154 | end |
| 155 | |
| 156 | ---------------------------------------------------------------------- |
| 157 | -- check for existence of a token, throws error if not found |
| 158 | ---------------------------------------------------------------------- |
| 159 | |
| 160 | local function check(c) |
| 161 | if tok ~= c then error_expected(c) end |
| 162 | end |
| 163 | |
| 164 | ---------------------------------------------------------------------- |
| 165 | -- verify existence of a token, then skip it |
| 166 | ---------------------------------------------------------------------- |
| 167 | |
| 168 | local function checknext(c) |
| 169 | check(c); nextt() |
| 170 | end |
| 171 | |
| 172 | ---------------------------------------------------------------------- |
| 173 | -- throws error if condition not matched |
| 174 | ---------------------------------------------------------------------- |
| 175 | |
| 176 | local function check_condition(c, msg) |
| 177 | if not c then syntaxerror(msg) end |
| 178 | end |
| 179 | |
| 180 | ---------------------------------------------------------------------- |
| 181 | -- verifies token conditions are met or else throw error |
| 182 | ---------------------------------------------------------------------- |
| 183 | |
| 184 | local function check_match(what, who, where) |
| 185 | if not testnext(what) then |
| 186 | if where == ln then |
| 187 | error_expected(what) |
| 188 | else |
| 189 | syntaxerror("'"..what.."' expected (to close '"..who.."' at line "..where..")") |
| 190 | end |
| 191 | end |
| 192 | end |
| 193 | |
| 194 | ---------------------------------------------------------------------- |
| 195 | -- expect that token is a name, return the name |
| 196 | ---------------------------------------------------------------------- |
| 197 | |
| 198 | local function str_checkname() |
| 199 | check("<name>") |
| 200 | local ts = seminfo |
| 201 | nameref = xref |
| 202 | nextt() |
| 203 | return ts |
| 204 | end |
| 205 | |
| 206 | ---------------------------------------------------------------------- |
| 207 | -- adds given string s in string pool, sets e as VK |
| 208 | ---------------------------------------------------------------------- |
| 209 | |
| 210 | local function codestring(e, s) |
| 211 | e.k = "VK" |
| 212 | end |
| 213 | |
| 214 | ---------------------------------------------------------------------- |
| 215 | -- consume a name token, adds it to string pool |
| 216 | ---------------------------------------------------------------------- |
| 217 | |
| 218 | local function checkname(e) |
| 219 | codestring(e, str_checkname()) |
| 220 | end |
| 221 | |
| 222 | --[[-------------------------------------------------------------------- |
| 223 | -- variable (global|local|upvalue) handling |
| 224 | -- * to track locals and globals, we can extend Yueliang's minimal |
| 225 | -- variable management code with little trouble |
| 226 | -- * entry point is singlevar() for variable lookups |
| 227 | -- * lookup tables (bl.locallist) are maintained awkwardly in the basic |
| 228 | -- block data structures, PLUS the function data structure (this is |
| 229 | -- an inelegant hack, since bl is nil for the top level of a function) |
| 230 | ----------------------------------------------------------------------]] |
| 231 | |
| 232 | ---------------------------------------------------------------------- |
| 233 | -- register a local variable, create local variable object, set in |
| 234 | -- to-activate variable list |
| 235 | -- * used in new_localvarliteral(), parlist(), fornum(), forlist(), |
| 236 | -- localfunc(), localstat() |
| 237 | ---------------------------------------------------------------------- |
| 238 | |
| 239 | local function new_localvar(name, special) |
| 240 | local bl = fs.bl |
| 241 | local locallist |
| 242 | -- locate locallist in current block object or function root object |
| 243 | if bl then |
| 244 | locallist = bl.locallist |
| 245 | else |
| 246 | locallist = fs.locallist |
| 247 | end |
| 248 | -- build local variable information object and set localinfo |
| 249 | local id = #localinfo + 1 |
| 250 | localinfo[id] = { -- new local variable object |
| 251 | name = name, -- local variable name |
| 252 | xref = { nameref }, -- xref, first value is declaration |
| 253 | decl = nameref, -- location of declaration, = xref[1] |
| 254 | } |
| 255 | if special or name == "_ENV" then -- "self" must be not be changed |
| 256 | localinfo[id].preserve = true |
| 257 | end |
| 258 | -- this can override a local with the same name in the same scope |
| 259 | -- but first, keep it inactive until it gets activated |
| 260 | local i = #ilocalinfo + 1 |
| 261 | ilocalinfo[i] = id |
| 262 | ilocalrefs[i] = locallist |
| 263 | end |
| 264 | |
| 265 | ---------------------------------------------------------------------- |
| 266 | -- actually activate the variables so that they are visible |
| 267 | -- * remember Lua semantics, e.g. RHS is evaluated first, then LHS |
| 268 | -- * used in parlist(), forbody(), localfunc(), localstat(), body() |
| 269 | ---------------------------------------------------------------------- |
| 270 | |
| 271 | local function adjustlocalvars(nvars) |
| 272 | local sz = #ilocalinfo |
| 273 | -- i goes from left to right, in order of local allocation, because |
| 274 | -- of something like: local a,a,a = 1,2,3 which gives a = 3 |
| 275 | while nvars > 0 do |
| 276 | nvars = nvars - 1 |
| 277 | local i = sz - nvars |
| 278 | local id = ilocalinfo[i] -- local's id |
| 279 | local obj = localinfo[id] |
| 280 | local name = obj.name -- name of local |
| 281 | obj.act = xref -- set activation location |
| 282 | ilocalinfo[i] = nil |
| 283 | local locallist = ilocalrefs[i] -- ref to lookup table to update |
| 284 | ilocalrefs[i] = nil |
| 285 | local existing = locallist[name] -- if existing, remove old first! |
| 286 | if existing then -- do not overlap, set special |
| 287 | obj = localinfo[existing] -- form of rem, as -id |
| 288 | obj.rem = -id |
| 289 | end |
| 290 | locallist[name] = id -- activate, now visible to Lua |
| 291 | end |
| 292 | end |
| 293 | |
| 294 | ---------------------------------------------------------------------- |
| 295 | -- remove (deactivate) variables in current scope (before scope exits) |
| 296 | -- * zap entire locallist tables since we are not allocating registers |
| 297 | -- * used in leaveblock(), close_func() |
| 298 | ---------------------------------------------------------------------- |
| 299 | |
| 300 | local function removevars() |
| 301 | local bl = fs.bl |
| 302 | local locallist |
| 303 | -- locate locallist in current block object or function root object |
| 304 | if bl then |
| 305 | locallist = bl.locallist |
| 306 | else |
| 307 | locallist = fs.locallist |
| 308 | end |
| 309 | -- enumerate the local list at current scope and deactivate 'em |
| 310 | for name, id in base.pairs(locallist) do |
| 311 | local obj = localinfo[id] |
| 312 | obj.rem = xref -- set deactivation location |
| 313 | end |
| 314 | end |
| 315 | |
| 316 | ---------------------------------------------------------------------- |
| 317 | -- creates a new local variable given a name |
| 318 | -- * skips internal locals (those starting with '('), so internal |
| 319 | -- locals never needs a corresponding adjustlocalvars() call |
| 320 | -- * special is true for "self" which must not be optimized |
| 321 | -- * used in fornum(), forlist(), parlist(), body() |
| 322 | ---------------------------------------------------------------------- |
| 323 | |
| 324 | local function new_localvarliteral(name, special) |
| 325 | if string.sub(name, 1, 1) == "(" then -- can skip internal locals |
| 326 | return |
| 327 | end |
| 328 | new_localvar(name, special) |
| 329 | end |
| 330 | |
| 331 | ---------------------------------------------------------------------- |
| 332 | -- search the local variable namespace of the given fs for a match |
| 333 | -- * returns localinfo index |
| 334 | -- * used only in singlevaraux() |
| 335 | ---------------------------------------------------------------------- |
| 336 | |
| 337 | local function searchvar(fs, n) |
| 338 | local bl = fs.bl |
| 339 | local locallist |
| 340 | if bl then |
| 341 | locallist = bl.locallist |
| 342 | while locallist do |
| 343 | if locallist[n] then return locallist[n] end -- found |
| 344 | bl = bl.prev |
| 345 | locallist = bl and bl.locallist |
| 346 | end |
| 347 | end |
| 348 | locallist = fs.locallist |
| 349 | return locallist[n] or -1 -- found or not found (-1) |
| 350 | end |
| 351 | |
| 352 | ---------------------------------------------------------------------- |
| 353 | -- handle locals, globals and upvalues and related processing |
| 354 | -- * search mechanism is recursive, calls itself to search parents |
| 355 | -- * used only in singlevar() |
| 356 | ---------------------------------------------------------------------- |
| 357 | |
| 358 | local function singlevaraux(fs, n, var) |
| 359 | if fs == nil then -- no more levels? |
| 360 | var.k = "VGLOBAL" -- default is global variable |
| 361 | return "VGLOBAL" |
| 362 | else |
| 363 | local v = searchvar(fs, n) -- look up at current level |
| 364 | if v >= 0 then |
| 365 | var.k = "VLOCAL" |
| 366 | var.id = v |
| 367 | -- codegen may need to deal with upvalue here |
| 368 | return "VLOCAL" |
| 369 | else -- not found at current level; try upper one |
| 370 | if singlevaraux(fs.prev, n, var) == "VGLOBAL" then |
| 371 | return "VGLOBAL" |
| 372 | end |
| 373 | -- else was LOCAL or UPVAL, handle here |
| 374 | var.k = "VUPVAL" -- upvalue in this level |
| 375 | return "VUPVAL" |
| 376 | end--if v |
| 377 | end--if fs |
| 378 | end |
| 379 | |
| 380 | ---------------------------------------------------------------------- |
| 381 | -- consume a name token, creates a variable (global|local|upvalue) |
| 382 | -- * used in prefixexp(), funcname() |
| 383 | ---------------------------------------------------------------------- |
| 384 | |
| 385 | local function singlevar(v) |
| 386 | local name = str_checkname() |
| 387 | singlevaraux(fs, name, v) |
| 388 | ------------------------------------------------------------------ |
| 389 | -- variable tracking |
| 390 | ------------------------------------------------------------------ |
| 391 | if v.k == "VGLOBAL" then |
| 392 | -- if global being accessed, keep track of it by creating an object |
| 393 | local id = globallookup[name] |
| 394 | if not id then |
| 395 | id = #globalinfo + 1 |
| 396 | globalinfo[id] = { -- new global variable object |
| 397 | name = name, -- global variable name |
| 398 | xref = { nameref }, -- xref, first value is declaration |
| 399 | } |
| 400 | globallookup[name] = id -- remember it |
| 401 | else |
| 402 | local obj = globalinfo[id].xref |
| 403 | obj[#obj + 1] = nameref -- add xref |
| 404 | end |
| 405 | else |
| 406 | -- local/upvalue is being accessed, keep track of it |
| 407 | local id = v.id |
| 408 | local obj = localinfo[id].xref |
| 409 | obj[#obj + 1] = nameref -- add xref |
| 410 | end |
| 411 | end |
| 412 | |
| 413 | --[[-------------------------------------------------------------------- |
| 414 | -- state management functions with open/close pairs |
| 415 | ----------------------------------------------------------------------]] |
| 416 | |
| 417 | ---------------------------------------------------------------------- |
| 418 | -- enters a code unit, initializes elements |
| 419 | ---------------------------------------------------------------------- |
| 420 | |
| 421 | local function enterblock(isbreakable) |
| 422 | local bl = {} -- per-block state |
| 423 | bl.isbreakable = isbreakable |
| 424 | bl.prev = fs.bl |
| 425 | bl.locallist = {} |
| 426 | fs.bl = bl |
| 427 | end |
| 428 | |
| 429 | ---------------------------------------------------------------------- |
| 430 | -- leaves a code unit, close any upvalues |
| 431 | ---------------------------------------------------------------------- |
| 432 | |
| 433 | local function leaveblock() |
| 434 | local bl = fs.bl |
| 435 | removevars() |
| 436 | fs.bl = bl.prev |
| 437 | end |
| 438 | |
| 439 | ---------------------------------------------------------------------- |
| 440 | -- opening of a function |
| 441 | -- * top_fs is only for anchoring the top fs, so that parser() can |
| 442 | -- return it to the caller function along with useful output |
| 443 | -- * used in parser() and body() |
| 444 | ---------------------------------------------------------------------- |
| 445 | |
| 446 | local function open_func() |
| 447 | local new_fs -- per-function state |
| 448 | if not fs then -- top_fs is created early |
| 449 | new_fs = top_fs |
| 450 | else |
| 451 | new_fs = {} |
| 452 | end |
| 453 | new_fs.prev = fs -- linked list of function states |
| 454 | new_fs.bl = nil |
| 455 | new_fs.locallist = {} |
| 456 | fs = new_fs |
| 457 | end |
| 458 | |
| 459 | ---------------------------------------------------------------------- |
| 460 | -- closing of a function |
| 461 | -- * used in parser() and body() |
| 462 | ---------------------------------------------------------------------- |
| 463 | |
| 464 | local function close_func() |
| 465 | removevars() |
| 466 | fs = fs.prev |
| 467 | end |
| 468 | |
| 469 | --[[-------------------------------------------------------------------- |
| 470 | -- other parsing functions |
| 471 | -- * for table constructor, parameter list, argument list |
| 472 | ----------------------------------------------------------------------]] |
| 473 | |
| 474 | ---------------------------------------------------------------------- |
| 475 | -- parse a function name suffix, for function call specifications |
| 476 | -- * used in primaryexp(), funcname() |
| 477 | ---------------------------------------------------------------------- |
| 478 | |
| 479 | local function field(v) |
| 480 | -- field -> ['.' | ':'] NAME |
| 481 | local key = {} |
| 482 | nextt() -- skip the dot or colon |
| 483 | checkname(key) |
| 484 | v.k = "VINDEXED" |
| 485 | end |
| 486 | |
| 487 | ---------------------------------------------------------------------- |
| 488 | -- parse a table indexing suffix, for constructors, expressions |
| 489 | -- * used in recfield(), primaryexp() |
| 490 | ---------------------------------------------------------------------- |
| 491 | |
| 492 | local function yindex(v) |
| 493 | -- index -> '[' expr ']' |
| 494 | nextt() -- skip the '[' |
| 495 | expr(v) |
| 496 | checknext("]") |
| 497 | end |
| 498 | |
| 499 | ---------------------------------------------------------------------- |
| 500 | -- parse a table record (hash) field |
| 501 | -- * used in constructor() |
| 502 | ---------------------------------------------------------------------- |
| 503 | |
| 504 | local function recfield(cc) |
| 505 | -- recfield -> (NAME | '['exp1']') = exp1 |
| 506 | local key, val = {}, {} |
| 507 | if tok == "<name>" then |
| 508 | checkname(key) |
| 509 | else-- tok == '[' |
| 510 | yindex(key) |
| 511 | end |
| 512 | checknext("=") |
| 513 | expr(val) |
| 514 | end |
| 515 | |
| 516 | ---------------------------------------------------------------------- |
| 517 | -- emit a set list instruction if enough elements (LFIELDS_PER_FLUSH) |
| 518 | -- * note: retained in this skeleton because it modifies cc.v.k |
| 519 | -- * used in constructor() |
| 520 | ---------------------------------------------------------------------- |
| 521 | |
| 522 | local function closelistfield(cc) |
| 523 | if cc.v.k == "VVOID" then return end -- there is no list item |
| 524 | cc.v.k = "VVOID" |
| 525 | end |
| 526 | |
| 527 | ---------------------------------------------------------------------- |
| 528 | -- parse a table list (array) field |
| 529 | -- * used in constructor() |
| 530 | ---------------------------------------------------------------------- |
| 531 | |
| 532 | local function listfield(cc) |
| 533 | expr(cc.v) |
| 534 | end |
| 535 | |
| 536 | ---------------------------------------------------------------------- |
| 537 | -- parse a table constructor |
| 538 | -- * used in funcargs(), simpleexp() |
| 539 | ---------------------------------------------------------------------- |
| 540 | |
| 541 | local function constructor(t) |
| 542 | -- constructor -> '{' [ field { fieldsep field } [ fieldsep ] ] '}' |
| 543 | -- field -> recfield | listfield |
| 544 | -- fieldsep -> ',' | ';' |
| 545 | local line = ln |
| 546 | local cc = {} |
| 547 | cc.v = {} |
| 548 | cc.t = t |
| 549 | t.k = "VRELOCABLE" |
| 550 | cc.v.k = "VVOID" |
| 551 | checknext("{") |
| 552 | repeat |
| 553 | if tok == "}" then break end |
| 554 | -- closelistfield(cc) here |
| 555 | local c = tok |
| 556 | if c == "<name>" then -- may be listfields or recfields |
| 557 | if lookahead() ~= "=" then -- look ahead: expression? |
| 558 | listfield(cc) |
| 559 | else |
| 560 | recfield(cc) |
| 561 | end |
| 562 | elseif c == "[" then -- constructor_item -> recfield |
| 563 | recfield(cc) |
| 564 | else -- constructor_part -> listfield |
| 565 | listfield(cc) |
| 566 | end |
| 567 | until not testnext(",") and not testnext(";") |
| 568 | check_match("}", "{", line) |
| 569 | -- lastlistfield(cc) here |
| 570 | end |
| 571 | |
| 572 | ---------------------------------------------------------------------- |
| 573 | -- parse the arguments (parameters) of a function declaration |
| 574 | -- * used in body() |
| 575 | ---------------------------------------------------------------------- |
| 576 | |
| 577 | local function parlist() |
| 578 | -- parlist -> [ param { ',' param } ] |
| 579 | local nparams = 0 |
| 580 | if tok ~= ")" then -- is 'parlist' not empty? |
| 581 | repeat |
| 582 | local c = tok |
| 583 | if c == "<name>" then -- param -> NAME |
| 584 | new_localvar(str_checkname()) |
| 585 | nparams = nparams + 1 |
| 586 | elseif c == "..." then |
| 587 | nextt() |
| 588 | fs.is_vararg = true |
| 589 | else |
| 590 | syntaxerror("<name> or '...' expected") |
| 591 | end |
| 592 | until fs.is_vararg or not testnext(",") |
| 593 | end--if |
| 594 | adjustlocalvars(nparams) |
| 595 | end |
| 596 | |
| 597 | ---------------------------------------------------------------------- |
| 598 | -- parse the parameters of a function call |
| 599 | -- * contrast with parlist(), used in function declarations |
| 600 | -- * used in primaryexp() |
| 601 | ---------------------------------------------------------------------- |
| 602 | |
| 603 | local function funcargs(f) |
| 604 | local args = {} |
| 605 | local line = ln |
| 606 | local c = tok |
| 607 | if c == "(" then -- funcargs -> '(' [ explist1 ] ')' |
| 608 | if line ~= lastln then |
| 609 | syntaxerror("ambiguous syntax (function call x new statement)") |
| 610 | end |
| 611 | nextt() |
| 612 | if tok == ")" then -- arg list is empty? |
| 613 | args.k = "VVOID" |
| 614 | else |
| 615 | explist1(args) |
| 616 | end |
| 617 | check_match(")", "(", line) |
| 618 | elseif c == "{" then -- funcargs -> constructor |
| 619 | constructor(args) |
| 620 | elseif c == "<string>" then -- funcargs -> STRING |
| 621 | codestring(args, seminfo) |
| 622 | nextt() -- must use 'seminfo' before 'next' |
| 623 | else |
| 624 | syntaxerror("function arguments expected") |
| 625 | return |
| 626 | end--if c |
| 627 | f.k = "VCALL" |
| 628 | end |
| 629 | |
| 630 | --[[-------------------------------------------------------------------- |
| 631 | -- mostly expression functions |
| 632 | ----------------------------------------------------------------------]] |
| 633 | |
| 634 | ---------------------------------------------------------------------- |
| 635 | -- parses an expression in parentheses or a single variable |
| 636 | -- * used in primaryexp() |
| 637 | ---------------------------------------------------------------------- |
| 638 | |
| 639 | local function prefixexp(v) |
| 640 | -- prefixexp -> NAME | '(' expr ')' |
| 641 | local c = tok |
| 642 | if c == "(" then |
| 643 | local line = ln |
| 644 | nextt() |
| 645 | expr(v) |
| 646 | check_match(")", "(", line) |
| 647 | elseif c == "<name>" then |
| 648 | singlevar(v) |
| 649 | else |
| 650 | syntaxerror("unexpected symbol") |
| 651 | end--if c |
| 652 | end |
| 653 | |
| 654 | ---------------------------------------------------------------------- |
| 655 | -- parses a prefixexp (an expression in parentheses or a single |
| 656 | -- variable) or a function call specification |
| 657 | -- * used in simpleexp(), assignment(), expr_stat() |
| 658 | ---------------------------------------------------------------------- |
| 659 | |
| 660 | local function primaryexp(v) |
| 661 | -- primaryexp -> |
| 662 | -- prefixexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } |
| 663 | prefixexp(v) |
| 664 | while true do |
| 665 | local c = tok |
| 666 | if c == "." then -- field |
| 667 | field(v) |
| 668 | elseif c == "[" then -- '[' exp1 ']' |
| 669 | local key = {} |
| 670 | yindex(key) |
| 671 | elseif c == ":" then -- ':' NAME funcargs |
| 672 | local key = {} |
| 673 | nextt() |
| 674 | checkname(key) |
| 675 | funcargs(v) |
| 676 | elseif c == "(" or c == "<string>" or c == "{" then -- funcargs |
| 677 | funcargs(v) |
| 678 | else |
| 679 | return |
| 680 | end--if c |
| 681 | end--while |
| 682 | end |
| 683 | |
| 684 | ---------------------------------------------------------------------- |
| 685 | -- parses general expression types, constants handled here |
| 686 | -- * used in subexpr() |
| 687 | ---------------------------------------------------------------------- |
| 688 | |
| 689 | local function simpleexp(v) |
| 690 | -- simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | ... | |
| 691 | -- constructor | FUNCTION body | primaryexp |
| 692 | local c = tok |
| 693 | if c == "<number>" then |
| 694 | v.k = "VKNUM" |
| 695 | elseif c == "<string>" then |
| 696 | codestring(v, seminfo) |
| 697 | elseif c == "nil" then |
| 698 | v.k = "VNIL" |
| 699 | elseif c == "true" then |
| 700 | v.k = "VTRUE" |
| 701 | elseif c == "false" then |
| 702 | v.k = "VFALSE" |
| 703 | elseif c == "..." then -- vararg |
| 704 | check_condition(fs.is_vararg == true, |
| 705 | "cannot use '...' outside a vararg function"); |
| 706 | v.k = "VVARARG" |
| 707 | elseif c == "{" then -- constructor |
| 708 | constructor(v) |
| 709 | return |
| 710 | elseif c == "function" then |
| 711 | nextt() |
| 712 | body(v, false, ln) |
| 713 | return |
| 714 | else |
| 715 | primaryexp(v) |
| 716 | return |
| 717 | end--if c |
| 718 | nextt() |
| 719 | end |
| 720 | |
| 721 | ------------------------------------------------------------------------ |
| 722 | -- Parse subexpressions. Includes handling of unary operators and binary |
| 723 | -- operators. A subexpr is given the rhs priority level of the operator |
| 724 | -- immediately left of it, if any (limit is -1 if none,) and if a binop |
| 725 | -- is found, limit is compared with the lhs priority level of the binop |
| 726 | -- in order to determine which executes first. |
| 727 | -- * recursively called |
| 728 | -- * used in expr() |
| 729 | ------------------------------------------------------------------------ |
| 730 | |
| 731 | local function subexpr(v, limit) |
| 732 | -- subexpr -> (simpleexp | unop subexpr) { binop subexpr } |
| 733 | -- * where 'binop' is any binary operator with a priority |
| 734 | -- higher than 'limit' |
| 735 | local op = tok |
| 736 | local uop = unopr[op] |
| 737 | if uop then |
| 738 | nextt() |
| 739 | subexpr(v, UNARY_PRIORITY) |
| 740 | else |
| 741 | simpleexp(v) |
| 742 | end |
| 743 | -- expand while operators have priorities higher than 'limit' |
| 744 | op = tok |
| 745 | local binop = binopr_left[op] |
| 746 | while binop and binop > limit do |
| 747 | local v2 = {} |
| 748 | nextt() |
| 749 | -- read sub-expression with higher priority |
| 750 | local nextop = subexpr(v2, binopr_right[op]) |
| 751 | op = nextop |
| 752 | binop = binopr_left[op] |
| 753 | end |
| 754 | return op -- return first untreated operator |
| 755 | end |
| 756 | |
| 757 | ---------------------------------------------------------------------- |
| 758 | -- Expression parsing starts here. Function subexpr is entered with the |
| 759 | -- left operator (which is non-existent) priority of -1, which is lower |
| 760 | -- than all actual operators. Expr information is returned in parm v. |
| 761 | -- * used in cond(), explist1(), index(), recfield(), listfield(), |
| 762 | -- prefixexp(), while_stat(), exp1() |
| 763 | ---------------------------------------------------------------------- |
| 764 | |
| 765 | -- this is a forward-referenced local |
| 766 | function expr(v) |
| 767 | -- expr -> subexpr |
| 768 | subexpr(v, 0) |
| 769 | end |
| 770 | |
| 771 | --[[-------------------------------------------------------------------- |
| 772 | -- third level parsing functions |
| 773 | ----------------------------------------------------------------------]] |
| 774 | |
| 775 | ------------------------------------------------------------------------ |
| 776 | -- parse a variable assignment sequence |
| 777 | -- * recursively called |
| 778 | -- * used in expr_stat() |
| 779 | ------------------------------------------------------------------------ |
| 780 | |
| 781 | local function assignment(v) |
| 782 | local e = {} |
| 783 | local c = v.v.k |
| 784 | check_condition(c == "VLOCAL" or c == "VUPVAL" or c == "VGLOBAL" |
| 785 | or c == "VINDEXED", "syntax error") |
| 786 | if testnext(",") then -- assignment -> ',' primaryexp assignment |
| 787 | local nv = {} -- expdesc |
| 788 | nv.v = {} |
| 789 | primaryexp(nv.v) |
| 790 | -- lparser.c deals with some register usage conflict here |
| 791 | assignment(nv) |
| 792 | else -- assignment -> '=' explist1 |
| 793 | checknext("=") |
| 794 | explist1(e) |
| 795 | return -- avoid default |
| 796 | end |
| 797 | e.k = "VNONRELOC" |
| 798 | end |
| 799 | |
| 800 | ---------------------------------------------------------------------- |
| 801 | -- parse a for loop body for both versions of the for loop |
| 802 | -- * used in fornum(), forlist() |
| 803 | ---------------------------------------------------------------------- |
| 804 | |
| 805 | local function forbody(nvars, isnum) |
| 806 | -- forbody -> DO block |
| 807 | checknext("do") |
| 808 | enterblock(false) -- scope for declared variables |
| 809 | adjustlocalvars(nvars) |
| 810 | block() |
| 811 | leaveblock() -- end of scope for declared variables |
| 812 | end |
| 813 | |
| 814 | ---------------------------------------------------------------------- |
| 815 | -- parse a numerical for loop, calls forbody() |
| 816 | -- * used in for_stat() |
| 817 | ---------------------------------------------------------------------- |
| 818 | |
| 819 | local function fornum(varname) |
| 820 | -- fornum -> NAME = exp1, exp1 [, exp1] DO body |
| 821 | local line = line |
| 822 | new_localvarliteral("(for index)") |
| 823 | new_localvarliteral("(for limit)") |
| 824 | new_localvarliteral("(for step)") |
| 825 | new_localvar(varname) |
| 826 | checknext("=") |
| 827 | exp1() -- initial value |
| 828 | checknext(",") |
| 829 | exp1() -- limit |
| 830 | if testnext(",") then |
| 831 | exp1() -- optional step |
| 832 | else |
| 833 | -- default step = 1 |
| 834 | end |
| 835 | forbody(1, true) |
| 836 | end |
| 837 | |
| 838 | ---------------------------------------------------------------------- |
| 839 | -- parse a generic for loop, calls forbody() |
| 840 | -- * used in for_stat() |
| 841 | ---------------------------------------------------------------------- |
| 842 | |
| 843 | local function forlist(indexname) |
| 844 | -- forlist -> NAME {, NAME} IN explist1 DO body |
| 845 | local e = {} |
| 846 | -- create control variables |
| 847 | new_localvarliteral("(for generator)") |
| 848 | new_localvarliteral("(for state)") |
| 849 | new_localvarliteral("(for control)") |
| 850 | -- create declared variables |
| 851 | new_localvar(indexname) |
| 852 | local nvars = 1 |
| 853 | while testnext(",") do |
| 854 | new_localvar(str_checkname()) |
| 855 | nvars = nvars + 1 |
| 856 | end |
| 857 | checknext("in") |
| 858 | local line = line |
| 859 | explist1(e) |
| 860 | forbody(nvars, false) |
| 861 | end |
| 862 | |
| 863 | ---------------------------------------------------------------------- |
| 864 | -- parse a function name specification |
| 865 | -- * used in func_stat() |
| 866 | ---------------------------------------------------------------------- |
| 867 | |
| 868 | local function funcname(v) |
| 869 | -- funcname -> NAME {field} [':' NAME] |
| 870 | local needself = false |
| 871 | singlevar(v) |
| 872 | while tok == "." do |
| 873 | field(v) |
| 874 | end |
| 875 | if tok == ":" then |
| 876 | needself = true |
| 877 | field(v) |
| 878 | end |
| 879 | return needself |
| 880 | end |
| 881 | |
| 882 | ---------------------------------------------------------------------- |
| 883 | -- parse the single expressions needed in numerical for loops |
| 884 | -- * used in fornum() |
| 885 | ---------------------------------------------------------------------- |
| 886 | |
| 887 | -- this is a forward-referenced local |
| 888 | function exp1() |
| 889 | -- exp1 -> expr |
| 890 | local e = {} |
| 891 | expr(e) |
| 892 | end |
| 893 | |
| 894 | ---------------------------------------------------------------------- |
| 895 | -- parse condition in a repeat statement or an if control structure |
| 896 | -- * used in repeat_stat(), test_then_block() |
| 897 | ---------------------------------------------------------------------- |
| 898 | |
| 899 | local function cond() |
| 900 | -- cond -> expr |
| 901 | local v = {} |
| 902 | expr(v) -- read condition |
| 903 | end |
| 904 | |
| 905 | ---------------------------------------------------------------------- |
| 906 | -- parse part of an if control structure, including the condition |
| 907 | -- * used in if_stat() |
| 908 | ---------------------------------------------------------------------- |
| 909 | |
| 910 | local function test_then_block() |
| 911 | -- test_then_block -> [IF | ELSEIF] cond THEN block |
| 912 | nextt() -- skip IF or ELSEIF |
| 913 | cond() |
| 914 | checknext("then") |
| 915 | block() -- 'then' part |
| 916 | end |
| 917 | |
| 918 | ---------------------------------------------------------------------- |
| 919 | -- parse a local function statement |
| 920 | -- * used in local_stat() |
| 921 | ---------------------------------------------------------------------- |
| 922 | |
| 923 | local function localfunc() |
| 924 | -- localfunc -> NAME body |
| 925 | local v, b = {} |
| 926 | new_localvar(str_checkname()) |
| 927 | v.k = "VLOCAL" |
| 928 | adjustlocalvars(1) |
| 929 | body(b, false, ln) |
| 930 | end |
| 931 | |
| 932 | ---------------------------------------------------------------------- |
| 933 | -- parse a local variable declaration statement |
| 934 | -- * used in local_stat() |
| 935 | ---------------------------------------------------------------------- |
| 936 | |
| 937 | local function localstat() |
| 938 | -- localstat -> NAME {',' NAME} ['=' explist1] |
| 939 | local nvars = 0 |
| 940 | local e = {} |
| 941 | repeat |
| 942 | new_localvar(str_checkname()) |
| 943 | nvars = nvars + 1 |
| 944 | until not testnext(",") |
| 945 | if testnext("=") then |
| 946 | explist1(e) |
| 947 | else |
| 948 | e.k = "VVOID" |
| 949 | end |
| 950 | adjustlocalvars(nvars) |
| 951 | end |
| 952 | |
| 953 | ---------------------------------------------------------------------- |
| 954 | -- parse a list of comma-separated expressions |
| 955 | -- * used in return_stat(), localstat(), funcargs(), assignment(), |
| 956 | -- forlist() |
| 957 | ---------------------------------------------------------------------- |
| 958 | |
| 959 | -- this is a forward-referenced local |
| 960 | function explist1(e) |
| 961 | -- explist1 -> expr { ',' expr } |
| 962 | expr(e) |
| 963 | while testnext(",") do |
| 964 | expr(e) |
| 965 | end |
| 966 | end |
| 967 | |
| 968 | ---------------------------------------------------------------------- |
| 969 | -- parse function declaration body |
| 970 | -- * used in simpleexp(), localfunc(), func_stat() |
| 971 | ---------------------------------------------------------------------- |
| 972 | |
| 973 | -- this is a forward-referenced local |
| 974 | function body(e, needself, line) |
| 975 | -- body -> '(' parlist ')' chunk END |
| 976 | open_func() |
| 977 | checknext("(") |
| 978 | if needself then |
| 979 | new_localvarliteral("self", true) |
| 980 | adjustlocalvars(1) |
| 981 | end |
| 982 | parlist() |
| 983 | checknext(")") |
| 984 | chunk() |
| 985 | check_match("end", "function", line) |
| 986 | close_func() |
| 987 | end |
| 988 | |
| 989 | ---------------------------------------------------------------------- |
| 990 | -- parse a code block or unit |
| 991 | -- * used in do_stat(), while_stat(), forbody(), test_then_block(), |
| 992 | -- if_stat() |
| 993 | ---------------------------------------------------------------------- |
| 994 | |
| 995 | -- this is a forward-referenced local |
| 996 | function block() |
| 997 | -- block -> chunk |
| 998 | enterblock(false) |
| 999 | chunk() |
| 1000 | leaveblock() |
| 1001 | end |
| 1002 | |
| 1003 | --[[-------------------------------------------------------------------- |
| 1004 | -- second level parsing functions, all with '_stat' suffix |
| 1005 | -- * since they are called via a table lookup, they cannot be local |
| 1006 | -- functions (a lookup table of local functions might be smaller...) |
| 1007 | -- * stat() -> *_stat() |
| 1008 | ----------------------------------------------------------------------]] |
| 1009 | |
| 1010 | ---------------------------------------------------------------------- |
| 1011 | -- initial parsing for a for loop, calls fornum() or forlist() |
| 1012 | -- * removed 'line' parameter (used to set debug information only) |
| 1013 | -- * used in stat() |
| 1014 | ---------------------------------------------------------------------- |
| 1015 | |
| 1016 | function for_stat() |
| 1017 | -- stat -> for_stat -> FOR (fornum | forlist) END |
| 1018 | local line = line |
| 1019 | enterblock(true) -- scope for loop and control variables |
| 1020 | nextt() -- skip 'for' |
| 1021 | local varname = str_checkname() -- first variable name |
| 1022 | local c = tok |
| 1023 | if c == "=" then |
| 1024 | fornum(varname) |
| 1025 | elseif c == "," or c == "in" then |
| 1026 | forlist(varname) |
| 1027 | else |
| 1028 | syntaxerror("'=' or 'in' expected") |
| 1029 | end |
| 1030 | check_match("end", "for", line) |
| 1031 | leaveblock() -- loop scope (`break' jumps to this point) |
| 1032 | end |
| 1033 | |
| 1034 | ---------------------------------------------------------------------- |
| 1035 | -- parse a while-do control structure, body processed by block() |
| 1036 | -- * used in stat() |
| 1037 | ---------------------------------------------------------------------- |
| 1038 | |
| 1039 | function while_stat() |
| 1040 | -- stat -> while_stat -> WHILE cond DO block END |
| 1041 | local line = line |
| 1042 | nextt() -- skip WHILE |
| 1043 | cond() -- parse condition |
| 1044 | enterblock(true) |
| 1045 | checknext("do") |
| 1046 | block() |
| 1047 | check_match("end", "while", line) |
| 1048 | leaveblock() |
| 1049 | end |
| 1050 | |
| 1051 | ---------------------------------------------------------------------- |
| 1052 | -- parse a repeat-until control structure, body parsed by chunk() |
| 1053 | -- * originally, repeatstat() calls breakstat() too if there is an |
| 1054 | -- upvalue in the scope block; nothing is actually lexed, it is |
| 1055 | -- actually the common code in breakstat() for closing of upvalues |
| 1056 | -- * used in stat() |
| 1057 | ---------------------------------------------------------------------- |
| 1058 | |
| 1059 | function repeat_stat() |
| 1060 | -- stat -> repeat_stat -> REPEAT block UNTIL cond |
| 1061 | local line = line |
| 1062 | enterblock(true) -- loop block |
| 1063 | enterblock(false) -- scope block |
| 1064 | nextt() -- skip REPEAT |
| 1065 | chunk() |
| 1066 | check_match("until", "repeat", line) |
| 1067 | cond() |
| 1068 | -- close upvalues at scope level below |
| 1069 | leaveblock() -- finish scope |
| 1070 | leaveblock() -- finish loop |
| 1071 | end |
| 1072 | |
| 1073 | ---------------------------------------------------------------------- |
| 1074 | -- parse an if control structure |
| 1075 | -- * used in stat() |
| 1076 | ---------------------------------------------------------------------- |
| 1077 | |
| 1078 | function if_stat() |
| 1079 | -- stat -> if_stat -> IF cond THEN block |
| 1080 | -- {ELSEIF cond THEN block} [ELSE block] END |
| 1081 | local line = line |
| 1082 | local v = {} |
| 1083 | test_then_block() -- IF cond THEN block |
| 1084 | while tok == "elseif" do |
| 1085 | test_then_block() -- ELSEIF cond THEN block |
| 1086 | end |
| 1087 | if tok == "else" then |
| 1088 | nextt() -- skip ELSE |
| 1089 | block() -- 'else' part |
| 1090 | end |
| 1091 | check_match("end", "if", line) |
| 1092 | end |
| 1093 | |
| 1094 | ---------------------------------------------------------------------- |
| 1095 | -- parse a return statement |
| 1096 | -- * used in stat() |
| 1097 | ---------------------------------------------------------------------- |
| 1098 | |
| 1099 | function return_stat() |
| 1100 | -- stat -> return_stat -> RETURN explist |
| 1101 | local e = {} |
| 1102 | nextt() -- skip RETURN |
| 1103 | local c = tok |
| 1104 | if block_follow[c] or c == ";" then |
| 1105 | -- return no values |
| 1106 | else |
| 1107 | explist1(e) -- optional return values |
| 1108 | end |
| 1109 | end |
| 1110 | |
| 1111 | ---------------------------------------------------------------------- |
| 1112 | -- parse a break statement |
| 1113 | -- * used in stat() |
| 1114 | ---------------------------------------------------------------------- |
| 1115 | |
| 1116 | function break_stat() |
| 1117 | -- stat -> break_stat -> BREAK |
| 1118 | local bl = fs.bl |
| 1119 | nextt() -- skip BREAK |
| 1120 | while bl and not bl.isbreakable do -- find a breakable block |
| 1121 | bl = bl.prev |
| 1122 | end |
| 1123 | if not bl then |
| 1124 | syntaxerror("no loop to break") |
| 1125 | end |
| 1126 | end |
| 1127 | |
| 1128 | ---------------------------------------------------------------------- |
| 1129 | -- parse a function call with no returns or an assignment statement |
| 1130 | -- * the struct with .prev is used for name searching in lparse.c, |
| 1131 | -- so it is retained for now; present in assignment() also |
| 1132 | -- * used in stat() |
| 1133 | ---------------------------------------------------------------------- |
| 1134 | |
| 1135 | function expr_stat() |
| 1136 | -- stat -> expr_stat -> func | assignment |
| 1137 | local v = {} |
| 1138 | v.v = {} |
| 1139 | primaryexp(v.v) |
| 1140 | if v.v.k == "VCALL" then -- stat -> func |
| 1141 | -- call statement uses no results |
| 1142 | else -- stat -> assignment |
| 1143 | v.prev = nil |
| 1144 | assignment(v) |
| 1145 | end |
| 1146 | end |
| 1147 | |
| 1148 | ---------------------------------------------------------------------- |
| 1149 | -- parse a function statement |
| 1150 | -- * used in stat() |
| 1151 | ---------------------------------------------------------------------- |
| 1152 | |
| 1153 | function function_stat() |
| 1154 | -- stat -> function_stat -> FUNCTION funcname body |
| 1155 | local line = line |
| 1156 | local v, b = {}, {} |
| 1157 | nextt() -- skip FUNCTION |
| 1158 | local needself = funcname(v) |
| 1159 | body(b, needself, line) |
| 1160 | end |
| 1161 | |
| 1162 | ---------------------------------------------------------------------- |
| 1163 | -- parse a simple block enclosed by a DO..END pair |
| 1164 | -- * used in stat() |
| 1165 | ---------------------------------------------------------------------- |
| 1166 | |
| 1167 | function do_stat() |
| 1168 | -- stat -> do_stat -> DO block END |
| 1169 | local line = line |
| 1170 | nextt() -- skip DO |
| 1171 | block() |
| 1172 | check_match("end", "do", line) |
| 1173 | end |
| 1174 | |
| 1175 | ---------------------------------------------------------------------- |
| 1176 | -- parse a statement starting with LOCAL |
| 1177 | -- * used in stat() |
| 1178 | ---------------------------------------------------------------------- |
| 1179 | |
| 1180 | function local_stat() |
| 1181 | -- stat -> local_stat -> LOCAL FUNCTION localfunc |
| 1182 | -- -> LOCAL localstat |
| 1183 | nextt() -- skip LOCAL |
| 1184 | if testnext("function") then -- local function? |
| 1185 | localfunc() |
| 1186 | else |
| 1187 | localstat() |
| 1188 | end |
| 1189 | end |
| 1190 | |
| 1191 | --[[-------------------------------------------------------------------- |
| 1192 | -- main functions, top level parsing functions |
| 1193 | -- * accessible functions are: init(lexer), parser() |
| 1194 | -- * [entry] -> parser() -> chunk() -> stat() |
| 1195 | ----------------------------------------------------------------------]] |
| 1196 | |
| 1197 | ---------------------------------------------------------------------- |
| 1198 | -- initial parsing for statements, calls '_stat' suffixed functions |
| 1199 | -- * used in chunk() |
| 1200 | ---------------------------------------------------------------------- |
| 1201 | |
| 1202 | local function stat() |
| 1203 | -- stat -> if_stat while_stat do_stat for_stat repeat_stat |
| 1204 | -- function_stat local_stat return_stat break_stat |
| 1205 | -- expr_stat |
| 1206 | line = ln -- may be needed for error messages |
| 1207 | local c = tok |
| 1208 | local fn = stat_call[c] |
| 1209 | -- handles: if while do for repeat function local return break |
| 1210 | if fn then |
| 1211 | lparser[fn]() |
| 1212 | -- return or break must be last statement |
| 1213 | if c == "return" or c == "break" then return true end |
| 1214 | else |
| 1215 | expr_stat() |
| 1216 | end |
| 1217 | return false |
| 1218 | end |
| 1219 | |
| 1220 | ---------------------------------------------------------------------- |
| 1221 | -- parse a chunk, which consists of a bunch of statements |
| 1222 | -- * used in parser(), body(), block(), repeat_stat() |
| 1223 | ---------------------------------------------------------------------- |
| 1224 | |
| 1225 | -- this is a forward-referenced local |
| 1226 | function chunk() |
| 1227 | -- chunk -> { stat [';'] } |
| 1228 | local islast = false |
| 1229 | while not islast and not block_follow[tok] do |
| 1230 | islast = stat() |
| 1231 | testnext(";") |
| 1232 | end |
| 1233 | end |
| 1234 | |
| 1235 | ---------------------------------------------------------------------- |
| 1236 | -- performs parsing, returns parsed data structure |
| 1237 | ---------------------------------------------------------------------- |
| 1238 | |
| 1239 | function parser() |
| 1240 | open_func() |
| 1241 | fs.is_vararg = true -- main func. is always vararg |
| 1242 | nextt() -- read first token |
| 1243 | chunk() |
| 1244 | check("<eof>") |
| 1245 | close_func() |
| 1246 | return globalinfo, localinfo |
| 1247 | end |
| 1248 | |
| 1249 | ---------------------------------------------------------------------- |
| 1250 | -- initialization function |
| 1251 | ---------------------------------------------------------------------- |
| 1252 | |
| 1253 | function init(tokorig, seminfoorig, toklnorig) |
| 1254 | tpos = 1 -- token position |
| 1255 | top_fs = {} -- reset top level function state |
| 1256 | ------------------------------------------------------------------ |
| 1257 | -- set up grammar-only token tables; impedance-matching... |
| 1258 | -- note that constants returned by the lexer is source-level, so |
| 1259 | -- for now, fake(!) constant tokens (TK_NUMBER|TK_STRING|TK_LSTRING) |
| 1260 | ------------------------------------------------------------------ |
| 1261 | local j = 1 |
| 1262 | toklist, seminfolist, toklnlist, xreflist = {}, {}, {}, {} |
| 1263 | for i = 1, #tokorig do |
| 1264 | local tok = tokorig[i] |
| 1265 | local yep = true |
| 1266 | if tok == "TK_KEYWORD" or tok == "TK_OP" then |
| 1267 | tok = seminfoorig[i] |
| 1268 | elseif tok == "TK_NAME" then |
| 1269 | tok = "<name>" |
| 1270 | seminfolist[j] = seminfoorig[i] |
| 1271 | elseif tok == "TK_NUMBER" then |
| 1272 | tok = "<number>" |
| 1273 | seminfolist[j] = 0 -- fake! |
| 1274 | elseif tok == "TK_STRING" or tok == "TK_LSTRING" then |
| 1275 | tok = "<string>" |
| 1276 | seminfolist[j] = "" -- fake! |
| 1277 | elseif tok == "TK_EOS" then |
| 1278 | tok = "<eof>" |
| 1279 | else |
| 1280 | -- non-grammar tokens; ignore them |
| 1281 | yep = false |
| 1282 | end |
| 1283 | if yep then -- set rest of the information |
| 1284 | toklist[j] = tok |
| 1285 | toklnlist[j] = toklnorig[i] |
| 1286 | xreflist[j] = i |
| 1287 | j = j + 1 |
| 1288 | end |
| 1289 | end--for |
| 1290 | ------------------------------------------------------------------ |
| 1291 | -- initialize data structures for variable tracking |
| 1292 | ------------------------------------------------------------------ |
| 1293 | globalinfo, globallookup, localinfo = {}, {}, {} |
| 1294 | ilocalinfo, ilocalrefs = {}, {} |
| 1295 | end |
| 1296 | |
| 1297 | lparser = { |
| 1298 | expr = expr, |
| 1299 | exp1 = exp1, |
| 1300 | explist1 = explist1, |
| 1301 | body = body, |
| 1302 | block = block, |
| 1303 | for_stat = for_stat, |
| 1304 | while_stat = while_stat, |
| 1305 | repeat_stat = repeat_stat, |
| 1306 | if_stat = if_stat, |
| 1307 | return_stat = return_stat, |
| 1308 | break_stat = break_stat, |
| 1309 | expr_stat = expr_stat, |
| 1310 | function_stat = function_stat, |
| 1311 | do_stat = do_stat, |
| 1312 | local_stat = local_stat, |
| 1313 | chunk = chunk, |
| 1314 | parser = parser, |
| 1315 | init = init |
| 1316 | } |
| 1317 | |
| 1318 | return lparser |