summaryrefslogtreecommitdiffhomepage
path: root/contrib/luasrcdiet/lua/lparser.lua
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/luasrcdiet/lua/lparser.lua')
-rw-r--r--contrib/luasrcdiet/lua/lparser.lua1295
1 files changed, 0 insertions, 1295 deletions
diff --git a/contrib/luasrcdiet/lua/lparser.lua b/contrib/luasrcdiet/lua/lparser.lua
deleted file mode 100644
index a1e10e0161..0000000000
--- a/contrib/luasrcdiet/lua/lparser.lua
+++ /dev/null
@@ -1,1295 +0,0 @@
---[[--------------------------------------------------------------------
-
- lparser.lua: Lua 5.1 parser in Lua
- This file is part of LuaSrcDiet, based on Yueliang material.
-
- Copyright (c) 2008 Kein-Hong Man <khman@users.sf.net>
- The COPYRIGHT file describes the conditions
- under which this software may be distributed.
-
- See the ChangeLog for more information.
-
-----------------------------------------------------------------------]]
-
---[[--------------------------------------------------------------------
--- NOTES:
--- * This is a version of the native 5.1.x parser from Yueliang 0.4.0,
--- with significant modifications to handle LuaSrcDiet's needs:
--- (1) needs pre-built token tables instead of a module.method
--- (2) lparser.error is an optional error handler (from llex)
--- (3) not full parsing, currently fakes raw/unlexed constants
--- (4) parser() returns globalinfo, localinfo tables
--- * Please read technotes.txt for more technical details.
--- * NO support for 'arg' vararg functions (LUA_COMPAT_VARARG)
--- * A lot of the parser is unused, but might later be useful for
--- full-on parsing and analysis for a few measly bytes saved.
-----------------------------------------------------------------------]]
-
-local base = _G
-local string = require "string"
-module "lparser"
-local _G = base.getfenv()
-
---[[--------------------------------------------------------------------
--- variable and data structure initialization
-----------------------------------------------------------------------]]
-
-----------------------------------------------------------------------
--- initialization: main variables
-----------------------------------------------------------------------
-
-local toklist, -- grammar-only token tables (token table,
- seminfolist, -- semantic information table, line number
- toklnlist, -- table, cross-reference table)
- xreflist,
- tpos, -- token position
-
- line, -- start line # for error messages
- lastln, -- last line # for ambiguous syntax chk
- tok, seminfo, ln, xref, -- token, semantic info, line
- nameref, -- proper position of <name> token
- fs, -- current function state
- top_fs, -- top-level function state
-
- globalinfo, -- global variable information table
- globallookup, -- global variable name lookup table
- localinfo, -- local variable information table
- ilocalinfo, -- inactive locals (prior to activation)
- ilocalrefs -- corresponding references to activate
-
--- forward references for local functions
-local explist1, expr, block, exp1, body, chunk
-
-----------------------------------------------------------------------
--- initialization: data structures
-----------------------------------------------------------------------
-
-local gmatch = string.gmatch
-
-local block_follow = {} -- lookahead check in chunk(), returnstat()
-for v in gmatch("else elseif end until <eof>", "%S+") do
- block_follow[v] = true
-end
-
-local stat_call = {} -- lookup for calls in stat()
-for v in gmatch("if while do for repeat function local return break", "%S+") do
- stat_call[v] = v.."_stat"
-end
-
-local binopr_left = {} -- binary operators, left priority
-local binopr_right = {} -- binary operators, right priority
-for op, lt, rt in gmatch([[
-{+ 6 6}{- 6 6}{* 7 7}{/ 7 7}{% 7 7}
-{^ 10 9}{.. 5 4}
-{~= 3 3}{== 3 3}
-{< 3 3}{<= 3 3}{> 3 3}{>= 3 3}
-{and 2 2}{or 1 1}
-]], "{(%S+)%s(%d+)%s(%d+)}") do
- binopr_left[op] = lt + 0
- binopr_right[op] = rt + 0
-end
-
-local unopr = { ["not"] = true, ["-"] = true,
- ["#"] = true, } -- unary operators
-local UNARY_PRIORITY = 8 -- priority for unary operators
-
---[[--------------------------------------------------------------------
--- support functions
-----------------------------------------------------------------------]]
-
-----------------------------------------------------------------------
--- formats error message and throws error (duplicated from llex)
--- * a simplified version, does not report what token was responsible
-----------------------------------------------------------------------
-
-local function errorline(s, line)
- local e = error or base.error
- e(string.format("(source):%d: %s", line or ln, s))
-end
-
-----------------------------------------------------------------------
--- handles incoming token, semantic information pairs
--- * NOTE: 'nextt' is named 'next' originally
-----------------------------------------------------------------------
-
--- reads in next token
-local function nextt()
- lastln = toklnlist[tpos]
- tok, seminfo, ln, xref
- = toklist[tpos], seminfolist[tpos], toklnlist[tpos], xreflist[tpos]
- tpos = tpos + 1
-end
-
--- peek at next token (single lookahead for table constructor)
-local function lookahead()
- return toklist[tpos]
-end
-
-----------------------------------------------------------------------
--- throws a syntax error, or if token expected is not there
-----------------------------------------------------------------------
-
-local function syntaxerror(msg)
- local tok = tok
- if tok ~= "<number>" and tok ~= "<string>" then
- if tok == "<name>" then tok = seminfo end
- tok = "'"..tok.."'"
- end
- errorline(msg.." near "..tok)
-end
-
-local function error_expected(token)
- syntaxerror("'"..token.."' expected")
-end
-
-----------------------------------------------------------------------
--- tests for a token, returns outcome
--- * return value changed to boolean
-----------------------------------------------------------------------
-
-local function testnext(c)
- if tok == c then nextt(); return true end
-end
-
-----------------------------------------------------------------------
--- check for existence of a token, throws error if not found
-----------------------------------------------------------------------
-
-local function check(c)
- if tok ~= c then error_expected(c) end
-end
-
-----------------------------------------------------------------------
--- verify existence of a token, then skip it
-----------------------------------------------------------------------
-
-local function checknext(c)
- check(c); nextt()
-end
-
-----------------------------------------------------------------------
--- throws error if condition not matched
-----------------------------------------------------------------------
-
-local function check_condition(c, msg)
- if not c then syntaxerror(msg) end
-end
-
-----------------------------------------------------------------------
--- verifies token conditions are met or else throw error
-----------------------------------------------------------------------
-
-local function check_match(what, who, where)
- if not testnext(what) then
- if where == ln then
- error_expected(what)
- else
- syntaxerror("'"..what.."' expected (to close '"..who.."' at line "..where..")")
- end
- end
-end
-
-----------------------------------------------------------------------
--- expect that token is a name, return the name
-----------------------------------------------------------------------
-
-local function str_checkname()
- check("<name>")
- local ts = seminfo
- nameref = xref
- nextt()
- return ts
-end
-
-----------------------------------------------------------------------
--- adds given string s in string pool, sets e as VK
-----------------------------------------------------------------------
-
-local function codestring(e, s)
- e.k = "VK"
-end
-
-----------------------------------------------------------------------
--- consume a name token, adds it to string pool
-----------------------------------------------------------------------
-
-local function checkname(e)
- codestring(e, str_checkname())
-end
-
---[[--------------------------------------------------------------------
--- variable (global|local|upvalue) handling
--- * to track locals and globals, we can extend Yueliang's minimal
--- variable management code with little trouble
--- * entry point is singlevar() for variable lookups
--- * lookup tables (bl.locallist) are maintained awkwardly in the basic
--- block data structures, PLUS the function data structure (this is
--- an inelegant hack, since bl is nil for the top level of a function)
-----------------------------------------------------------------------]]
-
-----------------------------------------------------------------------
--- register a local variable, create local variable object, set in
--- to-activate variable list
--- * used in new_localvarliteral(), parlist(), fornum(), forlist(),
--- localfunc(), localstat()
-----------------------------------------------------------------------
-
-local function new_localvar(name, special)
- local bl = fs.bl
- local locallist
- -- locate locallist in current block object or function root object
- if bl then
- locallist = bl.locallist
- else
- locallist = fs.locallist
- end
- -- build local variable information object and set localinfo
- local id = #localinfo + 1
- localinfo[id] = { -- new local variable object
- name = name, -- local variable name
- xref = { nameref }, -- xref, first value is declaration
- decl = nameref, -- location of declaration, = xref[1]
- }
- if special then -- "self" must be not be changed
- localinfo[id].isself = true
- end
- -- this can override a local with the same name in the same scope
- -- but first, keep it inactive until it gets activated
- local i = #ilocalinfo + 1
- ilocalinfo[i] = id
- ilocalrefs[i] = locallist
-end
-
-----------------------------------------------------------------------
--- actually activate the variables so that they are visible
--- * remember Lua semantics, e.g. RHS is evaluated first, then LHS
--- * used in parlist(), forbody(), localfunc(), localstat(), body()
-----------------------------------------------------------------------
-
-local function adjustlocalvars(nvars)
- local sz = #ilocalinfo
- -- i goes from left to right, in order of local allocation, because
- -- of something like: local a,a,a = 1,2,3 which gives a = 3
- while nvars > 0 do
- nvars = nvars - 1
- local i = sz - nvars
- local id = ilocalinfo[i] -- local's id
- local obj = localinfo[id]
- local name = obj.name -- name of local
- obj.act = xref -- set activation location
- ilocalinfo[i] = nil
- local locallist = ilocalrefs[i] -- ref to lookup table to update
- ilocalrefs[i] = nil
- local existing = locallist[name] -- if existing, remove old first!
- if existing then -- do not overlap, set special
- obj = localinfo[existing] -- form of rem, as -id
- obj.rem = -id
- end
- locallist[name] = id -- activate, now visible to Lua
- end
-end
-
-----------------------------------------------------------------------
--- remove (deactivate) variables in current scope (before scope exits)
--- * zap entire locallist tables since we are not allocating registers
--- * used in leaveblock(), close_func()
-----------------------------------------------------------------------
-
-local function removevars()
- local bl = fs.bl
- local locallist
- -- locate locallist in current block object or function root object
- if bl then
- locallist = bl.locallist
- else
- locallist = fs.locallist
- end
- -- enumerate the local list at current scope and deactivate 'em
- for name, id in base.pairs(locallist) do
- local obj = localinfo[id]
- obj.rem = xref -- set deactivation location
- end
-end
-
-----------------------------------------------------------------------
--- creates a new local variable given a name
--- * skips internal locals (those starting with '('), so internal
--- locals never needs a corresponding adjustlocalvars() call
--- * special is true for "self" which must not be optimized
--- * used in fornum(), forlist(), parlist(), body()
-----------------------------------------------------------------------
-
-local function new_localvarliteral(name, special)
- if string.sub(name, 1, 1) == "(" then -- can skip internal locals
- return
- end
- new_localvar(name, special)
-end
-
-----------------------------------------------------------------------
--- search the local variable namespace of the given fs for a match
--- * returns localinfo index
--- * used only in singlevaraux()
-----------------------------------------------------------------------
-
-local function searchvar(fs, n)
- local bl = fs.bl
- local locallist
- if bl then
- locallist = bl.locallist
- while locallist do
- if locallist[n] then return locallist[n] end -- found
- bl = bl.prev
- locallist = bl and bl.locallist
- end
- end
- locallist = fs.locallist
- return locallist[n] or -1 -- found or not found (-1)
-end
-
-----------------------------------------------------------------------
--- handle locals, globals and upvalues and related processing
--- * search mechanism is recursive, calls itself to search parents
--- * used only in singlevar()
-----------------------------------------------------------------------
-
-local function singlevaraux(fs, n, var)
- if fs == nil then -- no more levels?
- var.k = "VGLOBAL" -- default is global variable
- return "VGLOBAL"
- else
- local v = searchvar(fs, n) -- look up at current level
- if v >= 0 then
- var.k = "VLOCAL"
- var.id = v
- -- codegen may need to deal with upvalue here
- return "VLOCAL"
- else -- not found at current level; try upper one
- if singlevaraux(fs.prev, n, var) == "VGLOBAL" then
- return "VGLOBAL"
- end
- -- else was LOCAL or UPVAL, handle here
- var.k = "VUPVAL" -- upvalue in this level
- return "VUPVAL"
- end--if v
- end--if fs
-end
-
-----------------------------------------------------------------------
--- consume a name token, creates a variable (global|local|upvalue)
--- * used in prefixexp(), funcname()
-----------------------------------------------------------------------
-
-local function singlevar(v)
- local name = str_checkname()
- singlevaraux(fs, name, v)
- ------------------------------------------------------------------
- -- variable tracking
- ------------------------------------------------------------------
- if v.k == "VGLOBAL" then
- -- if global being accessed, keep track of it by creating an object
- local id = globallookup[name]
- if not id then
- id = #globalinfo + 1
- globalinfo[id] = { -- new global variable object
- name = name, -- global variable name
- xref = { nameref }, -- xref, first value is declaration
- }
- globallookup[name] = id -- remember it
- else
- local obj = globalinfo[id].xref
- obj[#obj + 1] = nameref -- add xref
- end
- else
- -- local/upvalue is being accessed, keep track of it
- local id = v.id
- local obj = localinfo[id].xref
- obj[#obj + 1] = nameref -- add xref
- end
-end
-
---[[--------------------------------------------------------------------
--- state management functions with open/close pairs
-----------------------------------------------------------------------]]
-
-----------------------------------------------------------------------
--- enters a code unit, initializes elements
-----------------------------------------------------------------------
-
-local function enterblock(isbreakable)
- local bl = {} -- per-block state
- bl.isbreakable = isbreakable
- bl.prev = fs.bl
- bl.locallist = {}
- fs.bl = bl
-end
-
-----------------------------------------------------------------------
--- leaves a code unit, close any upvalues
-----------------------------------------------------------------------
-
-local function leaveblock()
- local bl = fs.bl
- removevars()
- fs.bl = bl.prev
-end
-
-----------------------------------------------------------------------
--- opening of a function
--- * top_fs is only for anchoring the top fs, so that parser() can
--- return it to the caller function along with useful output
--- * used in parser() and body()
-----------------------------------------------------------------------
-
-local function open_func()
- local new_fs -- per-function state
- if not fs then -- top_fs is created early
- new_fs = top_fs
- else
- new_fs = {}
- end
- new_fs.prev = fs -- linked list of function states
- new_fs.bl = nil
- new_fs.locallist = {}
- fs = new_fs
-end
-
-----------------------------------------------------------------------
--- closing of a function
--- * used in parser() and body()
-----------------------------------------------------------------------
-
-local function close_func()
- removevars()
- fs = fs.prev
-end
-
---[[--------------------------------------------------------------------
--- other parsing functions
--- * for table constructor, parameter list, argument list
-----------------------------------------------------------------------]]
-
-----------------------------------------------------------------------
--- parse a function name suffix, for function call specifications
--- * used in primaryexp(), funcname()
-----------------------------------------------------------------------
-
-local function field(v)
- -- field -> ['.' | ':'] NAME
- local key = {}
- nextt() -- skip the dot or colon
- checkname(key)
- v.k = "VINDEXED"
-end
-
-----------------------------------------------------------------------
--- parse a table indexing suffix, for constructors, expressions
--- * used in recfield(), primaryexp()
-----------------------------------------------------------------------
-
-local function yindex(v)
- -- index -> '[' expr ']'
- nextt() -- skip the '['
- expr(v)
- checknext("]")
-end
-
-----------------------------------------------------------------------
--- parse a table record (hash) field
--- * used in constructor()
-----------------------------------------------------------------------
-
-local function recfield(cc)
- -- recfield -> (NAME | '['exp1']') = exp1
- local key, val = {}, {}
- if tok == "<name>" then
- checkname(key)
- else-- tok == '['
- yindex(key)
- end
- checknext("=")
- expr(val)
-end
-
-----------------------------------------------------------------------
--- emit a set list instruction if enough elements (LFIELDS_PER_FLUSH)
--- * note: retained in this skeleton because it modifies cc.v.k
--- * used in constructor()
-----------------------------------------------------------------------
-
-local function closelistfield(cc)
- if cc.v.k == "VVOID" then return end -- there is no list item
- cc.v.k = "VVOID"
-end
-
-----------------------------------------------------------------------
--- parse a table list (array) field
--- * used in constructor()
-----------------------------------------------------------------------
-
-local function listfield(cc)
- expr(cc.v)
-end
-
-----------------------------------------------------------------------
--- parse a table constructor
--- * used in funcargs(), simpleexp()
-----------------------------------------------------------------------
-
-local function constructor(t)
- -- constructor -> '{' [ field { fieldsep field } [ fieldsep ] ] '}'
- -- field -> recfield | listfield
- -- fieldsep -> ',' | ';'
- local line = ln
- local cc = {}
- cc.v = {}
- cc.t = t
- t.k = "VRELOCABLE"
- cc.v.k = "VVOID"
- checknext("{")
- repeat
- if tok == "}" then break end
- -- closelistfield(cc) here
- local c = tok
- if c == "<name>" then -- may be listfields or recfields
- if lookahead() ~= "=" then -- look ahead: expression?
- listfield(cc)
- else
- recfield(cc)
- end
- elseif c == "[" then -- constructor_item -> recfield
- recfield(cc)
- else -- constructor_part -> listfield
- listfield(cc)
- end
- until not testnext(",") and not testnext(";")
- check_match("}", "{", line)
- -- lastlistfield(cc) here
-end
-
-----------------------------------------------------------------------
--- parse the arguments (parameters) of a function declaration
--- * used in body()
-----------------------------------------------------------------------
-
-local function parlist()
- -- parlist -> [ param { ',' param } ]
- local nparams = 0
- if tok ~= ")" then -- is 'parlist' not empty?
- repeat
- local c = tok
- if c == "<name>" then -- param -> NAME
- new_localvar(str_checkname())
- nparams = nparams + 1
- elseif c == "..." then
- nextt()
- fs.is_vararg = true
- else
- syntaxerror("<name> or '...' expected")
- end
- until fs.is_vararg or not testnext(",")
- end--if
- adjustlocalvars(nparams)
-end
-
-----------------------------------------------------------------------
--- parse the parameters of a function call
--- * contrast with parlist(), used in function declarations
--- * used in primaryexp()
-----------------------------------------------------------------------
-
-local function funcargs(f)
- local args = {}
- local line = ln
- local c = tok
- if c == "(" then -- funcargs -> '(' [ explist1 ] ')'
- if line ~= lastln then
- syntaxerror("ambiguous syntax (function call x new statement)")
- end
- nextt()
- if tok == ")" then -- arg list is empty?
- args.k = "VVOID"
- else
- explist1(args)
- end
- check_match(")", "(", line)
- elseif c == "{" then -- funcargs -> constructor
- constructor(args)
- elseif c == "<string>" then -- funcargs -> STRING
- codestring(args, seminfo)
- nextt() -- must use 'seminfo' before 'next'
- else
- syntaxerror("function arguments expected")
- return
- end--if c
- f.k = "VCALL"
-end
-
---[[--------------------------------------------------------------------
--- mostly expression functions
-----------------------------------------------------------------------]]
-
-----------------------------------------------------------------------
--- parses an expression in parentheses or a single variable
--- * used in primaryexp()
-----------------------------------------------------------------------
-
-local function prefixexp(v)
- -- prefixexp -> NAME | '(' expr ')'
- local c = tok
- if c == "(" then
- local line = ln
- nextt()
- expr(v)
- check_match(")", "(", line)
- elseif c == "<name>" then
- singlevar(v)
- else
- syntaxerror("unexpected symbol")
- end--if c
-end
-
-----------------------------------------------------------------------
--- parses a prefixexp (an expression in parentheses or a single
--- variable) or a function call specification
--- * used in simpleexp(), assignment(), expr_stat()
-----------------------------------------------------------------------
-
-local function primaryexp(v)
- -- primaryexp ->
- -- prefixexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs }
- prefixexp(v)
- while true do
- local c = tok
- if c == "." then -- field
- field(v)
- elseif c == "[" then -- '[' exp1 ']'
- local key = {}
- yindex(key)
- elseif c == ":" then -- ':' NAME funcargs
- local key = {}
- nextt()
- checkname(key)
- funcargs(v)
- elseif c == "(" or c == "<string>" or c == "{" then -- funcargs
- funcargs(v)
- else
- return
- end--if c
- end--while
-end
-
-----------------------------------------------------------------------
--- parses general expression types, constants handled here
--- * used in subexpr()
-----------------------------------------------------------------------
-
-local function simpleexp(v)
- -- simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | ... |
- -- constructor | FUNCTION body | primaryexp
- local c = tok
- if c == "<number>" then
- v.k = "VKNUM"
- elseif c == "<string>" then
- codestring(v, seminfo)
- elseif c == "nil" then
- v.k = "VNIL"
- elseif c == "true" then
- v.k = "VTRUE"
- elseif c == "false" then
- v.k = "VFALSE"
- elseif c == "..." then -- vararg
- check_condition(fs.is_vararg == true,
- "cannot use '...' outside a vararg function");
- v.k = "VVARARG"
- elseif c == "{" then -- constructor
- constructor(v)
- return
- elseif c == "function" then
- nextt()
- body(v, false, ln)
- return
- else
- primaryexp(v)
- return
- end--if c
- nextt()
-end
-
-------------------------------------------------------------------------
--- Parse subexpressions. Includes handling of unary operators and binary
--- operators. A subexpr is given the rhs priority level of the operator
--- immediately left of it, if any (limit is -1 if none,) and if a binop
--- is found, limit is compared with the lhs priority level of the binop
--- in order to determine which executes first.
--- * recursively called
--- * used in expr()
-------------------------------------------------------------------------
-
-local function subexpr(v, limit)
- -- subexpr -> (simpleexp | unop subexpr) { binop subexpr }
- -- * where 'binop' is any binary operator with a priority
- -- higher than 'limit'
- local op = tok
- local uop = unopr[op]
- if uop then
- nextt()
- subexpr(v, UNARY_PRIORITY)
- else
- simpleexp(v)
- end
- -- expand while operators have priorities higher than 'limit'
- op = tok
- local binop = binopr_left[op]
- while binop and binop > limit do
- local v2 = {}
- nextt()
- -- read sub-expression with higher priority
- local nextop = subexpr(v2, binopr_right[op])
- op = nextop
- binop = binopr_left[op]
- end
- return op -- return first untreated operator
-end
-
-----------------------------------------------------------------------
--- Expression parsing starts here. Function subexpr is entered with the
--- left operator (which is non-existent) priority of -1, which is lower
--- than all actual operators. Expr information is returned in parm v.
--- * used in cond(), explist1(), index(), recfield(), listfield(),
--- prefixexp(), while_stat(), exp1()
-----------------------------------------------------------------------
-
--- this is a forward-referenced local
-function expr(v)
- -- expr -> subexpr
- subexpr(v, 0)
-end
-
---[[--------------------------------------------------------------------
--- third level parsing functions
-----------------------------------------------------------------------]]
-
-------------------------------------------------------------------------
--- parse a variable assignment sequence
--- * recursively called
--- * used in expr_stat()
-------------------------------------------------------------------------
-
-local function assignment(v)
- local e = {}
- local c = v.v.k
- check_condition(c == "VLOCAL" or c == "VUPVAL" or c == "VGLOBAL"
- or c == "VINDEXED", "syntax error")
- if testnext(",") then -- assignment -> ',' primaryexp assignment
- local nv = {} -- expdesc
- nv.v = {}
- primaryexp(nv.v)
- -- lparser.c deals with some register usage conflict here
- assignment(nv)
- else -- assignment -> '=' explist1
- checknext("=")
- explist1(e)
- return -- avoid default
- end
- e.k = "VNONRELOC"
-end
-
-----------------------------------------------------------------------
--- parse a for loop body for both versions of the for loop
--- * used in fornum(), forlist()
-----------------------------------------------------------------------
-
-local function forbody(nvars, isnum)
- -- forbody -> DO block
- checknext("do")
- enterblock(false) -- scope for declared variables
- adjustlocalvars(nvars)
- block()
- leaveblock() -- end of scope for declared variables
-end
-
-----------------------------------------------------------------------
--- parse a numerical for loop, calls forbody()
--- * used in for_stat()
-----------------------------------------------------------------------
-
-local function fornum(varname)
- -- fornum -> NAME = exp1, exp1 [, exp1] DO body
- local line = line
- new_localvarliteral("(for index)")
- new_localvarliteral("(for limit)")
- new_localvarliteral("(for step)")
- new_localvar(varname)
- checknext("=")
- exp1() -- initial value
- checknext(",")
- exp1() -- limit
- if testnext(",") then
- exp1() -- optional step
- else
- -- default step = 1
- end
- forbody(1, true)
-end
-
-----------------------------------------------------------------------
--- parse a generic for loop, calls forbody()
--- * used in for_stat()
-----------------------------------------------------------------------
-
-local function forlist(indexname)
- -- forlist -> NAME {, NAME} IN explist1 DO body
- local e = {}
- -- create control variables
- new_localvarliteral("(for generator)")
- new_localvarliteral("(for state)")
- new_localvarliteral("(for control)")
- -- create declared variables
- new_localvar(indexname)
- local nvars = 1
- while testnext(",") do
- new_localvar(str_checkname())
- nvars = nvars + 1
- end
- checknext("in")
- local line = line
- explist1(e)
- forbody(nvars, false)
-end
-
-----------------------------------------------------------------------
--- parse a function name specification
--- * used in func_stat()
-----------------------------------------------------------------------
-
-local function funcname(v)
- -- funcname -> NAME {field} [':' NAME]
- local needself = false
- singlevar(v)
- while tok == "." do
- field(v)
- end
- if tok == ":" then
- needself = true
- field(v)
- end
- return needself
-end
-
-----------------------------------------------------------------------
--- parse the single expressions needed in numerical for loops
--- * used in fornum()
-----------------------------------------------------------------------
-
--- this is a forward-referenced local
-function exp1()
- -- exp1 -> expr
- local e = {}
- expr(e)
-end
-
-----------------------------------------------------------------------
--- parse condition in a repeat statement or an if control structure
--- * used in repeat_stat(), test_then_block()
-----------------------------------------------------------------------
-
-local function cond()
- -- cond -> expr
- local v = {}
- expr(v) -- read condition
-end
-
-----------------------------------------------------------------------
--- parse part of an if control structure, including the condition
--- * used in if_stat()
-----------------------------------------------------------------------
-
-local function test_then_block()
- -- test_then_block -> [IF | ELSEIF] cond THEN block
- nextt() -- skip IF or ELSEIF
- cond()
- checknext("then")
- block() -- 'then' part
-end
-
-----------------------------------------------------------------------
--- parse a local function statement
--- * used in local_stat()
-----------------------------------------------------------------------
-
-local function localfunc()
- -- localfunc -> NAME body
- local v, b = {}
- new_localvar(str_checkname())
- v.k = "VLOCAL"
- adjustlocalvars(1)
- body(b, false, ln)
-end
-
-----------------------------------------------------------------------
--- parse a local variable declaration statement
--- * used in local_stat()
-----------------------------------------------------------------------
-
-local function localstat()
- -- localstat -> NAME {',' NAME} ['=' explist1]
- local nvars = 0
- local e = {}
- repeat
- new_localvar(str_checkname())
- nvars = nvars + 1
- until not testnext(",")
- if testnext("=") then
- explist1(e)
- else
- e.k = "VVOID"
- end
- adjustlocalvars(nvars)
-end
-
-----------------------------------------------------------------------
--- parse a list of comma-separated expressions
--- * used in return_stat(), localstat(), funcargs(), assignment(),
--- forlist()
-----------------------------------------------------------------------
-
--- this is a forward-referenced local
-function explist1(e)
- -- explist1 -> expr { ',' expr }
- expr(e)
- while testnext(",") do
- expr(e)
- end
-end
-
-----------------------------------------------------------------------
--- parse function declaration body
--- * used in simpleexp(), localfunc(), func_stat()
-----------------------------------------------------------------------
-
--- this is a forward-referenced local
-function body(e, needself, line)
- -- body -> '(' parlist ')' chunk END
- open_func()
- checknext("(")
- if needself then
- new_localvarliteral("self", true)
- adjustlocalvars(1)
- end
- parlist()
- checknext(")")
- chunk()
- check_match("end", "function", line)
- close_func()
-end
-
-----------------------------------------------------------------------
--- parse a code block or unit
--- * used in do_stat(), while_stat(), forbody(), test_then_block(),
--- if_stat()
-----------------------------------------------------------------------
-
--- this is a forward-referenced local
-function block()
- -- block -> chunk
- enterblock(false)
- chunk()
- leaveblock()
-end
-
---[[--------------------------------------------------------------------
--- second level parsing functions, all with '_stat' suffix
--- * since they are called via a table lookup, they cannot be local
--- functions (a lookup table of local functions might be smaller...)
--- * stat() -> *_stat()
-----------------------------------------------------------------------]]
-
-----------------------------------------------------------------------
--- initial parsing for a for loop, calls fornum() or forlist()
--- * removed 'line' parameter (used to set debug information only)
--- * used in stat()
-----------------------------------------------------------------------
-
-function for_stat()
- -- stat -> for_stat -> FOR (fornum | forlist) END
- local line = line
- enterblock(true) -- scope for loop and control variables
- nextt() -- skip 'for'
- local varname = str_checkname() -- first variable name
- local c = tok
- if c == "=" then
- fornum(varname)
- elseif c == "," or c == "in" then
- forlist(varname)
- else
- syntaxerror("'=' or 'in' expected")
- end
- check_match("end", "for", line)
- leaveblock() -- loop scope (`break' jumps to this point)
-end
-
-----------------------------------------------------------------------
--- parse a while-do control structure, body processed by block()
--- * used in stat()
-----------------------------------------------------------------------
-
-function while_stat()
- -- stat -> while_stat -> WHILE cond DO block END
- local line = line
- nextt() -- skip WHILE
- cond() -- parse condition
- enterblock(true)
- checknext("do")
- block()
- check_match("end", "while", line)
- leaveblock()
-end
-
-----------------------------------------------------------------------
--- parse a repeat-until control structure, body parsed by chunk()
--- * originally, repeatstat() calls breakstat() too if there is an
--- upvalue in the scope block; nothing is actually lexed, it is
--- actually the common code in breakstat() for closing of upvalues
--- * used in stat()
-----------------------------------------------------------------------
-
-function repeat_stat()
- -- stat -> repeat_stat -> REPEAT block UNTIL cond
- local line = line
- enterblock(true) -- loop block
- enterblock(false) -- scope block
- nextt() -- skip REPEAT
- chunk()
- check_match("until", "repeat", line)
- cond()
- -- close upvalues at scope level below
- leaveblock() -- finish scope
- leaveblock() -- finish loop
-end
-
-----------------------------------------------------------------------
--- parse an if control structure
--- * used in stat()
-----------------------------------------------------------------------
-
-function if_stat()
- -- stat -> if_stat -> IF cond THEN block
- -- {ELSEIF cond THEN block} [ELSE block] END
- local line = line
- local v = {}
- test_then_block() -- IF cond THEN block
- while tok == "elseif" do
- test_then_block() -- ELSEIF cond THEN block
- end
- if tok == "else" then
- nextt() -- skip ELSE
- block() -- 'else' part
- end
- check_match("end", "if", line)
-end
-
-----------------------------------------------------------------------
--- parse a return statement
--- * used in stat()
-----------------------------------------------------------------------
-
-function return_stat()
- -- stat -> return_stat -> RETURN explist
- local e = {}
- nextt() -- skip RETURN
- local c = tok
- if block_follow[c] or c == ";" then
- -- return no values
- else
- explist1(e) -- optional return values
- end
-end
-
-----------------------------------------------------------------------
--- parse a break statement
--- * used in stat()
-----------------------------------------------------------------------
-
-function break_stat()
- -- stat -> break_stat -> BREAK
- local bl = fs.bl
- nextt() -- skip BREAK
- while bl and not bl.isbreakable do -- find a breakable block
- bl = bl.prev
- end
- if not bl then
- syntaxerror("no loop to break")
- end
-end
-
-----------------------------------------------------------------------
--- parse a function call with no returns or an assignment statement
--- * the struct with .prev is used for name searching in lparse.c,
--- so it is retained for now; present in assignment() also
--- * used in stat()
-----------------------------------------------------------------------
-
-function expr_stat()
- -- stat -> expr_stat -> func | assignment
- local v = {}
- v.v = {}
- primaryexp(v.v)
- if v.v.k == "VCALL" then -- stat -> func
- -- call statement uses no results
- else -- stat -> assignment
- v.prev = nil
- assignment(v)
- end
-end
-
-----------------------------------------------------------------------
--- parse a function statement
--- * used in stat()
-----------------------------------------------------------------------
-
-function function_stat()
- -- stat -> function_stat -> FUNCTION funcname body
- local line = line
- local v, b = {}, {}
- nextt() -- skip FUNCTION
- local needself = funcname(v)
- body(b, needself, line)
-end
-
-----------------------------------------------------------------------
--- parse a simple block enclosed by a DO..END pair
--- * used in stat()
-----------------------------------------------------------------------
-
-function do_stat()
- -- stat -> do_stat -> DO block END
- local line = line
- nextt() -- skip DO
- block()
- check_match("end", "do", line)
-end
-
-----------------------------------------------------------------------
--- parse a statement starting with LOCAL
--- * used in stat()
-----------------------------------------------------------------------
-
-function local_stat()
- -- stat -> local_stat -> LOCAL FUNCTION localfunc
- -- -> LOCAL localstat
- nextt() -- skip LOCAL
- if testnext("function") then -- local function?
- localfunc()
- else
- localstat()
- end
-end
-
---[[--------------------------------------------------------------------
--- main functions, top level parsing functions
--- * accessible functions are: init(lexer), parser()
--- * [entry] -> parser() -> chunk() -> stat()
-----------------------------------------------------------------------]]
-
-----------------------------------------------------------------------
--- initial parsing for statements, calls '_stat' suffixed functions
--- * used in chunk()
-----------------------------------------------------------------------
-
-local function stat()
- -- stat -> if_stat while_stat do_stat for_stat repeat_stat
- -- function_stat local_stat return_stat break_stat
- -- expr_stat
- line = ln -- may be needed for error messages
- local c = tok
- local fn = stat_call[c]
- -- handles: if while do for repeat function local return break
- if fn then
- _G[fn]()
- -- return or break must be last statement
- if c == "return" or c == "break" then return true end
- else
- expr_stat()
- end
- return false
-end
-
-----------------------------------------------------------------------
--- parse a chunk, which consists of a bunch of statements
--- * used in parser(), body(), block(), repeat_stat()
-----------------------------------------------------------------------
-
--- this is a forward-referenced local
-function chunk()
- -- chunk -> { stat [';'] }
- local islast = false
- while not islast and not block_follow[tok] do
- islast = stat()
- testnext(";")
- end
-end
-
-----------------------------------------------------------------------
--- performs parsing, returns parsed data structure
-----------------------------------------------------------------------
-
-function parser()
- open_func()
- fs.is_vararg = true -- main func. is always vararg
- nextt() -- read first token
- chunk()
- check("<eof>")
- close_func()
- return globalinfo, localinfo
-end
-
-----------------------------------------------------------------------
--- initialization function
-----------------------------------------------------------------------
-
-function init(tokorig, seminfoorig, toklnorig)
- tpos = 1 -- token position
- top_fs = {} -- reset top level function state
- ------------------------------------------------------------------
- -- set up grammar-only token tables; impedance-matching...
- -- note that constants returned by the lexer is source-level, so
- -- for now, fake(!) constant tokens (TK_NUMBER|TK_STRING|TK_LSTRING)
- ------------------------------------------------------------------
- local j = 1
- toklist, seminfolist, toklnlist, xreflist = {}, {}, {}, {}
- for i = 1, #tokorig do
- local tok = tokorig[i]
- local yep = true
- if tok == "TK_KEYWORD" or tok == "TK_OP" then
- tok = seminfoorig[i]
- elseif tok == "TK_NAME" then
- tok = "<name>"
- seminfolist[j] = seminfoorig[i]
- elseif tok == "TK_NUMBER" then
- tok = "<number>"
- seminfolist[j] = 0 -- fake!
- elseif tok == "TK_STRING" or tok == "TK_LSTRING" then
- tok = "<string>"
- seminfolist[j] = "" -- fake!
- elseif tok == "TK_EOS" then
- tok = "<eof>"
- else
- -- non-grammar tokens; ignore them
- yep = false
- end
- if yep then -- set rest of the information
- toklist[j] = tok
- toklnlist[j] = toklnorig[i]
- xreflist[j] = i
- j = j + 1
- end
- end--for
- ------------------------------------------------------------------
- -- initialize data structures for variable tracking
- ------------------------------------------------------------------
- globalinfo, globallookup, localinfo = {}, {}, {}
- ilocalinfo, ilocalrefs = {}, {}
-end
-
-return _G