From 9f0b67bba1d80dfebab5059249a65434d966eaa4 Mon Sep 17 00:00:00 2001 From: Lua Team Date: Sun, 12 Jul 1998 01:48:48 +0000 Subject: [PATCH] Imported from ../lua-3.1.tar.gz. --- COPYRIGHT | 71 +- HISTORY | 34 +- INSTALL | 32 +- MANIFEST | 112 +++ Makefile | 4 +- README | 54 +- clients/lib/Makefile | 35 - clients/lib/iolib.c | 330 -------- clients/lib/mathlib.c | 217 ------ clients/lib/strlib.c | 535 ------------- clients/lua/README | 5 - clients/lua/lua.c | 141 ---- config | 46 +- doc/idx.html | 115 +-- doc/index.html | 51 +- doc/luac.html | 246 +++--- doc/luac.man | 165 ++++ doc/manual.html | 1733 +++++++++++++++++++++++++---------------- etc/Makefile | 24 + etc/README | 25 + etc/bin2c.c | 66 ++ etc/min.c | 13 + etc/setfallback.lua | 55 ++ etc/trace.c | 53 ++ include/Makefile | 4 +- include/auxlib.h | 30 - include/lauxlib.h | 47 ++ include/lua.h | 87 ++- include/luadebug.h | 10 +- include/lualib.h | 63 +- src/Makefile | 151 ++-- src/auxlib.c | 81 -- src/auxlib.h | 30 - src/fallback.c | 368 --------- src/fallback.h | 65 -- src/func.c | 166 ---- src/func.h | 45 -- src/hash.c | 332 -------- src/hash.h | 39 - src/inout.c | 408 ---------- src/inout.h | 25 - src/lapi.c | 631 +++++++++++++++ src/lapi.h | 20 + src/lauxlib.c | 111 +++ src/lbuffer.c | 85 ++ src/lbuiltin.c | 526 +++++++++++++ src/lbuiltin.h | 14 + src/ldo.c | 427 ++++++++++ src/ldo.h | 46 ++ src/lex.c | 470 ----------- src/lex.h | 18 - src/lfunc.c | 98 +++ src/lfunc.h | 23 + src/lgc.c | 288 +++++++ src/lgc.h | 21 + src/lib/Makefile | 28 + src/lib/README | 4 + src/lib/liolib.c | 448 +++++++++++ src/lib/lmathlib.c | 213 +++++ src/lib/lstrlib.c | 541 +++++++++++++ src/llex.c | 463 +++++++++++ src/llex.h | 62 ++ src/lmem.c | 113 +++ src/lmem.h | 43 + src/lobject.c | 83 ++ src/lobject.h | 210 +++++ src/lopcodes.h | 181 +++++ src/lparser.c | 1333 +++++++++++++++++++++++++++++++ src/lparser.h | 20 + src/lstate.c | 86 ++ src/lstate.h | 86 ++ src/lstring.c | 313 ++++++++ src/lstring.h | 28 + src/ltable.c | 216 +++++ src/ltable.h | 24 + src/ltm.c | 263 +++++++ src/ltm.h | 62 ++ src/lua.stx | 791 ------------------- {clients => src}/lua/Makefile | 14 +- src/lua/README | 20 + src/lua/lua.c | 194 +++++ src/luac/Makefile | 16 +- src/luac/README | 25 + src/luac/dump.c | 398 ++++------ src/luac/luac.c | 176 ++--- src/luac/luac.h | 58 +- src/luac/opcode.c | 87 +++ src/luac/opcode.h | 134 ++++ src/luac/opt.c | 228 ++++++ src/luac/print.c | 616 ++++++--------- src/luac/print.h | 79 -- src/luac/stubs.c | 68 ++ src/luamem.c | 159 ---- src/luamem.h | 39 - src/lundump.c | 228 ++++++ src/lundump.h | 78 ++ src/lvm.c | 737 ++++++++++++++++++ src/lvm.h | 29 + src/{zio.c => lzio.c} | 29 +- src/{zio.h => lzio.h} | 22 +- src/opcode.c | 1478 ----------------------------------- src/opcode.h | 171 ---- src/parser.c | 1696 ---------------------------------------- src/parser.h | 38 - src/table.c | 266 ------- src/table.h | 39 - src/tree.c | 211 ----- src/tree.h | 38 - src/types.h | 29 - src/undump.c | 330 -------- src/undump.h | 30 - test/array.lua | 2 - test/bisect.lua | 6 +- test/examples/www/README | 6 +- test/examples/www/db.lua | 2 +- test/factorial.lua | 37 + test/fib.lua | 11 + test/globals.lua | 20 + test/{dump.lua => save.lua} | 10 +- test/sort.lua | 115 +-- test/trace.lua | 33 + 121 files changed, 11885 insertions(+), 10619 deletions(-) rewrite COPYRIGHT (67%) create mode 100644 MANIFEST delete mode 100644 clients/lib/Makefile delete mode 100644 clients/lib/iolib.c delete mode 100644 clients/lib/mathlib.c delete mode 100644 clients/lib/strlib.c delete mode 100644 clients/lua/README delete mode 100644 clients/lua/lua.c rewrite doc/luac.html (100%) create mode 100644 doc/luac.man create mode 100644 etc/Makefile create mode 100644 etc/README create mode 100644 etc/bin2c.c create mode 100644 etc/min.c create mode 100644 etc/setfallback.lua create mode 100644 etc/trace.c delete mode 100644 include/auxlib.h create mode 100644 include/lauxlib.h rewrite include/lualib.h (85%) rewrite src/Makefile (88%) delete mode 100644 src/auxlib.c delete mode 100644 src/auxlib.h delete mode 100644 src/fallback.c delete mode 100644 src/fallback.h delete mode 100644 src/func.c delete mode 100644 src/func.h delete mode 100644 src/hash.c delete mode 100644 src/hash.h delete mode 100644 src/inout.c delete mode 100644 src/inout.h create mode 100644 src/lapi.c create mode 100644 src/lapi.h create mode 100644 src/lauxlib.c create mode 100644 src/lbuffer.c create mode 100644 src/lbuiltin.c create mode 100644 src/lbuiltin.h create mode 100644 src/ldo.c create mode 100644 src/ldo.h delete mode 100644 src/lex.c delete mode 100644 src/lex.h create mode 100644 src/lfunc.c create mode 100644 src/lfunc.h create mode 100644 src/lgc.c create mode 100644 src/lgc.h create mode 100644 src/lib/Makefile create mode 100644 src/lib/README create mode 100644 src/lib/liolib.c create mode 100644 src/lib/lmathlib.c create mode 100644 src/lib/lstrlib.c create mode 100644 src/llex.c create mode 100644 src/llex.h create mode 100644 src/lmem.c create mode 100644 src/lmem.h create mode 100644 src/lobject.c create mode 100644 src/lobject.h create mode 100644 src/lopcodes.h create mode 100644 src/lparser.c create mode 100644 src/lparser.h create mode 100644 src/lstate.c create mode 100644 src/lstate.h create mode 100644 src/lstring.c create mode 100644 src/lstring.h create mode 100644 src/ltable.c create mode 100644 src/ltable.h create mode 100644 src/ltm.c create mode 100644 src/ltm.h delete mode 100644 src/lua.stx rename {clients => src}/lua/Makefile (68%) create mode 100644 src/lua/README create mode 100644 src/lua/lua.c create mode 100644 src/luac/README rewrite src/luac/dump.c (92%) rewrite src/luac/luac.h (98%) create mode 100644 src/luac/opcode.c create mode 100644 src/luac/opcode.h create mode 100644 src/luac/opt.c rewrite src/luac/print.c (90%) delete mode 100644 src/luac/print.h create mode 100644 src/luac/stubs.c delete mode 100644 src/luamem.c delete mode 100644 src/luamem.h create mode 100644 src/lundump.c create mode 100644 src/lundump.h create mode 100644 src/lvm.c create mode 100644 src/lvm.h rename src/{zio.c => lzio.c} (71%) rename src/{zio.h => lzio.h} (60%) delete mode 100644 src/opcode.c delete mode 100644 src/opcode.h delete mode 100644 src/parser.c delete mode 100644 src/parser.h delete mode 100644 src/table.c delete mode 100644 src/table.h delete mode 100644 src/tree.c delete mode 100644 src/tree.h delete mode 100644 src/types.h delete mode 100644 src/undump.c delete mode 100644 src/undump.h create mode 100644 test/factorial.lua create mode 100644 test/fib.lua create mode 100644 test/globals.lua rename test/{dump.lua => save.lua} (87%) rewrite test/sort.lua (70%) create mode 100644 test/trace.lua diff --git a/COPYRIGHT b/COPYRIGHT dissimilarity index 67% index f84898d..3a1c024 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,24 +1,47 @@ -Copyright (c) 1994-1997 TeCGraf, PUC-Rio. Written by Waldemar Celes Filho, -Roberto Ierusalimschy, Luiz Henrique de Figueiredo. All rights reserved. - -Permission is hereby granted, without written agreement and without license or -royalty fees, to use, copy, modify, and distribute this software and its -documentation for any purpose, subject to the following conditions: - -The above copyright notice and this permission notice shall appear in all -copies or substantial portions of this software. - -The name "Lua" cannot be used for any modified form of this software that does -not originate from the authors. Nevertheless, the name "Lua" may and should be -used to designate the language implemented and described in this package, -even if embedded in any other system, as long as its syntax and semantics -remain unchanged. - -The authors specifically disclaim any warranties, including, but not limited -to, the implied warranties of merchantability and fitness for a particular -purpose. The software provided hereunder is on an "as is" basis, and the -authors have no obligation to provide maintenance, support, updates, -enhancements, or modifications. In no event shall TeCGraf, PUC-Rio, or the -authors be liable to any party for direct, indirect, special, incidental, or -consequential damages arising out of the use of this software and its -documentation. +Lua COPYRIGHT NOTICE +-------------------- + +Lua is free and non-proprietary. +It can be used for both academic and commercial purposes at absolutely no cost. +There are no royalties or GNU-like "copyleft" restrictions. +On the other hand, Lua is not in the public domain; TeCGraf keeps its copyright. +If you use Lua, please give us credit, but we would appreciate *not* receiving +lengthy legal documents to sign. +The legal details are below. + +=============================================================================== + +Copyright (c) 1994-1998 TeCGraf, PUC-Rio. All rights reserved. + +Permission is hereby granted, without written agreement and without license +or royalty fees, to use, copy, modify, and distribute this software and its +documentation for any purpose, including commercial applications, subject to +the following conditions: + + * The above copyright notice and this permission notice shall appear in all + copies or substantial portions of this software. + + * The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software in a + product, an acknowledgment in the product documentation would be greatly + appreciated (but it is not required). + + * Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + +The authors specifically disclaim any warranties, including, but not limited +to, the implied warranties of merchantability and fitness for a particular +purpose. The software provided hereunder is on an "as is" basis, and the +authors have no obligation to provide maintenance, support, updates, +enhancements, or modifications. In no event shall TeCGraf, PUC-Rio, or the +authors be held liable to any party for direct, indirect, special, +incidental, or consequential damages arising out of the use of this software +and its documentation. + +The Lua language and this implementation have been entirely designed and written +by Waldemar Celes, Roberto Ierusalimschy, and Luiz Henrique de Figueiredo +at TeCGraf, PUC-Rio. + +This implementation contains no third-party code. + +=============================================================================== diff --git a/HISTORY b/HISTORY index 1db2df2..c87a005 100644 --- a/HISTORY +++ b/HISTORY @@ -1,6 +1,28 @@ -This is version 3.0. +This is version 3.1. -* Changes since version 2.5 (no versions between 2.5 and 3.0) +* Changes from version 3.0 to 3.1 + + NEW FEATURE: anonymous functions with closures (via "upvalues"). + + new syntax: + - local variables in chunks. + - better scope control with DO block END. + - constructors can now be also written: { record-part; list-part }. + - more general syntax for function calls and lvalues, e.g.: + f(x).y=1 + o:f(x,y):g(z) + f"string" is sugar for f("string") + + strings may now contain arbitrary binary data (e.g., embedded zeros). + + major code re-organization and clean-up; reduced module interdependecies. + + no arbitrary limits on the total number of constants and globals. + + support for multiple global contexts. + + better syntax error messages. + + new traversal functions "foreach" and "foreachvar". + + the default for numbers is now double. + changing it to use floats or longs is easy. + + complete debug information stored in pre-compiled chunks. + + sample interpreter now prompts user when run interactively, and also + handles control-C interruptions gracefully. + +* Changes from version 2.5 to 3.0 + NEW CONCEPT: "tag methods". Tag methods replace fallbacks as the meta-mechanism for extending the semantics of Lua. Whereas fallbacks had a global nature, tag methods @@ -14,14 +36,14 @@ This is version 3.0. + better type checking and error messages in the standard library. + luac can now also undump. -* Changes since version 2.4 +* Changes from version 2.4 to 2.5 + io and string libraries are now based on pattern matching; the old libraries are still available for compatibility + dofile and dostring can now return values (via return statement) + better support for 16- and 64-bit machines + expanded documentation, with more examples -* Changes since version 2.2 +* Changes from version 2.2 to 2.4 + external compiler creates portable binary files that can be loaded faster + interface for debugging and profiling + new "getglobal" fallback @@ -30,12 +52,12 @@ This is version 3.0. + only one copy of each string is stored + expanded documentation, with more examples -* Changes since version 2.1 +* Changes from version 2.1 to 2.2 + functions now may be declared with any "lvalue" as a name + garbage collection of functions + support for pipes -* Changes since version 1.1 +* Changes from version 1.1 to 2.1 + object-oriented support + fallbacks + simplified syntax for tables diff --git a/INSTALL b/INSTALL index 5a349d7..95a10dd 100644 --- a/INSTALL +++ b/INSTALL @@ -2,20 +2,21 @@ Building Lua on a Unix system should be very easy: - 1. Edit "config" to suit your platform, if at all necessary - 2. Then, type "make" + 1. Edit "config" to suit your platform, if at all necessary. + 2. Then, type "make". See below for instructions for Windows and Macintosh. * What you get - If make succeeds, you get: - * an interpreter and a compiler in ./bin; + If "make" succeeds, you get: + * an interpreter in ./bin/lua and a compiler in ./bin/luac; * libraries in ./lib; * include files in ./include. These are the only directories you need for development. - There is a reference manual in html in ./doc, and sample code in ./test. + There is a reference manual in html in ./doc, some sample code in ./test, + and some useful stuff in ./etc. You don't need these directories for development. * If you have problems (and solutions!) @@ -26,28 +27,33 @@ * Shared libraries If you are running SunOs 4.x, type the following after "make" succeeds: - ld -o lib/liblua.so.3.0 src/*.o - ld -o lib/liblualib.so.3.0 clients/lib/*.o + ld -o lib/liblua.so.3.1 src/*.o + ld -o lib/liblualib.so.3.1 src/lib/*.o + + If you want the interpreter to use shared libraries, then do: + rm bin/lua + cd src/lua; make For AIX, the OpenGL clone Mesa includes a script for making shared libraries. For other systems, please tell us how! * Installation on Windows or Macintosh - + The instructions for building Lua on a Mac or Windows machine depend on the particular compiler you are using. The simplest way is to create a folder with all .c and .h files. Then create projects for the basic library, the standard library, the interpreter and the compiler, as follows: - basic lib: auxlib.c fallback.c func.c hash.c inout.c lex.c luamem.c - opcode.c parser.c table.c tree.c undump.c zio.c + basic lib: lapi.c lauxlib.c lbuffer.c lbuiltin.c ldo.c lfunc.c lgc.c + llex.c lmem.c lobject.c lparser.c lstate.c lstring.c ltable.c + ltm.c lundump.c lvm.c lzio.c - standard lib: iolib.c mathlib.c strlib.c + standard lib: liolib.c lmathlib.c lstrlib.c interpreter: basic lib, standard lib, lua.c - compiler: basic lib, dump.c luac.c print.c + compiler: basic lib, dump.c luac.c print.c stubs.c opcode.c opt.c Of course, to use Lua as a library, you'll have to know how to create - libraries and use with your compiler. + and use libraries with your compiler. diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000..7e5d11d --- /dev/null +++ b/MANIFEST @@ -0,0 +1,112 @@ +MANIFEST contents of Lua 3.1 distribution on Sat Jul 11 22:48:43 EST 1998 +lua +lua/COPYRIGHT +lua/HISTORY +lua/INSTALL +lua/MANIFEST +lua/Makefile +lua/README +lua/bin +lua/config +lua/doc +lua/doc/idx.html +lua/doc/index.html +lua/doc/luac.html +lua/doc/luac.man +lua/doc/manual.html +lua/etc +lua/etc/Makefile +lua/etc/README +lua/etc/bin2c.c +lua/etc/min.c +lua/etc/setfallback.lua +lua/etc/trace.c +lua/include +lua/include/Makefile +lua/include/lauxlib.h +lua/include/lua.h +lua/include/luadebug.h +lua/include/lualib.h +lua/lib +lua/src +lua/src/Makefile +lua/src/lapi.c +lua/src/lapi.h +lua/src/lauxlib.c +lua/src/lbuffer.c +lua/src/lbuiltin.c +lua/src/lbuiltin.h +lua/src/ldo.c +lua/src/ldo.h +lua/src/lfunc.c +lua/src/lfunc.h +lua/src/lgc.c +lua/src/lgc.h +lua/src/lib +lua/src/lib/Makefile +lua/src/lib/README +lua/src/lib/liolib.c +lua/src/lib/lmathlib.c +lua/src/lib/lstrlib.c +lua/src/llex.c +lua/src/llex.h +lua/src/lmem.c +lua/src/lmem.h +lua/src/lobject.c +lua/src/lobject.h +lua/src/lopcodes.h +lua/src/lparser.c +lua/src/lparser.h +lua/src/lstate.c +lua/src/lstate.h +lua/src/lstring.c +lua/src/lstring.h +lua/src/ltable.c +lua/src/ltable.h +lua/src/ltm.c +lua/src/ltm.h +lua/src/lua +lua/src/lua/Makefile +lua/src/lua/README +lua/src/lua/lua.c +lua/src/luac +lua/src/luac/Makefile +lua/src/luac/README +lua/src/luac/dump.c +lua/src/luac/luac.c +lua/src/luac/luac.h +lua/src/luac/opcode.c +lua/src/luac/opcode.h +lua/src/luac/opt.c +lua/src/luac/print.c +lua/src/luac/stubs.c +lua/src/lundump.c +lua/src/lundump.h +lua/src/lvm.c +lua/src/lvm.h +lua/src/lzio.c +lua/src/lzio.h +lua/test +lua/test/README +lua/test/array.lua +lua/test/bisect.lua +lua/test/cf.lua +lua/test/examples +lua/test/examples/ps +lua/test/examples/ps/hilbert.lua +lua/test/examples/ps/ps.lua +lua/test/examples/www +lua/test/examples/www/README +lua/test/examples/www/db.lua +lua/test/examples/www/staff.lua +lua/test/examples/www/template.html +lua/test/factorial.lua +lua/test/fib.lua +lua/test/globals.lua +lua/test/hello.lua +lua/test/lua +lua/test/luac +lua/test/save.lua +lua/test/sort.lua +lua/test/trace.lua +END OF MANIFEST diff --git a/Makefile b/Makefile index c1c09f5..a8978c9 100644 --- a/Makefile +++ b/Makefile @@ -4,5 +4,5 @@ all co clean klean: cd include; make $@ cd src; make $@ cd src/luac; make $@ - cd clients/lib; make $@ - cd clients/lua; make $@ + cd src/lib; make $@ + cd src/lua; make $@ diff --git a/README b/README index b5d9b43..344faf7 100644 --- a/README +++ b/README @@ -1,36 +1,46 @@ * What is Lua? - Lua is a simple, yet powerful, language for extending applications. - Lua has been developed by TeCGraf, the Computer Graphics Technology Group - of PUC-Rio, the Pontifical Catholic University of Rio de Janeiro, Brazil. - Dozens of industrial products developed by TeCGraf use Lua. + Lua is a programming language originally designed for extending applications, + but also frequently used as a general-purpose, stand-alone language. + Lua combines simple procedural syntax (similar to Pascal) with powerful + data description constructs based on associative arrays and extensible + semantics. Lua is dynamically typed, interpreted from bytecodes, and has + automatic memory management, making it ideal for configuration, scripting, + and rapid prototyping. + + Lua is implemented as a small library of C functions, written in ANSI C, + and compiles unmodified in all known platforms. The implementation goals + are simplicity, efficiency, portability, and low embedding cost. -* Some features of Lua - + simple syntax (Pascal-like); - + powerful data description constructs (e.g., associative arrays); - + user-controlled type constructors; - + extensible semantics with tag methods; - + garbage collection; - + Lua programs are compiled into bytecodes, which are then interpreted; - + truly portable, written in ANSI C. + Lua has been awarded the first prize (technological category) in the Second + Compaq Award for Research and Development in Computer Science. This award + is a joint venture of Compaq Computer in Brazil, the Brazilian Ministry of + Science and Technology, and the Brazilian Academy of Sciences. * Availability - The latest version of Lua is always available at the following locations: - In Brazil: ftp://ftp.icad.puc-rio.br/pub/lua/lua.tar.gz + Lua is freely available for both academic and commercial purposes and + can be downloaded from the sites below. See COPYRIGHT for details. + + Home page: http://www.tecgraf.puc-rio.br/lua/ + http://csg.uwaterloo.ca/~lhf/lua/ + In Brazil: ftp://ftp.tecgraf.puc-rio.br/pub/lua/lua.tar.gz In Canada: ftp://csg.uwaterloo.ca/pub/lhf/lua/lua.tar.gz In Germany: ftp://ftp.uni-trier.de/pub/languages/lua/lua.tar.gz In Greece: ftp://ftp.ntua.gr/pub/lang/lua/lua.tar.gz - Home page: http://www.tecgraf.puc-rio.br/lua/ - Meta page: http://www.tecgraf.puc-rio.br/lua/meta.html - The current version is 3.0 - -* Legal matters - Lua is freely available for both academic and commercial purposes. - See COPYRIGHT. * Installation See INSTALL. * Contacting the authors + Lua has been designed and implemented by Waldemar Celes, + Roberto Ierusalimschy and Luiz Henrique de Figueiredo. + They can be contacted by email at lua@tecgraf.puc-rio.br. + Send your comments, bug reports and anything else to lua@tecgraf.puc-rio.br. - Please send us email if you download Lua so that we can know how far it goes. For reporting bugs, try also the mailing list: lua-l@tecgraf.puc-rio.br + To subscribe to this list, send "subscribe lua-l YOUR-NAME" to + listproc@tecgraf.puc-rio.br in the body of the message (not in the subject). + + Lua has been developed at TeCGraf, the Computer Graphics Technology Group + of PUC-Rio (the Pontifical Catholic University of Rio de Janeiro in Brazil). + TeCGraf is a laboratory of the Department of Computer Science. + Dozens of industrial products developed by TeCGraf use Lua. diff --git a/clients/lib/Makefile b/clients/lib/Makefile deleted file mode 100644 index 0388805..0000000 --- a/clients/lib/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -# makefile for lualib - -LUA= ../.. - -include $(LUA)/config - -EXTRA_DEFS= $(POPEN) $(NOSTRERROR) - -OBJS= iolib.o mathlib.o strlib.o -SRCS= iolib.c mathlib.c strlib.c - -SLIB= $(LIB)/liblualib.a - -# dynamic libraries only work for SunOs -DLIB= $(LIB)/liblualib.so.$(VERSION) - -all: $(SLIB) - -dynamic: $(DLIB) - -$(SLIB): $(OBJS) - ar rcu $@ $(OBJS) - $(RANLIB) $(SLIB) - -$(DLIB): $(OBJS) - ld -o $@ $(OBJS) - -clean: - rm -f $(OBJS) $(SLIB) $(DLIB) - -co: - co -f -M $(SRCS) - -klean: clean - rm -f $(SRCS) diff --git a/clients/lib/iolib.c b/clients/lib/iolib.c deleted file mode 100644 index e518df1..0000000 --- a/clients/lib/iolib.c +++ /dev/null @@ -1,330 +0,0 @@ -#include -#include -#include -#include -#include - -#include "lua.h" -#include "auxlib.h" -#include "luadebug.h" -#include "lualib.h" - - -int lua_tagio; - - -#ifdef POPEN -FILE *popen(); -int pclose(); -#else -#define popen(x,y) NULL /* that is, popen always fails */ -#define pclose(x) (-1) -#endif - - -static void pushresult (int i) -{ - if (i) - lua_pushuserdata(NULL); - else { - lua_pushnil(); -#ifndef NOSTRERROR - lua_pushstring(strerror(errno)); -#else - lua_pushstring("O.S. unable to define the error"); -#endif - } -} - - - -static FILE *getfile (char *name) -{ - lua_Object f = lua_getglobal(name); - if (!lua_isuserdata(f) || lua_tag(f) != lua_tagio) - luaL_verror("global variable %s is not a file handle", name); - return lua_getuserdata(f); -} - - -static void closefile (char *name) -{ - FILE *f = getfile(name); - if (f == stdin || f == stdout) return; - if (pclose(f) == -1) - fclose(f); -} - - -static void setfile (FILE *f, char *name) -{ - lua_pushusertag(f, lua_tagio); - lua_setglobal(name); -} - - -static void setreturn (FILE *f, char *name) -{ - setfile(f, name); - lua_pushusertag(f, lua_tagio); -} - - -static void io_readfrom (void) -{ - FILE *current; - lua_Object f = lua_getparam(1); - if (f == LUA_NOOBJECT) { - closefile("_INPUT"); - current = stdin; - } - else if (lua_tag(f) == lua_tagio) - current = lua_getuserdata(f); - else { - char *s = luaL_check_string(1); - current = (*s == '|') ? popen(s+1, "r") : fopen(s, "r"); - if (current == NULL) { - pushresult(0); - return; - } - } - setreturn(current, "_INPUT"); -} - - -static void io_writeto (void) -{ - FILE *current; - lua_Object f = lua_getparam(1); - if (f == LUA_NOOBJECT) { - closefile("_OUTPUT"); - current = stdout; - } - else if (lua_tag(f) == lua_tagio) - current = lua_getuserdata(f); - else { - char *s = luaL_check_string(1); - current = (*s == '|') ? popen(s+1,"w") : fopen(s,"w"); - if (current == NULL) { - pushresult(0); - return; - } - } - setreturn(current, "_OUTPUT"); -} - - -static void io_appendto (void) -{ - char *s = luaL_check_string(1); - FILE *fp = fopen (s, "a"); - if (fp != NULL) - setreturn(fp, "_OUTPUT"); - else - pushresult(0); -} - - -#define NEED_OTHER (EOF-1) /* just some flag different from EOF */ - -static void io_read (void) -{ - FILE *f = getfile("_INPUT"); - char *buff; - char *p = luaL_opt_string(1, "[^\n]*{\n}"); - int inskip = 0; /* to control {skips} */ - int c = NEED_OTHER; - luaI_emptybuff(); - while (*p) { - if (*p == '{') { - inskip++; - p++; - } - else if (*p == '}') { - if (inskip == 0) - lua_error("unbalanced braces in read pattern"); - inskip--; - p++; - } - else { - char *ep = luaL_item_end(p); /* get what is next */ - int m; /* match result */ - if (c == NEED_OTHER) c = getc(f); - m = (c == EOF) ? 0 : luaL_singlematch((char)c, p); - if (m) { - if (inskip == 0) luaI_addchar(c); - c = NEED_OTHER; - } - switch (*ep) { - case '*': /* repetition */ - if (!m) p = ep+1; /* else stay in (repeat) the same item */ - break; - case '?': /* optional */ - p = ep+1; /* continues reading the pattern */ - break; - default: - if (m) p = ep; /* continues reading the pattern */ - else - goto break_while; /* pattern fails */ - } - } - } break_while: - if (c >= 0) /* not EOF nor NEED_OTHER? */ - ungetc(c, f); - buff = luaI_addchar(0); - if (*buff != 0 || *p == 0) /* read something or did not fail? */ - lua_pushstring(buff); -} - - -static void io_write (void) -{ - FILE *f = getfile("_OUTPUT"); - int arg = 1; - int status = 1; - char *s; - while ((s = luaL_opt_string(arg++, NULL)) != NULL) - status = status && (fputs(s, f) != EOF); - pushresult(status); -} - - -static void io_execute (void) -{ - lua_pushnumber(system(luaL_check_string(1))); -} - - -static void io_remove (void) -{ - pushresult(remove(luaL_check_string(1)) == 0); -} - - -static void io_rename (void) -{ - pushresult(rename(luaL_check_string(1), - luaL_check_string(2)) == 0); -} - - -static void io_tmpname (void) -{ - lua_pushstring(tmpnam(NULL)); -} - - - -static void io_getenv (void) -{ - lua_pushstring(getenv(luaL_check_string(1))); /* if NULL push nil */ -} - - -static void io_date (void) -{ - time_t t; - struct tm *tm; - char *s = luaL_opt_string(1, "%c"); - char b[BUFSIZ]; - time(&t); tm = localtime(&t); - if (strftime(b,sizeof(b),s,tm)) - lua_pushstring(b); - else - lua_error("invalid `date' format"); -} - - -static void io_exit (void) -{ - lua_Object o = lua_getparam(1); - exit(lua_isnumber(o) ? (int)lua_getnumber(o) : 1); -} - - -static void io_debug (void) -{ - while (1) { - char buffer[250]; - fprintf(stderr, "lua_debug> "); - if (fgets(buffer, sizeof(buffer), stdin) == 0) return; - if (strcmp(buffer, "cont\n") == 0) return; - lua_dostring(buffer); - } -} - - -static void lua_printstack (FILE *f) -{ - int level = 1; /* skip level 0 (it's this function) */ - lua_Object func; - while ((func = lua_stackedfunction(level++)) != LUA_NOOBJECT) { - char *name; - int currentline; - char *filename; - int linedefined; - lua_funcinfo(func, &filename, &linedefined); - fprintf(f, (level==2) ? "Active Stack:\n\t" : "\t"); - switch (*lua_getobjname(func, &name)) { - case 'g': - fprintf(f, "function %s", name); - break; - case 't': - fprintf(f, "`%s' tag method", name); - break; - default: { - if (linedefined == 0) - fprintf(f, "main of %s", filename); - else if (linedefined < 0) - fprintf(f, "%s", filename); - else - fprintf(f, "function (%s:%d)", filename, linedefined); - filename = NULL; - } - } - if ((currentline = lua_currentline(func)) > 0) - fprintf(f, " at line %d", currentline); - if (filename) - fprintf(f, " [in file %s]", filename); - fprintf(f, "\n"); - } -} - - -static void errorfb (void) -{ - fprintf(stderr, "lua: %s\n", lua_getstring(lua_getparam(1))); - lua_printstack(stderr); -} - - - -static struct luaL_reg iolib[] = { -{"readfrom", io_readfrom}, -{"writeto", io_writeto}, -{"appendto", io_appendto}, -{"read", io_read}, -{"write", io_write}, -{"execute", io_execute}, -{"remove", io_remove}, -{"rename", io_rename}, -{"tmpname", io_tmpname}, -{"getenv", io_getenv}, -{"date", io_date}, -{"exit", io_exit}, -{"debug", io_debug}, -{"print_stack", errorfb} -}; - -void iolib_open (void) -{ - lua_tagio = lua_newtag(); - setfile(stdin, "_INPUT"); - setfile(stdout, "_OUTPUT"); - setfile(stdin, "_STDIN"); - setfile(stdout, "_STDOUT"); - setfile(stderr, "_STDERR"); - luaL_openlib(iolib, (sizeof(iolib)/sizeof(iolib[0]))); - lua_pushcfunction(errorfb); - lua_seterrormethod(); -} diff --git a/clients/lib/mathlib.c b/clients/lib/mathlib.c deleted file mode 100644 index e929d6a..0000000 --- a/clients/lib/mathlib.c +++ /dev/null @@ -1,217 +0,0 @@ -/* -** mathlib.c -** Mathematics library to LUA -*/ - -char *rcs_mathlib="$Id: mathlib.c,v 1.25 1997/06/19 18:03:04 roberto Exp $"; - -#include -#include - -#include "lualib.h" -#include "auxlib.h" -#include "lua.h" - -#ifndef PI -#define PI 3.14159265358979323846 -#endif -#define TODEGREE(a) ((a)*180.0/PI) -#define TORAD(a) ((a)*PI/180.0) - -static void math_abs (void) -{ - double d = luaL_check_number(1); - if (d < 0) d = -d; - lua_pushnumber (d); -} - - -static void math_sin (void) -{ - double d = luaL_check_number(1); - lua_pushnumber (sin(TORAD(d))); -} - - - -static void math_cos (void) -{ - double d = luaL_check_number(1); - lua_pushnumber (cos(TORAD(d))); -} - - - -static void math_tan (void) -{ - double d = luaL_check_number(1); - lua_pushnumber (tan(TORAD(d))); -} - - -static void math_asin (void) -{ - double d = luaL_check_number(1); - lua_pushnumber (TODEGREE(asin(d))); -} - - -static void math_acos (void) -{ - double d = luaL_check_number(1); - lua_pushnumber (TODEGREE(acos(d))); -} - - -static void math_atan (void) -{ - double d = luaL_check_number(1); - lua_pushnumber (TODEGREE(atan(d))); -} - - -static void math_atan2 (void) -{ - double d1 = luaL_check_number(1); - double d2 = luaL_check_number(2); - lua_pushnumber (TODEGREE(atan2(d1, d2))); -} - - -static void math_ceil (void) -{ - double d = luaL_check_number(1); - lua_pushnumber (ceil(d)); -} - - -static void math_floor (void) -{ - double d = luaL_check_number(1); - lua_pushnumber (floor(d)); -} - -static void math_mod (void) -{ - float x = luaL_check_number(1); - float y = luaL_check_number(2); - lua_pushnumber(fmod(x, y)); -} - - -static void math_sqrt (void) -{ - double d = luaL_check_number(1); - lua_pushnumber (sqrt(d)); -} - - -static void math_pow (void) -{ - double d1 = luaL_check_number(1); - double d2 = luaL_check_number(2); - lua_pushnumber(pow(d1,d2)); -} - -static void math_min (void) -{ - int i=1; - double dmin = luaL_check_number(i); - while (lua_getparam(++i) != LUA_NOOBJECT) - { - double d = luaL_check_number(i); - if (d < dmin) dmin = d; - } - lua_pushnumber (dmin); -} - -static void math_max (void) -{ - int i=1; - double dmax = luaL_check_number(i); - while (lua_getparam(++i) != LUA_NOOBJECT) - { - double d = luaL_check_number(i); - if (d > dmax) dmax = d; - } - lua_pushnumber (dmax); -} - -static void math_log (void) -{ - double d = luaL_check_number(1); - lua_pushnumber (log(d)); -} - - -static void math_log10 (void) -{ - double d = luaL_check_number(1); - lua_pushnumber (log10(d)); -} - - -static void math_exp (void) -{ - double d = luaL_check_number(1); - lua_pushnumber (exp(d)); -} - -static void math_deg (void) -{ - float d = luaL_check_number(1); - lua_pushnumber (d*180./PI); -} - -static void math_rad (void) -{ - float d = luaL_check_number(1); - lua_pushnumber (d/180.*PI); -} - -static void math_random (void) -{ - lua_pushnumber((double)(rand()%RAND_MAX) / (double)RAND_MAX); -} - -static void math_randomseed (void) -{ - srand(luaL_check_number(1)); -} - - -static struct luaL_reg mathlib[] = { -{"abs", math_abs}, -{"sin", math_sin}, -{"cos", math_cos}, -{"tan", math_tan}, -{"asin", math_asin}, -{"acos", math_acos}, -{"atan", math_atan}, -{"atan2", math_atan2}, -{"ceil", math_ceil}, -{"floor", math_floor}, -{"mod", math_mod}, -{"sqrt", math_sqrt}, -{"min", math_min}, -{"max", math_max}, -{"log", math_log}, -{"log10", math_log10}, -{"exp", math_exp}, -{"deg", math_deg}, -{"rad", math_rad}, -{"random", math_random}, -{"randomseed", math_randomseed} -}; - -/* -** Open math library -*/ -void mathlib_open (void) -{ - luaL_openlib(mathlib, (sizeof(mathlib)/sizeof(mathlib[0]))); - lua_pushcfunction(math_pow); - lua_pushnumber(0); /* to get its tag */ - lua_settagmethod(lua_tag(lua_pop()), "pow"); -} - diff --git a/clients/lib/strlib.c b/clients/lib/strlib.c deleted file mode 100644 index bd41693..0000000 --- a/clients/lib/strlib.c +++ /dev/null @@ -1,535 +0,0 @@ -/* -** strlib.c -** String library to LUA -*/ - -char *rcs_strlib="$Id: strlib.c,v 1.46 1997/06/19 18:49:40 roberto Exp $"; - -#include -#include -#include -#include - -#include "lua.h" -#include "auxlib.h" -#include "lualib.h" - - -struct lbuff { - char *b; - size_t max; - size_t size; -}; - -static struct lbuff lbuffer = {NULL, 0, 0}; - - -static char *strbuffer (unsigned long size) -{ - if (size > lbuffer.max) { - /* ANSI "realloc" doesn't need this test, but some machines (Sun!) - don't follow ANSI */ - lbuffer.b = (lbuffer.b) ? realloc(lbuffer.b, lbuffer.max=size) : - malloc(lbuffer.max=size); - if (lbuffer.b == NULL) - lua_error("memory overflow"); - } - return lbuffer.b; -} - -static char *openspace (unsigned long size) -{ - char *buff = strbuffer(lbuffer.size+size); - return buff+lbuffer.size; -} - -char *luaI_addchar (int c) -{ - if (lbuffer.size >= lbuffer.max) - strbuffer(lbuffer.max == 0 ? 100 : lbuffer.max*2); - lbuffer.b[lbuffer.size++] = c; - return lbuffer.b; -} - -void luaI_emptybuff (void) -{ - lbuffer.size = 0; /* prepare for next string */ -} - - -static void addnchar (char *s, int n) -{ - char *b = openspace(n); - strncpy(b, s, n); - lbuffer.size += n; -} - -static void addstr (char *s) -{ - addnchar(s, strlen(s)); -} - - -/* -** Return the string length -*/ -static void str_len (void) -{ - lua_pushnumber(strlen(luaL_check_string(1))); -} - -/* -** Return the substring of a string -*/ -static void str_sub (void) -{ - char *s = luaL_check_string(1); - long l = strlen(s); - long start = (long)luaL_check_number(2); - long end = (long)luaL_opt_number(3, -1); - if (start < 0) start = l+start+1; - if (end < 0) end = l+end+1; - if (1 <= start && start <= end && end <= l) { - luaI_emptybuff(); - addnchar(s+start-1, end-start+1); - lua_pushstring(luaI_addchar(0)); - } - else lua_pushstring(""); -} - -/* -** Convert a string to lower case. -*/ -static void str_lower (void) -{ - char *s; - luaI_emptybuff(); - for (s = luaL_check_string(1); *s; s++) - luaI_addchar(tolower((unsigned char)*s)); - lua_pushstring(luaI_addchar(0)); -} - -/* -** Convert a string to upper case. -*/ -static void str_upper (void) -{ - char *s; - luaI_emptybuff(); - for (s = luaL_check_string(1); *s; s++) - luaI_addchar(toupper((unsigned char)*s)); - lua_pushstring(luaI_addchar(0)); -} - -static void str_rep (void) -{ - char *s = luaL_check_string(1); - int n = (int)luaL_check_number(2); - luaI_emptybuff(); - while (n-- > 0) - addstr(s); - lua_pushstring(luaI_addchar(0)); -} - -/* -** get ascii value of a character in a string -*/ -static void str_ascii (void) -{ - char *s = luaL_check_string(1); - long pos = (long)luaL_opt_number(2, 1) - 1; - luaL_arg_check(0<=pos && pos=0; level--) - if (capture[level].len == -1) return level; - lua_error("invalid pattern capture"); - return 0; /* to avoid warnings */ -} - -static char *matchbalance (char *s, int b, int e) -{ - if (*s != b) return NULL; - else { - int cont = 1; - while (*(++s)) { - if (*s == e) { - if (--cont == 0) return s+1; - } - else if (*s == b) cont++; - } - } - return NULL; /* string ends out of balance */ -} - -static char *match (char *s, char *p, int level) -{ - init: /* using goto's to optimize tail recursion */ - switch (*p) { - case '(': /* start capture */ - if (level >= MAX_CAPT) lua_error("too many captures"); - capture[level].init = s; - capture[level].len = -1; - level++; p++; goto init; /* return match(s, p+1, level); */ - case ')': { /* end capture */ - int l = capture_to_close(level); - char *res; - capture[l].len = s - capture[l].init; /* close capture */ - if ((res = match(s, p+1, level)) == NULL) /* match failed? */ - capture[l].len = -1; /* undo capture */ - return res; - } - case ESC: - if (isdigit((unsigned char)(*(p+1)))) { /* capture */ - int l = check_cap(*(p+1), level); - if (strncmp(capture[l].init, s, capture[l].len) == 0) { - /* return match(p+2, s+capture[l].len, level); */ - p+=2; s+=capture[l].len; goto init; - } - else return NULL; - } - else if (*(p+1) == 'b') { /* balanced string */ - if (*(p+2) == 0 || *(p+3) == 0) - lua_error("bad balanced pattern specification"); - s = matchbalance(s, *(p+2), *(p+3)); - if (s == NULL) return NULL; - else { /* return match(p+4, s, level); */ - p+=4; goto init; - } - } - else goto dflt; - case '\0': case '$': /* (possibly) end of pattern */ - if (*p == 0 || (*(p+1) == 0 && *s == 0)) { - num_captures = level; - return s; - } - else goto dflt; - default: dflt: { /* it is a pattern item */ - int m = luaL_singlematch(*s, p); - char *ep = luaL_item_end(p); /* get what is next */ - switch (*ep) { - case '*': { /* repetition */ - char *res; - if (m && (res = match(s+1, p, level))) - return res; - p=ep+1; goto init; /* else return match(s, ep+1, level); */ - } - case '-': { /* repetition */ - char *res; - if ((res = match(s, ep+1, level)) != 0) - return res; - else if (m) { - s++; - goto init; /* return match(s+1, p, level); */ - } - else - return NULL; - } - case '?': { /* optional */ - char *res; - if (m && (res = match(s+1, ep+1, level))) - return res; - p=ep+1; goto init; /* else return match(s, ep+1, level); */ - } - default: - if (m) { s++; p=ep; goto init; } /* return match(s+1, ep, level); */ - else return NULL; - } - } - } -} - -static void str_find (void) -{ - char *s = luaL_check_string(1); - char *p = luaL_check_string(2); - long init = (long)luaL_opt_number(3, 1) - 1; - luaL_arg_check(0 <= init && init <= strlen(s), 3, "out of range"); - if (lua_getparam(4) != LUA_NOOBJECT || - strpbrk(p, SPECIALS) == NULL) { /* no special caracters? */ - char *s2 = strstr(s+init, p); - if (s2) { - lua_pushnumber(s2-s+1); - lua_pushnumber(s2-s+strlen(p)); - } - } - else { - int anchor = (*p == '^') ? (p++, 1) : 0; - char *s1=s+init; - do { - char *res; - if ((res=match(s1, p, 0)) != NULL) { - lua_pushnumber(s1-s+1); /* start */ - lua_pushnumber(res-s); /* end */ - push_captures(); - return; - } - } while (*s1++ && !anchor); - } -} - -static void add_s (lua_Object newp, lua_Object table, int n) -{ - if (lua_isstring(newp)) { - char *news = lua_getstring(newp); - while (*news) { - if (*news != ESC || !isdigit((unsigned char)*++news)) - luaI_addchar(*news++); - else { - int l = check_cap(*news++, num_captures); - addnchar(capture[l].init, capture[l].len); - } - } - } - else if (lua_isfunction(newp)) { - lua_Object res; - struct lbuff oldbuff; - int status; - lua_beginblock(); - if (lua_istable(table)) { - lua_pushobject(table); - lua_pushnumber(n); - } - push_captures(); - /* function may use lbuffer, so save it and create a new one */ - oldbuff = lbuffer; - lbuffer.b = NULL; lbuffer.max = lbuffer.size = 0; - status = lua_callfunction(newp); - /* restore old buffer */ - free(lbuffer.b); - lbuffer = oldbuff; - if (status != 0) - lua_error(NULL); - res = lua_getresult(1); - addstr(lua_isstring(res) ? lua_getstring(res) : ""); - lua_endblock(); - } - else luaL_arg_check(0, 3, NULL); -} - -static void str_gsub (void) -{ - char *src = luaL_check_string(1); - char *p = luaL_check_string(2); - lua_Object newp = lua_getparam(3); - lua_Object table = lua_getparam(4); - int max_s = (int)luaL_opt_number(lua_istable(table)?5:4, strlen(src)+1); - int anchor = (*p == '^') ? (p++, 1) : 0; - int n = 0; - luaI_emptybuff(); - while (n < max_s) { - char *e = match(src, p, 0); - if (e) { - n++; - add_s(newp, table, n); - } - if (e && e>src) /* non empty match? */ - src = e; /* skip it */ - else if (*src) - luaI_addchar(*src++); - else break; - if (anchor) break; - } - addstr(src); - lua_pushstring(luaI_addchar(0)); - lua_pushnumber(n); /* number of substitutions */ -} - -static void str_set (void) -{ - char *item = luaL_check_string(1); - int i; - luaL_arg_check(*luaL_item_end(item) == 0, 1, "wrong format"); - luaI_emptybuff(); - for (i=1; i<256; i++) /* 0 cannot be part of a set */ - if (luaL_singlematch(i, item)) - luaI_addchar(i); - lua_pushstring(luaI_addchar(0)); -} - - -void luaI_addquoted (char *s) -{ - luaI_addchar('"'); - for (; *s; s++) { - if (strchr("\"\\\n", *s)) - luaI_addchar('\\'); - luaI_addchar(*s); - } - luaI_addchar('"'); -} - -#define MAX_FORMAT 200 - -static void str_format (void) -{ - int arg = 1; - char *strfrmt = luaL_check_string(arg++); - luaI_emptybuff(); /* initialize */ - while (*strfrmt) { - if (*strfrmt != '%') - luaI_addchar(*strfrmt++); - else if (*++strfrmt == '%') - luaI_addchar(*strfrmt++); /* %% */ - else { /* format item */ - char form[MAX_FORMAT]; /* store the format ('%...') */ - char *buff; - char *initf = strfrmt-1; /* -1 to include % */ - strfrmt = match(strfrmt, "[-+ #]*(%d*)%.?(%d*)", 0); - if (capture[0].len > 3 || capture[1].len > 3) /* < 1000? */ - lua_error("invalid format (width or precision too long)"); - strncpy(form, initf, strfrmt-initf+1); /* +1 to include convertion */ - form[strfrmt-initf+1] = 0; - buff = openspace(1000); /* to store the formated value */ - switch (*strfrmt++) { - case 'q': - luaI_addquoted(luaL_check_string(arg++)); - continue; - case 's': { - char *s = luaL_check_string(arg++); - buff = openspace(strlen(s)); - sprintf(buff, form, s); - break; - } - case 'c': case 'd': case 'i': case 'o': - case 'u': case 'x': case 'X': - sprintf(buff, form, (int)luaL_check_number(arg++)); - break; - case 'e': case 'E': case 'f': case 'g': - sprintf(buff, form, luaL_check_number(arg++)); - break; - default: /* also treat cases 'pnLlh' */ - lua_error("invalid format option in function `format'"); - } - lbuffer.size += strlen(buff); - } - } - lua_pushstring(luaI_addchar(0)); /* push the result */ -} - - -static struct luaL_reg strlib[] = { -{"strlen", str_len}, -{"strsub", str_sub}, -{"strset", str_set}, -{"strlower", str_lower}, -{"strupper", str_upper}, -{"strrep", str_rep}, -{"ascii", str_ascii}, -{"format", str_format}, -{"strfind", str_find}, -{"gsub", str_gsub} -}; - - -/* -** Open string library -*/ -void strlib_open (void) -{ - luaL_openlib(strlib, (sizeof(strlib)/sizeof(strlib[0]))); -} diff --git a/clients/lua/README b/clients/lua/README deleted file mode 100644 index c529892..0000000 --- a/clients/lua/README +++ /dev/null @@ -1,5 +0,0 @@ -This client is a simple lua interpreter. -It either loads and executes the files named on the command line or reads -and executes lines from stdin. -Note that, in the second case, each line must contain a complete statement. -For instance, functions cannot span several lines. diff --git a/clients/lua/lua.c b/clients/lua/lua.c deleted file mode 100644 index afa2b56..0000000 --- a/clients/lua/lua.c +++ /dev/null @@ -1,141 +0,0 @@ -/* -** lua.c -** Linguagem para Usuarios de Aplicacao -*/ - -char *rcs_lua="$Id: lua.c,v 1.18 1997/06/19 18:55:40 roberto Exp $"; - -#include -#include - -#include "lua.h" -#include "auxlib.h" -#include "lualib.h" - - -#ifdef _POSIX_SOURCE -#include -#else -#define isatty(x) (x==0) /* assume stdin is a tty */ -#endif - - -#define DEBUG 0 - -static void testC (void) -{ -#if DEBUG -#define getnum(s) ((*s++) - '0') -#define getname(s) (nome[0] = *s++, nome) - - static int locks[10]; - lua_Object reg[10]; - char nome[2]; - char *s = luaL_check_string(1); - nome[1] = 0; - while (1) { - switch (*s++) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - lua_pushnumber(*(s-1) - '0'); - break; - - case 'c': reg[getnum(s)] = lua_createtable(); break; - - case 'P': reg[getnum(s)] = lua_pop(); break; - - case 'g': { int n = getnum(s); reg[n] = lua_getglobal(getname(s)); break; } - - case 'G': { int n = getnum(s); - reg[n] = lua_rawgetglobal(getname(s)); - break; - } - - case 'l': locks[getnum(s)] = lua_ref(1); break; - case 'L': locks[getnum(s)] = lua_ref(0); break; - - case 'r': { int n = getnum(s); reg[n] = lua_getref(locks[getnum(s)]); break; } - - case 'u': lua_unref(locks[getnum(s)]); break; - - case 'p': { int n = getnum(s); reg[n] = lua_getparam(getnum(s)); break; } - - case '=': lua_setglobal(getname(s)); break; - - case 's': lua_pushstring(getname(s)); break; - - case 'o': lua_pushobject(reg[getnum(s)]); break; - - case 'f': lua_call(getname(s)); break; - - case 'i': reg[getnum(s)] = lua_gettable(); break; - - case 'I': reg[getnum(s)] = lua_rawgettable(); break; - - case 't': lua_settable(); break; - - case 'T': lua_rawsettable(); break; - - default: luaL_verror("unknown command in `testC': %c", *(s-1)); - - } - if (*s == 0) return; - if (*s++ != ' ') lua_error("missing ` ' between commands in `testC'"); - } -#else - lua_error("`testC' not active"); -#endif -} - - -static void manual_input (void) -{ - if (isatty(0)) { - char buffer[250]; - while (fgets(buffer, sizeof(buffer), stdin) != 0) { - lua_beginblock(); - lua_dostring(buffer); - lua_endblock(); - } - } - else - lua_dofile(NULL); /* executes stdin as a file */ -} - - -int main (int argc, char *argv[]) -{ - int i; - int result = 0; - iolib_open (); - strlib_open (); - mathlib_open (); - lua_register("testC", testC); - if (argc < 2) - manual_input(); - else for (i=1; i -Lua 3.0 Reference Manual - Word Index +Lua 3.1 Reference Manual - Word Index @@ -8,58 +8,85 @@

Index

..
+Adjustment
+Assignment
+Basic Expressions
+C pointers
+C2lua
+Coercion
+Comments
+Expressions
+Function Definitions
+Global variables
+Identifiers
+LUA_ANYTAG
+LUA_NOOBJECT
+Literal strings
+Local variables
+Lua Stand-alone
+Numerical constants
+Operator precedence
+PI
+Pre-processor
+Tag Methods
+Types and Tags
+Upvalues
+Visibility
+_INPUT
+_OUTPUT
+_STDERR
+_STDIN
+_STDOUT
abs
acos
add event
-Adjustment
and
appendto
-arg
arguments
+arg
arithmetic operators
arrays
-ascii
asin
assert
-Assignment
associative arrays
atan2
atan
basic types
block
-C pointers
-C2lua
call
captures
ceil
character class
chunk
+clock
closing a file
-Coercion
collectgarbage
-Comments
concatenation event
concatenation
condition expression
constructors
+copytagmethods
cos
date
debug pragma
+deg
div event
dofile
dostring
+eight-bit clean
error method
error
event
execute
exit
exponentiation
-Expressions
file handles
floor
+foreachvar
+foreach
format
+frexp
function call
-Function Definitions
function event
function
gc event
@@ -71,29 +98,25 @@ gettagmethod
gettagmethod
global environment
-Global variables
gsub
gt event
-Identifiers
if-then-else
index event
-_INPUT
+ldexp
le event
-Literal strings
-Local variables
log10
-log
logical operators
+log
lt event
-Lua Stand-alone
lua2C
-LUA_ANYTAG
-luac
-luac
-lua_callfunction
lua_CFunction
+lua_Object
+lua_callfunction
+lua_close
lua_collectgarbage
+lua_copytagmethods
lua_createtable
+lua_dobuffer
lua_dofile
lua_dostring
lua_error
@@ -107,6 +130,7 @@ lua_gettable
lua_gettagmethod
lua_getuserdata
+lua_iolibopen
lua_iscfunction
lua_isfunction
lua_isnil
@@ -115,11 +139,13 @@ lua_istable
lua_isuserdata
lua_lua2C
+lua_mathlibopen
lua_newtag
-LUA_NOOBJECT
-lua_Object
+lua_open
lua_pop
+lua_pushcclosure
lua_pushcfunction
+lua_pushlstring
lua_pushnil
lua_pushnumber
lua_pushobject
@@ -134,11 +160,17 @@ lua_register
lua_seterrormethod
lua_setglobal
+lua_setstate
lua_settable
-lua_settag
lua_settagmethod
+lua_settag
+lua_state
+lua_strlen
+lua_strlibopen
lua_tag
lua_unref
+luac
+luac
max
methods
min
@@ -146,15 +178,12 @@ mul event
multiple assignment
newtag
-next
nextvar
+next
nil
not
number
-Numerical constants
-Operator precedence
or
-_OUTPUT
packed results
pattern item
pattern
@@ -165,17 +194,18 @@ pow event
pre-compilation
predefined functions
-Pre-processor
print
-random
+protected calls
+rad
randomseed
+random
rawgetglobal
rawgettable
rawsetglobal
rawsettable
read pattern
-read
readfrom
+read
records
reference
reflexivity
@@ -189,19 +219,18 @@ self
setglobal event
setglobal
+setlocale
settable event
-settag
settagmethod
settagmethod
+settag
short-cut evaluation
-Simple Expressions
sin
skips
sqrt
statements
-_STDERR
-_STDIN
-_STDOUT
+strbyte
+strchar
strfind
string
strlen
@@ -211,7 +240,6 @@ strupper
sub event
table
-Tag Methods
tag
tag
tan
@@ -220,22 +248,17 @@ tonumber
tostring
type
-Types and Tags
unm event
userdata
vararg
-version 1.1
-version 2.1
-version 2.2
-version 2.4
-version 2.5
+version 3.0
while-do
-write
writeto
+write

Last update: -Tue Jul 1 07:55:45 EST 1997 +Fri Jul 10 15:10:14 EST 1998 by lhf. diff --git a/doc/index.html b/doc/index.html index 5ce16c4..ca4a281 100644 --- a/doc/index.html +++ b/doc/index.html @@ -1,15 +1,17 @@ -Lua 3.0 Reference Manual - Index +Lua 3.1 Reference Manual - Contents -

Reference Manual of the Programming Language Lua 3.0

+

Reference Manual of the Programming Language +Lua +3.1

Roberto Ierusalimschy, Luiz Henrique de Figueiredo, -Waldemar Celes +Waldemar Celes
lua@tecgraf.puc-rio.br
TeCGraf, @@ -17,22 +19,17 @@ PUC-Rio

+[ +top +| +contents +| +index +| +ps +]


-Abstract. -Lua is an extension programming language designed to be used -as a configuration language for any program that needs one. -This document describes version 3.0 of the Lua programming language and -the API that allows interaction between Lua programs and their host C programs. -
- -Sumário. -Lua é uma linguagem de extensão projetada para ser usada como -linguagem de configuração em qualquer programa que precise de uma. -Este documento descreve a versão 3.0 da linguagem de -programação Lua e a Interface de Programação (API) que permite -a interação entre programas Lua e programas C hospedeiros. -
- +
  • 5 - The Application Program Interface
  • 6 - Predefined Functions and Libraries
      @@ -79,7 +78,7 @@ a intera
      Last update: -Tue Jul 1 07:55:45 EST 1997 +Fri Jul 10 15:10:14 EST 1998 by lhf. diff --git a/doc/luac.html b/doc/luac.html dissimilarity index 100% index 7d43ff1..1948e7a 100644 --- a/doc/luac.html +++ b/doc/luac.html @@ -1,88 +1,158 @@ - - - -
      -luac manual page -
      - -Table of Contents

      - -

      NAME

      -luac - Lua compiler

      - -

      SYNOPSIS

      -luac [ -c | -u ] [ -d ] [ -l ] [ -p ] [ -q ] [ -v ] [ -o outputfile ] sourcefile ...

      - -

      DESCRIPTION

      -luac is the Lua compiler. It translates programs written in the Lua programming language into binary files that can be loaded and executed with lua_dofile in C or dofile in Lua.

      -luac produces a single output file containing the bytecode for all named source files. By default, the output file is named luac.out, but you can change this with the -o option.

      -You can use "-" to indicate stdin as a source file.

      -luac can also load and list binary files.

      - -

      OPTIONS

      -
      -
      -c
      compile (this is the default).

      -

      -
      -
      -
      -u
      undump.

      -

      -
      -
      -
      -d
      turns debugging on.

      -

      -
      -
      -
      -l
      produces a listing of the compiled bytecode for Lua's virtual machine. This is the default when undumping.

      -

      -
      -
      -
      -p
      parses sources files but does not generate any output file.

      -

      -
      -
      -
      -q
      quiet; procudes no listing. This is the default when compiling.

      -

      -
      -
      -
      -v
      prints version information.

      -

      -
      -
      -
      -o outputfile
      Name the output file output, instead of the default luac.out. The output file cannot be a source file.

      -

      -
      - -

      FILES

      -
      -
      luac.out
      default output file

      -

      -
      - -

      SEE ALSO

      -lua(1)

      -Reference Manual of the Programming Language Lua

      - -

      DIAGNOSTICS

      -Error messages should be self explanatory.

      - -

      BUGS

      -Inherits any bugs from Lua, but Lua has no bugs...

      - -

      AUTHORS

      -W. Celes, R. Ierusalimschy & L. H. de Figueiredo (lua@tecgraf.puc-rio.br)

      - -


      -Table of Contents

      -

      - + +LUAC 1 "06 February 1998" +

      NAME

      +luac - Lua compiler +

      SYNOPSIS

      +luac +[ +-c +| +-u +] [ +-D +name +] [ +-d +] [ +-l +] [ +-O +] [ +-o +filename +] [ +-p +] [ +-q +] [ +-v +] [ +-V +] +sourcefile ... +

      DESCRIPTION

      +luac +is the Lua compiler. +It translates programs written in the Lua programming language +into binary files that can be loaded and executed with +lua_dofile +in C or with +dofile +in Lua. +

      +The main advantages of pre-compiling chunks are: +faster loading, +protecting source code from user changes, +off-line syntax error detection. +The binary files created by +luac +are portable to all known architectures. +

      +luac +produces a single output file containing the bytecodes +for all source files given. +By default, +the output file is named +luac.out, +but you can change this with the +-o +option. +

      +You can use +"-" +to indicate +stdin +as a source file. +

      +luac +can also load and list binary files with the +-u +option. +

      +Binary files produced by differents runs of +luac +can be combined into one large file, +using +cat(1). +The result is still a valid binary file, +and can be loaded with a single call to +lua_dofile +or +dofile. +

      +

      OPTIONS

      +

      +-c +compile (this is the default). +

      +-u +undump, i.e., load and list the given binary files. +If no files are given, then luac undumps +luac.out. +

      +-D "name" +predefine symbol +name +for conditional compilation. +

      +-d +turn debugging on. +Individual chunks may +still control the generation of debug information with +$debug and $nodebug. +

      +-l +produce a listing of the compiled bytecode for Lua's virtual machine. +This is the default when undumping. +

      +-O +optimize code. +Debug information is removed, +duplicate constants are coalesced. +

      +-o "filename" +output to +filename, +instead of the default +luac.out. +The output file cannot be a source file. +

      +-p +parse sources files but does not generate any output file. +Used mainly for syntax checking. +

      +-q +quiet; produces no listing. +This is the default when compiling. +

      +-v +print version information. +

      +-V +verbose; +print the names of the source files as they are processed. +

      FILES

      +

      +luac.out +default output file +

      "SEE ALSO"

      +lua(1) +
      +"Reference Manual of the Programming Language Lua" +
      +http://www.tecgraf.puc-rio.br/lua/ +
      +"Lua: an extensible extension language", +Software: Practice & Experience +26 +#6 (1996) 635-652. +

      DIAGNOSTICS

      +Error messages should be self explanatory. +

      BUGS

      +Inherits any bugs from Lua, +but Lua has no bugs... +

      AUTHORS

      +L. H. de Figueiredo, +R. Ierusalimschy and +W. Celes +(lua@tecgraf.puc-rio.br) diff --git a/doc/luac.man b/doc/luac.man new file mode 100644 index 0000000..e5c9073 --- /dev/null +++ b/doc/luac.man @@ -0,0 +1,165 @@ +.\" $Id: luac.man,v 1.11 1998/07/01 14:51:45 lhf Exp $ +.TH LUAC 1 "01 July 1998" +.SH NAME +luac \- Lua compiler +.SH SYNOPSIS +.B luac +[ +.B \-c +| +.B \-u +] [ +.B \-d +] [ +.B \-D +.I name +] [ +.B \-l +] [ +.B \-o +.I filename +] [ +.B \-O +] [ +.B \-p +] [ +.B \-q +] [ +.B \-v +] [ +.B \-V +] +.IR sourcefile " ..." +.SH DESCRIPTION +.B luac +is the Lua compiler. +It translates programs written in the Lua programming language +into binary files that can be loaded and executed with +.B lua_dofile +in C or with +.B dofile +in Lua. +.LP +The main advantages of pre-compiling chunks are: +faster loading, +protecting source code from user changes, +off-line syntax error detection. +The binary files created by +.B luac +are portable to all known architectures. +.LP +.B luac +produces a single output file containing the bytecodes +for all source files given. +By default, +the output file is named +.BR luac.out , +but you can change this with the +.B \-o +option. +.LP +You can use +.B "\-" +to indicate +.I stdin +as a source file. +.LP +.B luac +can also load and list binary files with the +.B \-u +option. +.LP +Binary files produced by differents runs of +.B luac +can be combined into one large file, +using +.BR cat (1). +The result is still a valid binary file, +and can be loaded with a single call to +.B lua_dofile +or +.BR dofile . +.LP +.SH OPTIONS +.TP +.B \-c +compile (this is the default). +.TP +.B \-u +undump, i.e., load and list the given binary files. +If no files are given, then luac undumps +.BR luac.out . +.TP +.BI \-D " name" +predefine symbol +.I name +for conditional compilation. +By default, +.B luac +does +.I not +predefine any symbols, +not even the built-in functions. +.TP +.B \-d +turn debugging on. +Individual chunks may +still control the generation of debug information with +$debug and $nodebug. +If debugging is on, then listings show the names of the local variables. +.TP +.B \-l +produce a listing of the compiled bytecode for Lua's virtual machine. +This is the default when undumping. +.TP +.B \-O +optimize code. +Debug information is removed, +duplicate constants are coalesced. +.TP +.BI \-o " filename" +output to +.IR filename , +instead of the default +.BR luac.out . +The output file cannot be a source file. +.TP +.B \-p +parse sources files but does not generate any output file. +Used mainly for syntax checking. +.TP +.B \-q +quiet; produces no listing. +This is the default when compiling. +.TP +.B \-v +print version information. +.TP +.B \-V +verbose; +print the names of the source files as they are processed. +.SH FILES +.TP 15 +.B luac.out +default output file +.SH "SEE ALSO" +.BR lua (1) +.br +.I "Reference Manual of the Programming Language Lua" +.br +http://www.tecgraf.puc-rio.br/lua/ +.br +"Lua: an extensible extension language", +.I Software: Practice & Experience +.B 26 +#6 (1996) 635-652. +.SH DIAGNOSTICS +Error messages should be self explanatory. +.SH BUGS +Inherits any bugs from Lua, +but Lua has no bugs... +.SH AUTHORS +L. H. de Figueiredo, +R. Ierusalimschy and +W. Celes +.I (lua@tecgraf.puc-rio.br) diff --git a/doc/manual.html b/doc/manual.html index 0c3f531..8707ec2 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1,8 +1,8 @@ -Lua 3.0 Reference Manual +Lua 3.1 Reference Manual -

      Lua 3.0 Reference Manual

      +

      Lua 3.1 Reference Manual


      @@ -12,7 +12,7 @@ Lua is an extension programming language designed to support general procedural programming with data description facilities. -It is intended to be used as a light-weight, but powerful, +Lua is intended to be used as a light-weight, but powerful, configuration language for any program that needs one. Lua has been designed and implemented by W. Celes, @@ -32,13 +32,13 @@ thus creating customized programming languages sharing a syntactical framework.

      Lua is free-distribution software, and provided as usual with no guarantees, -as stated in the copyright notice in the front page of this manual. +as stated in the copyright notice. The implementation described in this manual is available at the following URL's: -

      +
          http://www.tecgraf.puc-rio.br/lua/
          ftp://ftp.tecgraf.puc-rio.br/pub/lua/lua.tar.gz
      -
      +

      @@ -47,14 +47,16 @@ at the following URL's:

      2 - Environment and Chunks

      All statements in Lua are executed in a global environment. -This environment, which keeps all global variables and functions, +This environment, which keeps all global variables, is initialized at the beginning of the embedding program and persists until its end. +Optionally, a user can create multiple independent global +environments (see Section 5.1).

      The global environment can be manipulated by Lua code or by the embedding program, which can read and write global variables -using functions in the library that implements Lua. +using functions from the API library that implements Lua.

      Global variables do not need declaration. Any variable is assumed to be global unless explicitly declared local @@ -63,28 +65,24 @@ Before the first assignment, the value of a global variable is nil; this default can be changed (see Section 4.8).

      The unit of execution of Lua is called a chunk. -The syntax -\footnote{As usual, {a} means 0 or more a's, +A chunk is simply a sequence of statements: +

      +chunk ::= {stat} [ret]
      +
      +Statements are described in Section 4.5. +(As usual, {a} means 0 or more a's, [a] means an optional a and ('a)+ means -one or more a's.} -for chunks is: --chunk ::= {stat | function} [ret] - -A chunk may contain statements and function definitions, -and may be in a file or in a string inside the host program. +one or more a's.) +

      +A chunk may be in a file or in a string inside the host program. A chunk may optionally end with a return statement (see Section 4.5.3). -When a chunk is executed, first all its functions and statements are compiled, +When a chunk is executed, first all its code is pre-compiled, then the statements are executed in sequential order. All modifications a chunk effects on the global environment persist after its end. -Those include modifications to global variables and definitions -of new functions -\footnote{Actually, a function definition is an -assignment to a global variable (see Section 3).}.

      -Chunks may be pre-compiled into binary form; -see program luac for details. +Chunks may also be pre-compiled into binary form; +see program luac for details. Text files with chunks and their binary pre-compiled forms are interchangeable. Lua automatically detects the file type and acts accordingly. @@ -106,29 +104,30 @@ There are six basic types in Lua: ni string, function, userdata, and table. Nil is the type of the value nil, whose main property is to be different from any other value. -Number represents real (floating-point) numbers, +Number represents real (double precision floating point) numbers, while string has the usual meaning. +Lua is eight-bit clean, +and so strings may contain any 8-bit character, +including embedded zeros ('\0'). The function type returns a string describing the type of a given value (see Section 6.1).

      Functions are considered first-class values in Lua. This means that functions can be stored in variables, -passed as arguments to other functions and returned as results. -When a function is defined in Lua, its body is compiled and stored -in a given variable. +passed as arguments to other functions, and returned as results. Lua can call (and manipulate) functions written in Lua and functions written in C. They can be distinguished by their tags: all Lua functions have the same tag, and all C functions have the same tag, -which is different from the tag of a Lua function. +which is different from the tag of Lua functions.

      The type userdata is provided to allow arbitrary C pointers to be stored in Lua variables. It corresponds to a void* and has no pre-defined operations in Lua, besides assignment and equality test. However, by using tag methods, -the programmer may define operations for userdata values +the programmer can define operations for userdata values (see Section 4.8).

      The type table implements associative arrays, @@ -136,6 +135,7 @@ that is, arrays that can be indexed not only with numbers, but with any value (except nil). Therefore, this type may be used not only to represent ordinary arrays, but also symbol tables, sets, records, etc. +Tables are the main data structuring mechanism in Lua. To represent records, Lua uses the field name as an index. The language supports this representation by providing a.name as syntactic sugar for a["name"]. @@ -144,23 +144,25 @@ Because functions are first class values, table fields may contain functions. The form t:f(x) is syntactic sugar for t.f(t,x), which calls the method f from the table t passing -itself as the first parameter (see Section 4.7). +itself as the first parameter (see Section 4.6.9).

      -It is important to notice that tables are objects, and not values. +Note that tables are objects, and not values. Variables cannot contain tables, only references to them. -Assignment, parameter passing and returns always manipulate references +Assignment, parameter passing, and returns always manipulate references to tables, and do not imply any kind of copy. Moreover, tables must be explicitly created before used (see Section 4.6.7).

      Tags are mainly used to select tag methods when -some events occur (see Section 4.8). -Each of the types nil, number and string has a different tag. +some events occur. +Tag methods are the main mechanism for extending the +semantics of Lua (see Section 4.8). +Each of the types nil, number and string has a different tag. All values of each of these types have this same pre-defined tag. -Values of type function can have two different tags, +Values of type function can have two different tags, depending on whether they are Lua or C functions. Finally, -values of type userdata and table can have +values of type userdata and table can have as many different tags as needed (see Section 4.8). Tags are created with the function newtag, and the function tag returns the tag of a given value. @@ -180,69 +182,101 @@ This section describes the lexis, the syntax and the semantics of Lua.

      4.1 - Lexical Conventions

      -Lua is a case-sensitive language. -Identifiers can be any string of letters, digits, and underscores, +Identifiers in Lua can be any string of letters, +digits, and underscores, not beginning with a digit. +The definition of letter depends on the current locale: +Any character considered alphabetic by the current locale +can be used in an identifier. The following words are reserved, and cannot be used as identifiers: -

      +
             and       do        else      elseif
             end       function  if        local
             nil       not       or        repeat
             return    then      until     while
      -
      + +Lua is a case-sensitive language: +and is a reserved word, but And and \'and +(if the locale permits) are two other different identifiers. +As a convention, identifiers starting with underscore followed by +uppercase letters should not be used in regular programs.

      The following strings denote other tokens: -

      - ~= <= >= < > == = .. + - * / - % ( ) { } [ ] ; , . ... - +
      +         ~=  <=  >=  <   >   ==  =   +   -   *   /   
      +         (   )   {   }   [   ]   ;   ,   .   ..  ...
      +

      Literal strings can be delimited by matching single or double quotes, and can contain the C-like escape sequences -'\n', '\t' and '\r'. +'\a' (bell), +'\b' (back space), +'\f' (form feed), +'\n' (new line), +'\r' (carriage return), +'\t' (horizontal tab), +'\v' (vertical tab), +'\\', (backslash), +'\"', (double quote), +and '\'' (single quote). +A character in a string may also be specified by its numerical value, +through the escape sequence '\ddd', +where ddd is a sequence of up to three decimal digits. +Strings in Lua may contain any 8-bit value, including embedded 0. +

      Literal strings can also be delimited by matching [[ ... ]]. Literals in this bracketed form may run for several lines, may contain nested [[ ... ]] pairs, and do not interpret escape sequences. This form is specially convenient for -handling strings that contain program pieces or +writing strings that contain program pieces or other quoted strings. +As an example, in a system using ASCII, +the following three literals are equivalent: +

      +1) "alo\n123\""
      +2) '\97lo\10\04923"'
      +3) [[alo
      +   123"]]
      +
      +

      Comments start anywhere outside a string with a double hyphen (--) and run until the end of the line. Moreover, -the first line of a chunk file is skipped if it starts with # -\footnote{This facility allows the use of Lua as a script interpreter -in Unix systems (see Section 8).}. +the first line of a chunk is skipped if it starts with #. +This facility allows the use of Lua as a script interpreter +in Unix systems (see Section 8).

      Numerical constants may be written with an optional decimal part, and an optional decimal exponent. Examples of valid numerical constants are: -

      +
              4     4.0     0.4     4.57e-3     0.3e12
      -
      +

      4.2 - The Pre-processor

      -All lines that start with a $ are handled by a pre-processor. -The $ can be followed by any of the following directives: +All lines that start with a $ sign are handled by a pre-processor. +The $ sign must be immediately +followed by one of the following directives:

      -
      debug
      - turn on some debugging facilities (see Section 4.9). -
      nodebug
      - turn off some debugging facilities (see Section 4.9). +
      debug
      - turn on debugging facilities (see Section 4.9). +
      nodebug
      - turn off debugging facilities (see Section 4.9).
      if cond
      - starts a conditional part. If cond is false, then this part is skipped by the lexical analyzer.
      ifnot cond
      - starts a conditional part. If cond is true, then this part is skipped by the lexical analyzer.
      end
      - ends a conditional part.
      else
      - starts an ``else'' conditional part, -switching the ``skip'' status. +flipping the ``skip'' status.
      endinput
      - ends the lexical parse of the file.

      -Directives can be freely nested. +Directives may be freely nested. Particularly, a $endinput may occur inside a $if; in that case, even the matching $end is not parsed.

      @@ -252,7 +286,7 @@ A cond part may be:

      1
      - always true.
      name
      - true if the value of the global variable name is different from nil. -Notice that name is evaluated before the chunk starts its execution. +Note that name is evaluated before the chunk starts its execution. Therefore, actions in a chunk do not affect its own conditional directives.

      @@ -260,7 +294,7 @@ Therefore, actions in a chunk do not affect its own conditional directives.

      4.3 - Coercion

      -Lua provides some automatic conversions between values. +Lua provides some automatic conversions between values at run time. Any arithmetic operation applied to a string tries to convert that string to a number, following the usual rules. Conversely, whenever a number is used when a string is expected, @@ -283,12 +317,15 @@ the system does not know how many values a function will return, or how many parameters it needs. Therefore, sometimes, a list of values must be adjusted, at run time, to a given length. -If there are more values than are needed, then the last values are thrown away. -If there are more needs than values, then the list is extended with as -many nil's as needed. -Adjustment occurs in multiple assignment and function calls. +If there are more values than are needed, +then the last values are thrown away. +If there are more needs than values, +then the list is extended with as many nil's as needed. +Adjustment occurs in multiple assignment (see Section 4.5.2) +and function calls (see Section 4.6.8).

      +

      4.5 - Statements

      @@ -302,15 +339,21 @@ and local variable declarations (see Section 4.5.5)

      4.5.1 - Blocks

      A block is a list of statements, which are executed sequentially. -Any statement can be optionally followed by a semicolon: -+A statement may be optionally followed by a semicolon: +
       block ::= {stat sc} [ret]
       sc ::= [';']
      -
      + For syntactic reasons, a return statement can only be written as the last statement of a block. This restriction also avoids some ``statement not reached'' conditions.

      +A block may be explicitly delimited: +

      +stat ::= do block end
      +
      +This is useful to control the scope of local variables (see Section 4.5.5). +

      4.5.2 - Assignment

      The language allows multiple assignment. @@ -318,32 +361,39 @@ Therefore, the syntax for assignment defines a list of variables on the left side, and a list of expressions on the right side. Both lists have their elements separated by commas: -+
       stat ::= varlist1 '=' explist1
       varlist1 ::= var {',' var}
      -
      + This statement first evaluates all values on the right side and eventual indices on the left side, and then makes the assignments. Therefore, it can be used to exchange two values, as in -+
          x, y = y, x
      -
      + The two lists may have different lengths. Before the assignment, the list of values is adjusted to the length of the list of variables (see Section 4.4).

      A single name can denote a global or a local variable, or a formal parameter: -

      +
       var ::= name
      -
      + Square brackets are used to index a table: --var ::= var '[' exp1 ']' - -The var should result in a table value, -where the field indexed by the expression value gets the assigned value. +
      +var ::= simpleexp '[' exp1 ']'
      +
      +The simpleexp should result in a table value, +from where the field indexed by the expression +value gets the assigned value. +

      +The syntax var.NAME is just syntactic sugar for +var["NAME"]: +

      +var ::= simpleexp '.' name
      +

      The meaning of assignments and evaluations of global variables and indexed variables can be changed by tag methods (see Section 4.8). @@ -352,15 +402,9 @@ an assignment x = val, where x is a global variable, is equivalent to a call setglobal('x', val); an assignment t[i] = val is equivalent to settable_event(t, i, val). -See Section 4.8 for a description of these functions -\footnote{Function setglobal is pre-defined in Lua. -Function settable_event is used only for explanation purposes.}. -

      -The syntax var.NAME is just syntactic sugar for -var["NAME"]: -

      -var ::= var '.' name - +See Section 4.8 for a complete description of these functions. +(Function setglobal is pre-defined in Lua. +Function settable_event is used only for explanatory purposes.)

      4.5.3 - Control Structures

      The condition expression of a control structure may return any value. @@ -369,28 +413,28 @@ only nil is considered false. if's, while's and repeat's have the usual meaning.

      -

      +
       stat ::= while exp1 do block end 
      | repeat block until exp1
      | if exp1 then block {elseif} [else block] end elseif ::= elseif exp1 then block -
      +

      -A return is used to return values from a function or a chunk. +A return is used to return values from a function or from a chunk. Because they may return more than one value, the syntax for a return statement is: -

      +
       ret ::= return [explist1] [sc]
      -
      +

      4.5.4 - Function Calls as Statements

      Because of possible side-effects, function calls can be executed as statements: -+
       stat ::= functioncall
      -
      -In this case, returned values are thrown away. + +In this case, all returned values are thrown away. Function calls are explained in Section 4.6.8.

      @@ -399,11 +443,11 @@ Function calls are explained in Section 4.6.8. Their scope begins after the declaration and lasts until the end of the block. The declaration may include an initial assignment: -

      +
       stat ::= local declist [init]
       declist ::= name {',' name}
       init ::= '=' explist1
      -
      + If present, an initial assignment has the same semantics of a multiple assignment. Otherwise, all variables are initialized with nil. @@ -412,32 +456,42 @@ Otherwise, all variables are initialized with nil.

      4.6 - Expressions

      -

      4.6.1 - Simple Expressions

      -Simple expressions are: -+

      4.6.1 - Basic Expressions

      +Basic expressions are: +
       exp ::= '(' exp ')'
       exp ::= nil
       exp ::= 'number'
       exp ::= 'literal'
      -exp ::= var
      -
      +exp ::= function +exp ::= simpleexp + +
      +simpleexp ::= var
      +simpleexp ::= upvalue
      +simpleexp ::= functioncall
      +
      +

      Numbers (numerical constants) and -string literals are explained in Section 4.1. -Variables are explained in Section 4.5.2. +string literals are explained in Section 4.1; +variables are explained in Section 4.5.2; +upvalues are explained in Section 4.7; +function definitions (function) are explained in Section 4.6.9; +function call are explained in Section 4.6.8.

      An access to a global variable x is equivalent to a call getglobal('x'); an access to an indexed variable t[i] is equivalent to a call gettable_event(t, i). -See Section 4.8 for a description of these functions -\footnote{Function getglobal is pre-defined in Lua. -Function gettable_event is used only for explanation purposes.}. +See Section 4.8 for a description of these functions. +(Function getglobal is pre-defined in Lua. +Function gettable_event is used only for explanatory purposes.)

      The non-terminal exp1 is used to indicate that the values returned by an expression must be adjusted to one single value: -

      +
       exp1 ::= exp
      -
      +

      4.6.2 - Arithmetic Operators

      Lua supports the usual arithmetic operators: @@ -446,7 +500,7 @@ the binary + (addition), / (division) and ^ (exponentiation), and unary - (negation). If the operands are numbers, or strings that can be converted to -numbers, according to the rules given in Section 4.3, +numbers (according to the rules given in Section 4.3), then all operations except exponentiation have the usual meaning. Otherwise, an appropriate tag method is called (see Section 4.8). An exponentiation always calls a tag method. @@ -456,12 +510,12 @@ giving the expected meaning to exponentiation

      4.6.3 - Relational Operators

      Lua provides the following relational operators: -+
              <   >   <=  >=  ~=  ==
      -
      + All these return nil as false and a value different from nil as true.

      -Equality first compares the types of its operands. +Equality first compares the tags of its operands. If they are different, then the result is nil. Otherwise, their values are compared. Numbers and strings are compared in the usual way. @@ -470,22 +524,24 @@ that is, two tables are considered equal only if they are the same table. The operator ~= is exactly the negation of equality (==). Note that the conversion rules of Section 4.3 do not apply to equality comparisons. -Thus, "0"==0 evaluates to false. +Thus, "0"==0 evaluates to false, +and t[0] and t["0"] denote different +entries in a table.

      The other operators work as follows. If both arguments are numbers, then they are compared as such. Otherwise, if both arguments are strings, -their values are compared using lexicographical order. +then their values are compared using lexicographical order. Otherwise, the ``order'' tag method is called (see Section 4.8).

      4.6.4 - Logical Operators

      -Like control structures, all logical operators -consider nil as false and anything else as true. The logical operators are: -+
                    and   or   not
      -
      + +Like control structures, all logical operators +consider nil as false and anything else as true. The operator and returns nil if its first argument is nil; otherwise, it returns its second argument. The operator or returns its first argument @@ -495,17 +551,25 @@ Both and and or use sho that is, the second operand is evaluated only when necessary.

      +A useful Lua idiom is x = x or v, +which is equivalent to +

      +      if x == nil then x = v end
      +
      +i.e., it sets x to a default value v when +x is not set. +

      4.6.5 - Concatenation

      -Lua offers a string
      concatenation operator, +The string concatenation operator in Lua is denoted by ``..''. -If operands are strings or numbers, then they are converted to +If both operands are strings or numbers, they are converted to strings according to the rules in Section 4.3. Otherwise, the ``concat'' tag method is called (see Section 4.8).

      4.6.6 - Precedence

      Operator precedence follows the table below, from the lower to the higher priority: -+
                    and   or
                    <   >   <=  >=  ~=  ==
                    ..
      @@ -513,7 +577,7 @@ from the lower to the higher priority:
                    *   /
                    not  - (unary)
                    ^
      -
      + All binary operators are left associative, except for ^ (exponentiation), which is right associative. @@ -526,87 +590,108 @@ Constructors can be used to create empty tables, or to create a table and initialize some fields.

      The general syntax for constructors is: -

      +
       tableconstructor ::= '{' fieldlist '}'
      -fieldlist ::= lfieldlist | ffieldlist | lfieldlist ';' ffieldlist
      +fieldlist ::= lfieldlist | ffieldlist | lfieldlist ';' ffieldlist | ffieldlist ';' lfieldlist
       lfieldlist ::= [lfieldlist1]
       ffieldlist ::= [ffieldlist1]
      -
      +

      The form lfieldlist1 is used to initialize lists. -

      +
       lfieldlist1 ::= exp {',' exp} [',']
      -
      + The expressions in the list are assigned to consecutive numerical indices, starting with 1. For example: -+
          a = {"v1", "v2", 34}
      -
      -is essentially equivalent to: -- temp = {} - temp[1] = "v1" - temp[2] = "v2" - temp[3] = 34 - a = temp - + +is equivalent to: +
      +  do
      +    local temp = {}
      +    temp[1] = "v1"
      +    temp[2] = "v2"
      +    temp[3] = 34
      +    a = temp
      +  end
      +

      The form ffieldlist1 initializes other fields in a table: -

      +
       ffieldlist1 ::= ffield {',' ffield} [',']
      -ffield ::= '[' exp ']' \ter {= exp | name '=' exp}
      -
      +ffield ::= '[' exp ']' '=' exp | name '=' exp + For example: -+
          a = {[f(k)] = g(y), x = 1, y = 3, [0] = b+c}
      -
      -is essentially equivalent to: -- temp = {} - temp[f(k)] = g(y) - temp.x = 1 -- or temp["x"] = 1 - temp.y = 3 -- or temp["y"] = 3 - temp[0] = b+c - a = temp - + +is equivalent to: +
      +  do
      +    local temp = {}
      +    temp[f(k)] = g(y)
      +    temp.x = 1    -- or temp["x"] = 1
      +    temp.y = 3    -- or temp["y"] = 3
      +    temp[0] = b+c
      +    a = temp
      +  end
      +
      An expression like {x = 1, y = 4} is in fact syntactic sugar for {["x"] = 1, ["y"] = 4}.

      +Both forms may have an optional trailing comma, +and can be used in the same constructor separated by +a semi-collon. +For example, all forms below are correct: +

      +   x = {;}
      +   x = {'a', 'b',}
      +   x = {type='list'; 'a', 'b'}
      +   x = {f(0), f(1), f(2),; n=3}
      +
      +

      4.6.8 - Function Calls

      A function call has the following syntax: --functioncall ::= var realParams - -Here, var can be any variable (global, local, indexed, etc). +
      +functioncall ::= simpleexp args
      +
      +First, simpleexp is evaluated. If its value has type function, -then this function is called. +then this function is called, +with the given arguments. Otherwise, the ``function'' tag method is called, -having as first parameter the value of var, +having as first parameter the value of simpleexp, and then the original call parameters.

      The form: -

      -functioncall ::= var ':' name realParams - +
      +functioncall ::= simpleexp ':' name args
      +
      can be used to call ``methods''. -A call var:name(...) +A call simpleexp:name(...) is syntactic sugar for -- var.name(var, ...) - -except that var is evaluated only once. -

      -

      -realParams ::= '(' [explist1] ')' -realParams ::= tableconstructor +
      +  simpleexp.name(simpleexp, ...)
      +
      +except that simpleexp is evaluated only once. +

      +

      +args ::= '(' [explist1] ')'
      +args ::= tableconstructor
      +args ::= 'literal'
       explist1 ::= exp1 {',' exp1}
      -
      + All argument expressions are evaluated before the call. A call of the form f{...} is syntactic sugar for f({...}), that is, the parameter list is a single new table. +A call of the form f'...' +(or f"..." or f[[...]]) is syntactic sugar for +f('...'), that is, +the parameter list is a single literal string.

      Because a function can return any number of results (see Section 4.5.3), @@ -621,32 +706,58 @@ thus discarding all returned values but the first one. If the function is called in a place that can hold many values (syntactically denoted by the non-terminal exp), then no adjustment is made. -

      +Note that the only place that can hold many values +is the last expression (or the only one) in an assignment +or in a return statement; see examples below. +

      +      f();  -- adjusted to 0
      +      g(x, f());     -- f() is adjusted to 1
      +      a,b,c = f(), x;   -- f() is adjusted to 1 result (and c gets nil)
      +      a,b,c = x, f();   -- f() is adjusted to 2
      +      a,b,c = f();   -- f() is adjusted to 3
      +      return f();   -- returns all values returned by f()
      +

      - -

      4.7 - Function Definitions

      +

      4.6.9 - Function Definitions

      -Functions in Lua can be defined anywhere in the global level of a chunk. The syntax for function definition is: -

      -function ::= function var '(' [parlist1] ')' block end - +
      +function ::= function '(' [parlist1] ')' block end
      +stat ::= function funcname '(' [parlist1] ')' block end
      +funcname ::= name | name '.' name
      +
      +The statement: +
      +      function f (...)
      +        ...
      +      end
      +
      +is just syntactic sugar for: +
      +      f = function (...)
      +            ...
      +          end
      +

      +A function definition is an executable expression, +whose value has type function. When Lua pre-compiles a chunk, all its function bodies are pre-compiled, too. -Then, when Lua ``executes'' the function definition, -its body is stored, with type function, -into the variable var. -It is in this sense that -a function definition is an assignment to a global variable. +Then, whenever Lua executes the function definition, +its upvalues are fixed (see Section 4.7), +and the function is instantiated (or ``closed''). +This function instance (or ``closure'') +is the final value of the expression. +Different instances of a same function +may have different upvalues.

      Parameters act as local variables, -initialized with the argument values. -

      +initialized with the argument values: +
       parlist1 ::= '...'
       parlist1 ::= name {',' name} [',' '...']
      -
      + When a function is called, @@ -655,19 +766,19 @@ the length of the list of parameters (see Section 4.4 unless the function is a vararg function, indicated by the dots (...) at the end of its parameter list. A vararg function does not adjust its argument list; -instead, it collects any extra arguments in an implicit parameter, -called arg. +instead, it collects any extra arguments into an implicit parameter, +called arg. This parameter is always initialized as a table, with a field n with the number of extra arguments, and the extra arguments at positions 1, 2, ...

      As an example, suppose definitions like: -

      +
             function f(a, b) end
             function g(a, b, ...) end
      -
      + Then, we have the following mapping from arguments to parameters: -+
             CALL            PARAMETERS
       

      f(3) a=3, b=nil @@ -677,56 +788,97 @@ Then, we have the following mapping from arguments to parameters: g(3) a=3, b=nil, arg={n=0} g(3, 4) a=3, b=4, arg={n=0} g(3, 4, 5, 8) a=3, b=4, arg={5, 8; n=2} -

      +

      Results are returned using the return statement (see Section 4.5.3). If control reaches the end of a function without a return instruction, then the function returns with no results.

      There is a special syntax for defining methods, -that is, functions that have an extra parameter self. -

      -function ::= function var ':' name '(' [parlist1] ')' block end - +that is, functions that have an implicit extra parameter self. +
      +function ::= function name ':' name '(' [parlist1] ')' block end
      +
      Thus, a declaration like -+
       function v:f (...)
         ...
       end
      -
      + is equivalent to --function v.f (self, ...) +
      +v.f = function (self, ...)
         ...
       end
      -
      + that is, the function gets an extra formal parameter called self. -Notice that -the variable v must have been +Note that the variable v must have been previously initialized with a table value.

      + + +

      4.7 - Visibility and Upvalues

      + +

      +A function body may refer to its own local variables +(which includes its parameters) and to global variables, +as long as they are not shadowed by local +variables from enclosing functions. +A function cannot access a local +variable from an enclosing function, +since such variables may no longer exist when the function is called. +However, a function may access the value of a local variable +from an enclosing function, using upvalues. +

      +

      +upvalue ::= '%' name
      +
      +An upvalue is somewhat similar to a variable expression, +but whose value is frozen when the function wherein it +appears is instantiated. +The name used in an upvalue may be the name of any variable visible +at the point where the function is defined. +

      +Here are some examples: +

      +a,b,c = 1,2,3   -- global variables
      +function f (x)
      +  local b   -- x and b are local to f
      +  local g = function (a)
      +    local y  -- a and y are local to g
      +    p = a   -- OK, access local 'a'
      +    p = c   -- OK, access global 'c'
      +    p = b   -- ERROR: cannot access a variable in outer scope
      +    p = %b  -- OK, access frozen value of 'b' (local to 'f')
      +    p = %c  -- OK, access frozen value of global 'c'
      +    p = %y  -- ERROR: 'y' is not visible where 'g' is defined
      +  end  -- g
      +end  -- f
      +
      +

      +

      4.8 - Tag Methods

      Lua provides a powerful mechanism to extend its semantics, called Tag Methods. -A tag method (TM) is a programmer-defined function -that can be called at many key points of the evaluation of a program, -allowing a programmer to change the standard Lua behavior at these points. +A tag method is a programmer-defined function +that is called at specific key points during the evaluation of a program, +allowing the programmer to change the standard Lua behavior at these points. Each of these points is called an event.

      The tag method called for any specific event is selected according to the tag of the values involved in the event (see Section 3). The function settagmethod changes the tag method -associated with a given pair <tag, event>. -Its first parameter is the tag, the second the event name +associated with a given pair (tag, event). +Its first parameter is the tag, the second is the event name (a string, see below), and the third parameter is the new method (a function), or nil to restore the default behavior. -The function returns the previous tag method. +The function returns the previous tag method for that pair. Another function, gettagmethod, receives a tag and an event name and returns the current method associated with the pair. @@ -739,8 +891,8 @@ The function not only shows when a tag method is called, but also its arguments, its results and the default behavior. Please notice that the code shown here is only illustrative; the real behavior is hard coded in the interpreter, -and it is much more efficient than this simulation. -All functions used in these descriptions +and it is much more efficient than this simulation. +All functions used in these descriptions (rawgetglobal, tonumber, call, etc) are described in Section 6.1.

      @@ -751,65 +903,65 @@ called when a + operation is applied to non numerical operands.

      The function getbinmethod defines how Lua chooses a tag method for a binary operation. -First Lua tries the first operand. +First, Lua tries the first operand. If its tag does not define a tag method for the operation, then Lua tries the second operand. If it also fails, then it gets a tag method from tag 0: -

      +
             function getbinmethod (op1, op2, event)
               return gettagmethod(tag(op1), event) or
                      gettagmethod(tag(op2), event) or
                      gettagmethod(0, event)
             end
      -
      -+ +
             function add_event (op1, op2)
               local o1, o2 = tonumber(op1), tonumber(op2)
               if o1 and o2 then  -- both operands are numeric
                 return o1+o2  -- '+' here is the primitive 'add'
      -        else  -- at least one of the operands is not numeric.
      +        else  -- at least one of the operands is not numeric
                 local tm = getbinmethod(op1, op2, "add")
                 if tm then
                   -- call the method with both operands and an extra
                   -- argument with the event name
                   return tm(op1, op2, "add")
      -          else  -- no tag method available: Default behavior
      +          else  -- no tag method available: default behavior
                   error("unexpected type at arithmetic operation")
                 end
               end
             end
      -
      +

      ``sub'':
      called when a - operation is applied to non numerical operands. -Behavior similar to "add" event. +Behavior similar to the "add" event.

      ``mul'':
      called when a * operation is applied to non numerical operands. -Behavior similar to "add" event. +Behavior similar to the "add" event.

      ``div'':
      called when a / operation is applied to non numerical operands. -Behavior similar to "add" event. +Behavior similar to the "add" event.

      ``pow'':
      called when a ^ operation is applied. -+
             function pow_event (op1, op2)
               local tm = getbinmethod(op1, op2, "pow")
               if tm then
                 -- call the method with both operands and an extra
                 -- argument with the event name
                 return tm(op1, op2, "pow")
      -        else  -- no tag method available: Default behavior
      +        else  -- no tag method available: default behavior
                 error("unexpected type at arithmetic operation")
               end
             end
      -
      +

      ``unm'':
      called when an unary - operation is applied to a non numerical operand. -+
             function unm_event (op)
               local o = tonumber(op)
               if o then  -- operand is numeric
      @@ -823,17 +975,17 @@ called when an unary - operation is applied to a non numerical oper
                   -- call the method with the operand, nil, and an extra
                   -- argument with the event name
                   return tm(op, nil, "unm")
      -          else  -- no tag method available: Default behavior
      +          else  -- no tag method available: default behavior
                   error("unexpected type at arithmetic operation")
                 end
               end
             end
      -
      +

      ``lt'':
      called when a < operation is applied to non numerical or non string operands. -+
             function lt_event (op1, op2)
               if type(op1) == "number" and type(op2) == "number" then
                 return op1 < op2   -- numeric comparison
      @@ -848,26 +1000,26 @@ or non string operands.
                 end
               end
             end
      -
      +

      ``gt'':
      called when a > operation is applied to non numerical or non string operands. -Behavior similar to "lt" event. +Behavior similar to the "lt" event.

      ``le'':
      called when a <= operation is applied to non numerical or non string operands. -Behavior similar to "lt" event. +Behavior similar to the "lt" event.

      ``ge'':
      called when a >= operation is applied to non numerical or non string operands. -Behavior similar to "lt" event. +Behavior similar to the "lt" event.

      ``concat'':
      called when a concatenation is applied to non string operands. -+
             function concat_event (op1, op2)
               if (type(op1) == "string" or type(op1) == "number") and
                  (type(op2) == "string" or type(op2) == "number") then
      @@ -881,7 +1033,7 @@ called when a concatenation is applied to non string operands.
                 end
               end
             end
      -
      +

      ``index'':
      called when Lua tries to retrieve the value of an index @@ -889,10 +1041,10 @@ not present in a table. See event "gettable" for its semantics.

      ``getglobal'':
      -called whenever Lua accesses a global variable. +called whenever Lua needs the value of a global variable. This method can only be set for nil and for tags created by newtag. -+
             function getglobal (varname)
               local value = rawgetglobal(varname)
               local tm = gettagmethod(tag(value), "getglobal")
      @@ -902,14 +1054,14 @@ created by newtag.
                 return tm(varname, value)
               end
             end
      -
      -Notice: the function getglobal is pre-defined in Lua (see Section 6.1). + +The function getglobal is pre-defined in Lua (see Section 6.1).

      ``setglobal'':
      called whenever Lua assigns to a global variable. -This method cannot be set for numbers, strings, and tables and +This method cannot be set for numbers, strings, and tables and userdata with default tags. -+
             function setglobal (varname, newvalue)
               local oldvalue = rawgetglobal(varname)
               local tm = gettagmethod(tag(oldvalue), "setglobal")
      @@ -919,13 +1071,13 @@ userdata with default tags.
                 return tm(varname, oldvalue, newvalue)
               end
             end
      -
      + Notice: the function setglobal is pre-defined in Lua (see Section 6.1).

      ``gettable'':
      called whenever Lua accesses an indexed variable. This method cannot be set for tables with default tag. -+
             function gettable_event (table, index)
               local tm = gettagmethod(tag(table), "gettable")
               if tm then
      @@ -935,19 +1087,19 @@ This method cannot be set for tables with default tag.
               else
                 local v = rawgettable(table, index)
                 tm = gettagmethod(tag(table), "index")
      -          if (v == nil) and tm then
      +          if v == nil and tm then
                   return tm(table, index)
                 else
                   return v
                 end
               end
             end
      -
      +

      ``settable'':
      called when Lua assigns to an indexed variable. This method cannot be set for tables with default tag. -+
             function settable_event (table, index, value)
               local tm = gettagmethod(tag(table), "settable")
               if tm then
      @@ -958,11 +1110,11 @@ This method cannot be set for tables with default tag.
                 rawsettable(table, index, value)
               end
             end
      -
      +

      ``function'':
      called when Lua tries to call a non function value. -+
             function function_event (func, ...)
               if type(func) == "function" then
                 return call(func, arg)
      @@ -982,7 +1134,7 @@ called when Lua tries to call a non function value.
                 end
               end
             end
      -
      +

      ``gc'':
      called when Lua is garbage collecting an object. @@ -990,14 +1142,14 @@ This method cannot be set for strings, numbers, functions, and userdata with default tag. For each object to be collected, Lua does the equivalent of the following function: -+
             function gc_event (obj)
               local tm = gettagmethod(tag(obj), "gc")
               if tm then
                 tm(obj)
               end
             end
      -
      + Moreover, at the end of a garbage collection cycle, Lua does the equivalent of the call gc_event(nil).

      @@ -1010,16 +1162,18 @@ Lua does the equivalent of the call gc_event(nil).

      4.9 - Error Handling

      Because Lua is an extension language, -all Lua actions start from C code calling a function from the Lua library. +all Lua actions start from C code in the host program +calling a function from the Lua library. Whenever an error occurs during Lua compilation or execution, the error method is called, and then the corresponding function from the library -(lua_dofile, lua_dostring, or lua_callfunction) -is terminated returning an error condition. +(lua_dofile, lua_dostring, +lua_dobuffer, or lua_callfunction) +is terminated, returning an error condition.

      The only argument to the error method is a string describing the error. -The default method prints this message in stderr. +The default method prints this message to stderr. If needed, it is possible to change the error method with the function seterrormethod, which gets the new error handler as its only parameter @@ -1027,7 +1181,7 @@ which gets the new error handler as its only parameter The standard I/O library uses this facility to redefine the error method, using the debug facilities (see Section 7), in order to print some extra information, -like the call stack. +such as the call stack.

      To provide more information about errors, Lua programs should include the compilation pragma $debug. @@ -1039,6 +1193,9 @@ lines where the calls (and the error) were made.

      Lua code can explicitly generate an error by calling the built-in function error (see Section 6.1). +Lua code can ``catch'' an error using the built-in function +call (see Section 6.1). +

      @@ -1051,6 +1208,7 @@ the set of C functions available to the host program to communicate with the Lua library. The API functions can be classified in the following categories:

        +
      1. managing states;
      2. exchanging values between C and Lua;
      3. executing Lua code;
      4. manipulating (reading and writing) Lua objects; @@ -1061,9 +1219,81 @@ The API functions can be classified in the following categories: All API functions and related types and constants are declared in the header file lua.h.

        - + -

        5.1 - Exchanging Values between C and Lua

        +

        5.1 - Managing States

        +The whole state of the Lua interpreter +(global variables, stack, tag methods, etc) +is stored in a dynamic structure pointed by +
        +typedef struct lua_State lua_State;
        +extern lua_State *lua_state;
        +
        +

        +Before calling any API function, +this state must be initialized. +This is done by calling +

        +void lua_open (void);
        +
        +This function allocates and initializes some internal structures, +and defines all pre-defined functions of Lua. +If lua_state is already different from NULL, +lua_open has no effect; +therefore, it is safe to call this function multiple times. +All standard libraries call lua_open when they are opened. +

        +Function lua_setstate is used to change the current state +of Lua: +

        +lua_State *lua_setstate (lua_State *st);
        +
        +It sets lua_state to st and returns the old state. +

        +Multiple, independent states may be created. +For that, you must set lua_state back to NULL before +calling lua_open. +An easy way to do that is defining an auxiliary function: +

        +lua_State *lua_newstate (void) {
        +  lua_State *old = lua_setstate(NULL);
        +  lua_open();
        +  return lua_setstate(old);
        +}
        +
        +This function creates a new state without changing the current state +of the interpreter. +Note that any new state is built with all predefined functions, +but any additional library (such as the standard libraries) must be +explicitly open in the new state, if needed. +

        +If necessary, a state may be released: +

        +void lua_close (void);
        +
        +This function destroys all objects in the current Lua environment +(calling the correspondent garbage collector tag methods), +frees all dynamic memory used by the state, +and then sets lua_state to NULL. +Usually, there is no need to call this function, +since these resources are naturally released when the program ends. +If lua_state is already NULL, +lua_close has no effect. +

        +If you are using multiple states, +you may find useful the following function, +which releases a given state: +

        +void lua_freestate (lua_State *st) {
        +  lua_State *old = lua_setstate(st);
        +  lua_close();
        +  if (old != st) lua_setstate(old);
        +}
        +
        +

        + + +

        5.2 - Exchanging Values between C and Lua

        Because Lua has no static type system, all values passed between Lua and C have type lua_Object, @@ -1077,65 +1307,73 @@ the following functions are available: --int lua_isnil (lua_Object object); -int lua_isnumber (lua_Object object); -int lua_isstring (lua_Object object); -int lua_istable (lua_Object object); -int lua_isfunction (lua_Object object); -int lua_iscfunction (lua_Object object); -int lua_isuserdata (lua_Object object); - +
        +int lua_isnil       (lua_Object object);
        +int lua_isnumber    (lua_Object object);
        +int lua_isstring    (lua_Object object);
        +int lua_istable     (lua_Object object);
        +int lua_isfunction  (lua_Object object);
        +int lua_iscfunction (lua_Object object);
        +int lua_isuserdata  (lua_Object object);
        +
        All macros return 1 if the object is compatible with the given type, and 0 otherwise. The function lua_isnumber accepts numbers and numerical strings, whereas lua_isstring accepts strings and numbers (see Section 4.3), -and lua_isfunction accepts Lua and C functions. +and lua_isfunction accepts Lua functions and C functions.

        -To check the tag of a lua_Object, +To get the tag of a lua_Object, the following function is available: -

        -int lua_tag (lua_Object object); - +
        +int lua_tag (lua_Object object);
        +

        To translate a value from type lua_Object to a specific C type, the programmer can use: - + -

        -float lua_getnumber (lua_Object object); -char *lua_getstring (lua_Object object); -lua_CFunction lua_getcfunction (lua_Object object); -void *lua_getuserdata (lua_Object object); - +
        +double         lua_getnumber    (lua_Object object);
        +char          *lua_getstring    (lua_Object object);
        +long           lua_strlen       (lua_Object object);
        +lua_CFunction  lua_getcfunction (lua_Object object);
        +void          *lua_getuserdata  (lua_Object object);
        +

        lua_getnumber converts a lua_Object to a floating-point number. This lua_Object must be a number or a string convertible to number -(see Section 4.3); otherwise, the function returns 0. +(see Section 4.3); otherwise, lua_getnumber returns 0.

        lua_getstring converts a lua_Object to a string (char*). This lua_Object must be a string or a number; otherwise, the function returns 0 (the NULL pointer). This function does not create a new string, but returns a pointer to a string inside the Lua environment. +Those strings always have a 0 after their last character (like in C), +but may contain other zeros in their body. +If you do not know whether a string may contain zeros, +you can use lua_strlen to get the actual length. Because Lua has garbage collection, there is no guarantee that such pointer will be valid after the block ends -(see below). +(see Section 5.3).

        lua_getcfunction converts a lua_Object to a C function. This lua_Object must have type CFunction; -otherwise, the function returns 0 (the NULL pointer). -The type lua_CFunction is explained in Section 5.5. +otherwise, lua_getcfunction returns 0 (the NULL pointer). +The type lua_CFunction is explained in Section 5.7.

        lua_getuserdata converts a lua_Object to void*. This lua_Object must have type userdata; -otherwise, the function returns 0 (the NULL pointer). +otherwise, lua_getuserdata returns 0 (the NULL pointer).

        + + +

        5.3 - Garbage Collection

        Because Lua has automatic memory management and garbage collection, a lua_Object has a limited scope, -and is only valid inside the block where it was created. +and is only valid inside the block where it has been created. A C function called from Lua is a block, and its parameters are valid only until its end. It is good programming practice to convert Lua objects to C values @@ -1144,65 +1382,72 @@ and never to store lua_Objects in C global variables.

        A garbage collection cycle can be forced by: -

        -long lua_collectgarbage (long limit); - +
        +long lua_collectgarbage (long limit);
        +
        This function returns the number of objects collected. The argument limit makes the next cycle occur only -when that number of new objects have been created. -If limit=0, then Lua uses an adaptable heuristics to set this limit. +after that number of new objects have been created. +If limit=0, then Lua uses an adaptive heuristics to set this limit.

        All communication between Lua and C is done through two abstract data types, called lua2C and C2lua. The first one, as the name implies, is used to pass values -from Lua to C: parameters when Lua calls C and results when C calls Lua. +from Lua to C: +parameters when Lua calls C and results when C calls Lua. The structure C2lua is used in the reverse direction: parameters when C calls Lua and results when Lua calls C.

        The structure lua2C is an abstract array, which can be indexed with the function: -

        +
         lua_Object lua_lua2C (int number);
        -
        + where number starts with 1. When called with a number larger than the array size, this function returns LUA_NOOBJECT. In this way, it is possible to write C functions that receive a variable number of parameters, and to call Lua functions that return a variable number of results. -Notice that the structure lua2C cannot be directly modified by C code. +Note that the structure lua2C cannot be directly modified by C code.

        -The second structure, C2lua, is a stack. +The second structure, C2lua, is an abstract stack. Pushing elements into this stack -is done with the following functions: - +is done with the following functions and macros: + -

        -void lua_pushnumber (double n); -void lua_pushstring (char *s); -void lua_pushcfunction (lua_CFunction f); -void lua_pushusertag (void *u, int tag); -void lua_pushnil (void); -void lua_pushobject (lua_Object object); - +
        +void lua_pushnumber    (double n);
        +void lua_pushlstring   (char *s, long len);
        +void lua_pushstring    (char *s);
        +void lua_pushusertag   (void *u, int tag);
        +void lua_pushnil       (void);
        +void lua_pushobject    (lua_Object object);
        +void lua_pushcfunction (lua_CFunction f);  /* macro */
        +
        All of them receive a C value, convert it to a corresponding lua_Object, and leave the result on the top of C2lua. +Particularly, functions lua_pushlstring and lua_pushstring +make an internal copy of the given string. +Function lua_pushstring can only be used to push proper C strings +(that is, strings that do not contain zeros and end with a zero); +otherwise you should use the more generic lua_pushlstring. The function --lua_Object lua_pop (void); - +
        +lua_Object lua_pop (void);
        +
        returns a reference to the object at the top of the C2lua stack, and pops it.

        As a general rule, all API functions pop from the stack -all elements that they use. +all elements they use.

        Because userdata are objects, the function lua_pushusertag may create a new userdata. @@ -1210,26 +1455,26 @@ If Lua has a userdata with the given value (void*) and tag, that userdata is pushed. Otherwise, a new userdata is created, with the given value and tag. If this function is called with -tag=LUA_ANYTAG, +tag equal to LUA_ANYTAG, then Lua will try to find any userdata with the given value, -no matter its tag. +regardless of its tag. If there is no userdata with that value, then a new one is created, -with tag=0. +with tag equal to 0.

        Userdata can have different tags, whose semantics are only known to the host program. Tags are created with the function: -

        -int lua_newtag (void); - +
        +int lua_newtag (void);
        +
        The function lua_settag changes the tag of the object on the top of C2lua (and pops it); the object must be a userdata or a table. --void lua_settag (int tag); - +
        +void lua_settag (int tag);
        +
        tag must be a value created with lua_newtag.

        When C code calls Lua repeatedly, as in a loop, @@ -1237,209 +1482,231 @@ objects returned by these calls can accumulate, and may cause a stack overflow. To avoid this, nested blocks can be defined with the functions: -

        -void lua_beginblock (void); -void lua_endblock (void); - +
        +void lua_beginblock (void);
        +void lua_endblock   (void);
        +
        After the end of the block, all lua_Object's created inside it are released. -The use of explicit nested blocks is strongly encouraged. +The use of explicit nested blocks is good programming practice +and is strongly encouraged.

        - -

        5.2 - Executing Lua Code

        + +

        5.4 - Executing Lua Code

        A host program can execute Lua chunks written in a file or in a string using the following functions: - -+ +
         int lua_dofile   (char *filename);
         int lua_dostring (char *string);
        -
        -Both functions return an error code: +int lua_dobuffer (char *buff, int size, char *name); + +All these functions return an error code: 0, in case of success; non zero, in case of errors. More specifically, lua_dofile returns 2 if for any reason it could not open the file. -The function lua_dofile, if called with argument NULL, -executes the stdin stream. -Function lua_dofile is also able to execute pre-compiled chunks. -It automatically detects whether the file is text or binary, -and loads it accordingly (see program luac). +When called with argument NULL, +lua_dofile executes the stdin stream. +Functions lua_dofile and lua_dobuffer +are both able to execute pre-compiled chunks. +They automatically detect whether the chunk is text or binary, +and load it accordingly (see program luac). +Function lua_dostring executes only source code. +

        +The third parameter to lua_dobuffer (name) +is the ``name of the chunk'', +used in error messages and debug information. +If name is NULL, +Lua gives a default name to the chunk. +In files this name is the file name, +and lua_dostring uses a small prefix +of the string as the chunk name.

        These functions return, in structure lua2C, any values eventually returned by the chunks. They also empty the stack C2lua.

        - -

        5.3 - Manipulating Lua Objects

        + +

        5.5 - Manipulating Lua Objects

        To read the value of any global Lua variable, one uses the function: --lua_Object lua_getglobal (char *varname); - +
        +lua_Object lua_getglobal (char *varname);
        +
        As in Lua, this function may trigger a tag method. To read the real value of any global variable, without invoking any tag method, -this function has a raw version: +use the raw version: --lua_Object lua_rawgetglobal (char *varname); - +
        +lua_Object lua_rawgetglobal (char *varname);
        +

        To store a value previously pushed onto C2lua in a global variable, there is the function: -

        -void lua_setglobal (char *varname); - +
        +void lua_setglobal (char *varname);
        +
        As in Lua, this function may trigger a tag method. To set the real value of any global variable, without invoking any tag method, -this function has a raw version: +use the raw version: --void lua_rawsetglobal (char *varname); - +
        +void lua_rawsetglobal (char *varname);
        +

        Tables can also be manipulated via the API. The function -

        -lua_Object lua_gettable (void); - +
        +lua_Object lua_gettable (void);
        +
        pops from the stack C2lua a table and an index, and returns the contents of the table at that index. As in Lua, this operation may trigger a tag method. To get the real value of any table index, without invoking any tag method, -this function has a raw version: +use the raw version: --lua_Object lua_rawgettable (void); - +
        +lua_Object lua_rawgettable (void);
        +

        To store a value in an index, the program must push the table, the index, and the value onto C2lua, and then call the function: -

        -void lua_settable (void); - +
        +void lua_settable (void);
        +
        Again, the tag method for ``settable'' may be called. To set the real value of any table index, without invoking any tag method, -this function has a raw version: +use the raw version: --void lua_rawsettable (void); - +
        +void lua_rawsettable (void);
        +

        Finally, the function -

        -lua_Object lua_createtable (void); - +
        +lua_Object lua_createtable (void);
        +
        creates and returns a new, empty table.

        - -

        5.4 - Calling Lua Functions

        -Functions defined in Lua by a chunk executed with -dofile or dostring can be called from the host program. + +

        5.6 - Calling Lua Functions

        +Functions defined in Lua by a chunk +can be called from the host program. This is done using the following protocol: first, the arguments to the function are pushed onto C2lua -(see Section 5.1), in direct order, i.e., the first argument is pushed first. -

        +(see Section 5.3), in direct order, i.e., the first argument is pushed first. Then, the function is called using -

        -int lua_callfunction (lua_Object function); - +
        +int lua_callfunction (lua_Object function);
        +
        This function returns an error code: 0, in case of success; non zero, in case of errors. Finally, the results (a Lua function may return many values) are returned in structure lua2C, and can be retrieved with the macro lua_getresult, -which is just another name to the function lua_lua2C. -Notice that the function lua_callfunction +which is just another name to function lua_lua2C. +Note that function lua_callfunction pops all elements from the C2lua stack.

        The following example shows how a C program may do the equivalent to the Lua code: -

        - a = f("how", t.x, 4) - -+
        +      a,b = f("how", t.x, 4)
        +
        +
           lua_pushstring("how");                               /* 1st argument */
           lua_pushobject(lua_getglobal("t"));      /* push value of global 't' */
           lua_pushstring("x");                          /* push the string 'x' */
        -  lua_pushobject(lua_gettable());     /* push result of t.x (= t['x']) */
        -  lua_pushnumber(4);                                   /* 3th argument */
        +  lua_pushobject(lua_gettable());      /* push result of t.x (2nd arg) */
        +  lua_pushnumber(4);                                   /* 3rd argument */
           lua_callfunction(lua_getglobal("f"));           /* call Lua function */
           lua_pushobject(lua_getresult(1));   /* push first result of the call */
           lua_setglobal("a");                      /* sets global variable 'a' */
        -
        + lua_pushobject(lua_getresult(2)); /* push second result of the call */ + lua_setglobal("b"); /* sets global variable 'b' */ +

        Some special Lua functions have exclusive interfaces. A C function can generate a Lua error calling the function -

        +
         void lua_error (char *message);
        -
        + This function never returns. If the C function has been called from Lua, then the corresponding Lua execution terminates, as if an error had occurred inside Lua code. Otherwise, the whole program terminates with a call to exit(1). -

        -The error handler method (see Section 4.9) can be changed with: - -

        -lua_Object lua_seterrormethod (void); - +The message is passed to the error handler method. +If message is NULL, +the error handler method is not called. +

        +The error handler method (see Section 4.9) can be +changed with: +

        +lua_Object lua_seterrormethod (void);
        +
        This function sets the object at the top of C2lua as the new error method, and returns the old error method value.

        -Tag methods can be changed with: - -

        -lua_Object lua_settagmethod (int tag, char *event); - +Tag methods can be changed with: +
        +lua_Object lua_settagmethod (int tag, char *event);
        +
        The first parameter is the tag, -the second is the event name (see Section 4.8); +and the second is the event name (see Section 4.8); the new method is pushed from C2lua. This function returns a lua_Object, which is the old tag method value. To get just the current value of a tag method, -there is the function - --lua_Object lua_gettagmethod (int tag, char *event); - +use the function +
        +lua_Object lua_gettagmethod (int tag, char *event);
        +
        +

        +It is also possible to copy all tag methods from one tag +to another: +

        +int lua_copytagmethods (int tagto, int tagfrom);
        +
        +This function returns tagto.

        - -

        5.5 - C Functions

        + +

        5.7 - C Functions

        To register a C function to Lua, there is the following macro: -+
         #define lua_register(n,f)       (lua_pushcfunction(f), lua_setglobal(n))
         /* char *n;         */
         /* lua_CFunction f; */
        -
        + which receives the name the function will have in Lua, and a pointer to the function. This pointer must have type lua_CFunction, which is defined as -+
         typedef void (*lua_CFunction) (void);
        -
        + that is, a pointer to a function with no parameters and no results.

        In order to communicate properly with Lua, @@ -1448,36 +1715,56 @@ which defines the way parameters and results are passed.

        A C function receives its arguments in structure lua2C; to access them, it uses the macro lua_getparam, -again just another name to lua_lua2C. +again just another name for lua_lua2C. To return values, a C function just pushes them onto the stack C2lua, -in direct order (see Section 5.1). +in direct order (see Section 5.2). Like a Lua function, a C function called by Lua can also return many results.

        -For some examples, see files strlib.c, -iolib.c and mathlib.c in Lua distribution. -

        - -

        5.6 - References to Lua Objects

        -

        -As noted in Section 5.5, lua_Objects are volatile. +When a C function is created, +it is possible to associate some upvalues to it; +then these values are passed to the function whenever it is called, +as common arguments. +To associate upvalues to a function, +first these values must be pushed on C2lua. +Then the function: + +

        +void lua_pushcclosure (lua_CFunction fn, int n);
        +
        +is used to put the C function on C2lua, +with the argument n telling how many upvalues must be +associated with the function; +in fact, the macro lua_pushcfunction is defined as +lua_pushcclosure with n set to 0. +Then, any time the function is called, +these upvalues are inserted as the first arguments to the function, +before the actual arguments provided in the call. +

        +For some examples of C functions, see files lstrlib.c, +liolib.c and lmathlib.c in the official Lua distribution. +

        + +

        5.8 - References to Lua Objects

        +

        +As noted in Section 5.3, lua_Objects are volatile. If the C code needs to keep a lua_Object outside block boundaries, then it must create a reference to the object. The routines to manipulate references are the following: -

        -int lua_ref (int lock); -lua_Object lua_getref (int ref); -void lua_unref (int ref); - +
        +int        lua_ref    (int lock);
        +lua_Object lua_getref (int ref);
        +void       lua_unref  (int ref);
        +
        The function lua_ref creates a reference to the object that is on the top of the stack, and returns this reference. If lock is true, the object is locked: this means the object will not be garbage collected. -Notice that an unlocked reference may be garbage collected. +Note that an unlocked reference may be garbage collected. Whenever the referenced object is needed, a call to lua_getref returns a handle to it; @@ -1485,7 +1772,7 @@ if the object has been collected, lua_getref returns LUA_NOOBJECT.

        When a reference is no longer needed, -it can be freed with a call to lua_unref. +it can be released with a call to lua_unref.

        @@ -1511,59 +1798,77 @@ Currently there are three standard libraries:

      5. mathematical functions (sin, log, etc);
      6. input and output (plus some system facilities).
    -In order to have access to these libraries, -the host program must call the functions -strlib_open, mathlib_open, and iolib_open, -declared in lualib.h. +To have access to these libraries, +the C host program must call the functions +lua_strlibopen, lua_mathlibopen, +and lua_iolibopen, declared in lualib.h. +

    6.1 - Predefined Functions

    -

    call (func, arg, [retmode])

    +

    call (func, arg [, mode [, errmethod]])

    + + This function calls function func with the arguments given by the table arg. The call is equivalent to -+
           func(arg[1], arg[2], ..., arg[arg.n])
    -
    + If arg.n is not defined, -then Lua stops getting arguments at the first nil value. +then Lua stops getting arguments at the first nil value.

    -If retmode is absent, +By default, all results from func are just returned by the call. -If retmode is equal to "pack", +If the string mode contains "p", the results are packed in a single table. That is, call returns just one table; at index n, the table has the total number of results from the call; the first result is at index 1, etc. For instance, the following calls produce the following results: -

    -a = call(sin, {5}) --> a = 0.0871557 = sin(5) -a = call(max, {1,4,5; n=2}) --> a = 4 (only 1 and 4 are arguments) +
    +a = call(sin, {5})                --> a = 0.0871557 = sin(5)
    +a = call(max, {1,4,5; n=2})       --> a = 4 (only 1 and 4 are arguments)
     t = {x=1}
    -a = call(next, {t,nil;n=2}, "pack")  --> a={"x", 1; n=2}
    -
    +a = call(next, {t,nil;n=2}, "p") --> a={"x", 1; n=2} + +

    +By default, +if an error occurs during the function call, +the error is propagated. +If the string mode contains "x", +then the call is protected. +In this mode, function call does not generate an error, +whatever happens during the call. +Instead, it returns nil to signal the error +(besides calling the appropriated error method). +

    +If provided, errmethod is temporarily set as the error method, +while func runs. +As a particular case, if errmethod is nil, +no error messages will be issued during the execution of the called function.

    collectgarbage ([limit])

    Forces a garbage collection cycle. Returns the number of objects collected. An optional argument, limit, is a number that -makes the next cycle occur when that number of new +makes the next cycle occur only after that number of new objects have been created. -If absent, Lua uses an adaptable algorithm to set +If absent, Lua uses an adaptive algorithm to set this limit. collectgarbage is equivalent to the API function lua_collectgarbage.

    dofile (filename)

    This function receives a file name, -opens it, and executes its contents as a Lua chunk, +opens the file, and executes the file contents as a Lua chunk, or as pre-compiled chunks. When called without arguments, -it executes the contents of the standard input (stdin). +dofile executes the contents of the standard input (stdin). If there is any error executing the file, then dofile returns nil. Otherwise, it returns the values returned by the chunk, @@ -1571,15 +1876,16 @@ or a non nil value if the chunk returns no values. It issues an error when called with a non string argument. dofile is equivalent to the API function lua_dofile.

    -

    dostring (string [, errmethod])

    +

    dostring (string [, chunkname])

    This function executes a given string as a Lua chunk. -If there is any error executing the string, it returns nil. +If there is any error executing the string, +dostring returns nil. Otherwise, it returns the values returned by the chunk, or a non nil value if the chunk returns no values. -If provided, errmethod is temporarily set as the error method, -while string runs. -As a particular case, if errmethod is nil, -no error messages will be issued during the execution of the string. +An optional second parameter (chunkname) +is the ``name of the chunk'', +used in error messages and debug information. +dostring is equivalent to the API function lua_dostring.

    newtag ()

    @@ -1595,17 +1901,17 @@ value associated with the index. When called with nil as its second argument, the function returns the first index of the table (and its associated value). -When called with the last index, or with nil in an empty table, +When called with the last index, +or with nil in an empty table, it returns nil.

    -In Lua there is no declaration of fields; +Lua has no declaration of fields; semantically, there is no difference between a field not present in a table or a field with value nil. Therefore, the function only considers fields with non nil values. The order in which the indices are enumerated is not specified, -not even for numeric indices -(to traverse a table in numeric order, -use a counter). +even for numeric indices +(to traverse a table in numeric order, use a counter). If the table is modified in any way during a traversal, the semantics of next is undefined.

    @@ -1613,7 +1919,7 @@ This function cannot be written with the standard API.

    nextvar (name)

    This function is similar to the function next, -but iterates over the global variables. +but iterates instead over the global variables. Its single argument is the name of a global variable, or nil to get a first name. Similarly to next, it returns the name of another variable @@ -1624,26 +1930,76 @@ otherwise the semantics of nextvar is undefined.

    This function cannot be written with the standard API.

    +

    foreach (table, function)

    +Executes the given function over all elements of table. +For each element, the function is called with the index and +respective value as arguments. +If the function returns any non-nil value, +the loop is broken, and the value is returned +as the final value of foreach. +

    +This function could be defined in Lua: +

    +function foreach (t, f)
    +  local i, v = next(t, nil)
    +  while i do
    +    local res = f(i, v)
    +    if res then return res end
    +    i, v = next(t, i)
    +  end
    +end
    +
    +

    +

    foreachvar (function)

    +Executes function over all global variables. +For each variable, +the function is called with its name and its value as arguments. +If the function returns any non-nil value, +the loop is broken, and the value is returned +as the final value of foreachvar. +

    +This function could be defined in Lua: +

    +function foreachvar (f)
    +  local n, v = nextvar(nil)
    +  while n do
    +    local res = f(n, v)
    +    if res then return res end
    +    n, v = nextvar(n)
    +  end
    +end
    +
    +

    tostring (e)

    This function receives an argument of any type and converts it to a string in a reasonable format. +For complete control on how numbers are converted, +use function format.

    print (e1, e2, ...)

    This function receives any number of arguments, -and prints their values in a reasonable format. -Each value is printed in a new line. +and prints their values using the strings returned by tostring. This function is not intended for formatted output, -but as a quick way to show a value, +but only as a quick way to show a value, for instance for error messages or debugging. See Section 6.4 for functions for formatted output.

    -

    tonumber (e)

    +

    tonumber (e [, base])

    This function receives one argument, and tries to convert it to a number. If the argument is already a number or a string convertible -to a number (see Section 4.3), then it returns that number; +to a number, then tonumber returns that number; otherwise, it returns nil.

    +An optional argument specifies the base to interpret the numeral. +The base may be any integer between 2 and 36 inclusive. +In bases above 10, the letter `A' (either upper or lower case) +represents 10, `B' represents 11, and so forth, with `Z' representing 35. +

    +In base 10 (the default), the number may have a decimal part, +as well as an optional exponent part (see Section 4.3). +In other bases, only integers are accepted. +

    type (v)

    This function allows Lua to test the type of a value. @@ -1655,7 +2011,6 @@ The possible results of this function are "table", "function", and "userdata". -type is equivalent to the API function lua_type.

    tag (v)

    This function allows Lua to test the tag of a value (see Section 3). @@ -1666,19 +2021,33 @@ It receives one argument, and returns its tag (a number). This function sets the tag of a given table (see Section 3). tag must be a value created with newtag (see Section 6.1). +It returns the value of its first argument (the table). For security reasons, it is impossible to change the tag of a userdata from Lua.

    -

    assert (v)

    +

    +

    assert (v [, message])

    This function issues an ``assertion failed!'' error when its argument is nil. +This function is equivalent to the following Lua function: +
    +function assert (v, m)
    +  if not v then
    +    m = m or ""
    +    error("assertion failed!  " .. m)
    +  end
    +end
    +

    error (message)

    -This function issues an error message and terminates -the last called function from the library -(lua_dofile, lua_dostring, or lua_callfunction). -It never returns. +This function calls the error handler and then terminates +the last protected function called +(in C: lua_dofile, lua_dostring, +lua_dobuffer, or lua_callfunction; +in Lua: dofile, dostring, or call in protected mode). +If message is nil, the error handler is not called. +Function error never returns. error is equivalent to the API function lua_error.

    rawgettable (table, index)

    @@ -1688,7 +2057,7 @@ without invoking any tag method. and index is any value different from nil.

    rawsettable (table, index, value)

    -Sets the real value table[index]=value, +Sets the real value of table[index] to value, without invoking any tag method. table must be a table, index is any value different from nil, @@ -1696,15 +2065,20 @@ and value is any Lua value.

    rawsetglobal (name, value)

    This function assigns the given value to a global variable. -The string name does not need to be a syntactically valid variable name. -Therefore, this function can set global variables with strange names like +The string name does not need to be a +syntactically valid variable name. +Therefore, +this function can set global variables with strange names like "m v 1" or 34. -It returns the value of its second argument. +Function rawsetglobal returns the value of its second argument.

    setglobal (name, value)

    This function assigns the given value to a global variable, or calls a tag method. Its full semantics is explained in Section 4.8. +The string name does not need to be a +syntactically valid variable name. +Function setglobal returns the value of its second argument.

    rawgetglobal (name)

    This function retrieves the value of a global variable. @@ -1715,6 +2089,8 @@ syntactically valid variable name. This function retrieves the value of a global variable, or calls a tag method. Its full semantics is explained in Section 4.8. +The string name does not need to be a +syntactically valid variable name.

    seterrormethod (newmethod)

    @@ -1726,23 +2102,28 @@ Returns the old error handler.

    settagmethod (tag, event, newmethod)

    -This function sets a new tag method to the given pair <tag, event>. +This function sets a new tag method to the given pair (tag, event). It returns the old method. If newmethod is nil, -it restores the default behavior for the given event. +settagmethod restores the default behavior for the given event.

    gettagmethod (tag, event)

    This function returns the current tag method -for a given pair <tag, event>. +for a given pair (tag, event). +

    +

    copytagmethods (tagto, tagfrom)

    + +This function copies all tag methods from one tag to another; +it returns tagto.

    6.2 - String Manipulation

    This library provides generic functions for string manipulation, such as finding and extracting substrings and pattern matching. -When indexing a string, the first character is at position 1, -not 0, as in C. +When indexing a string, the first character is at position 1 +(not at 0, as in C).

    strfind (str, pattern [, init [, plain]])

    @@ -1755,6 +2136,10 @@ If the pattern specifies captures, the captured strings are returned as extra results. A third optional numerical argument specifies where to start the search; its default value is 1. +If init is negative, +it is replaced by the length of the string minus its +absolute value plus 1. +Therefore, -1 points to the last character of str. A value of 1 as a fourth optional argument turns off the pattern matching facilities, so the function does a plain ``find substring'' operation, @@ -1769,9 +2154,9 @@ starting at i and running until j. If i or j are negative, they are replaced by the length of the string minus their absolute value plus 1. -Therefore, -1 points to the last character of s -and -2 to the previous one. -If j is absent, it is assumed to be equal to -1 +Therefore, -1 points to the last character of s +and -2 to the previous one. +If j is absent, it is assumed to be equal to -1 (which is the same as the string length). In particular, the call strsub(s,1,j) returns a prefix of s @@ -1783,24 +2168,42 @@ with length i. Receives a string and returns a copy of that string with all upper case letters changed to lower case. All other characters are left unchanged. +The definition of what is an upper case +letter depends on the current locale.

    strupper (s)

    Receives a string and returns a copy of that string with all lower case letters changed to upper case. All other characters are left unchanged. +The definition of what is a lower case +letter depends on the current locale.

    strrep (s, n)

    -Returns a string which is the concatenation of n copies of +Returns a string that is the concatenation of n copies of the string s.

    -

    ascii (s [, i])

    -Returns the ASCII code of the character s[i]. +

    strbyte (s [, i])

    +Returns the internal numerical code of the character s[i]. If i is absent, then it is assumed to be 1. +If i is negative, +it is replaced by the length of the string minus its +absolute value plus 1. +Therefore, -1 points to the last character of s. +

    +Note that numerical codes are not necessarily portable across platforms. +

    +

    strchar (i1, i2, ...)

    +Receives 0 or more integers. +Returns a string with length equal to the number of arguments, +wherein each character has the internal numerical code equal +to its correspondent argument. +

    +Note that numerical codes are not necessarily portable across platforms.

    format (formatstring, e1, e2, ...)

    -This function returns a formated version of its variable number of arguments +This function returns a formatted version of its variable number of arguments following the description given in its first argument (which must be a string). The format string follows the same rules as the printf family of standard C functions. @@ -1815,17 +2218,27 @@ the string is written between double quotes, and all double quotes, returns and backslashes in the string are correctly escaped when written. For instance, the call -+
     format('%q', 'a string with "quotes" and \n new line')
    -
    + will produce the string: -+
     "a string with \"quotes\" and \
      new line"
    -
    + +

    +Conversions can be applied to the n-th argument in the argument list, +rather than the next unused argument. +In this case, the conversion character % is replaced +by the sequence %d$, where d is a +decimal digit in the range [1,9], +giving the position of the argument in the argument list. +For instance, the call format("%2$d -> %1$03d", 1, 34) will +result in "34 -> 001". +The same argument can be used in more than one conversion.

    The options c, d, E, e, f, -g i, o, u, X, and x all +g, G, i, o, u, X, and x all expect a number as argument, whereas q and s expect a string. Note that the * modifier can be simulated by building @@ -1833,7 +2246,9 @@ the appropriate format string. For example, "%*g" can be simulated with "%"..width.."g".

    -

    gsub (s, pat, repl [, table] [, n])

    +Note: function format can only be used with strings that do not contain zeros. +

    +

    gsub (s, pat, repl [, n])

    Returns a copy of s, where all occurrences of the pattern pat have been @@ -1847,12 +2262,8 @@ with n between 1 and 9 stands for the value of the n-th captured substring.

    If repl is a function, then this function is called every time a -match occurs, with the following arguments: -If table is present, then the first argument is this table -and the second one is a match counter (1 for the first call). -Independently of these two optional arguments, -all captured substrings are passed as arguments, -in order (see below); +match occurs, with all captured substrings passed as arguments, +in order (see below). If the value returned by this function is a string, then it is used as the replacement string; otherwise, the replacement string is the empty string. @@ -1863,29 +2274,31 @@ For instance, when n is 1 only the first occurrence of pat is replaced.

    See some examples below: -

    +
    +  x = gsub("hello world", "(%w%w*)", "%1 %1")
    +  --> x="hello hello world world"
    +

    x = gsub("hello world", "(%w%w*)", "%1 %1", 1) --> x="hello hello world"

    + x = gsub("hello world from Lua", "(%w%w*)%s*(%w%w*)", "%2 %1") + --> x="world hello Lua from" +

    x = gsub("home = $HOME, user = $USER", "$(%w%w*)", getenv) --> x="home = /home/roberto, user = roberto" (for instance)

    x = gsub("4+5 = $return 4+5$", "$(.-)%$", dostring) --> x="4+5 = 9"

    - function f(t, i, v) return t[v] end - t = {name="lua", version="3.0"} - x = gsub("$name - $version", "$(%w%w*)", f, t) - --> x="lua - 3.0" -

    - t = {"apple", "orange", "lime"} - x = gsub("x and x and x", "x", rawgettable, t) - --> x="apple and orange and lime" + local t = {name="lua", version="3.1"} + x = gsub("$name - $version", "$(%w%w*)", function (v) return %t[v] end) + --> x="lua - 3.1"

    - t = {} - dummy, t.n = gsub("first second word", "(%w%w*)", rawsettable, t) + t = {n=0} + gsub("first second word", "(%w%w*)", + function (w) %t.n = %t.n+1; %t[%t.n] = w end) --> t={"first", "second", "word"; n=3} -

    +

    @@ -1897,7 +2310,7 @@ The following combinations are allowed in describing a character class:

    x
    (where x is any character not in the list ()%.[*-?) - represents the character x itself. -
    .
    - represents all characters. +
    .
    - (a dot) represents all characters.
    %a
    - represents all letters.
    %A
    - represents all non letter characters.
    %d
    - represents all digits. @@ -1910,26 +2323,31 @@ The following combinations are allowed in describing a character class:
    %U
    - represents all non upper case letter characters.
    %w
    - represents all alphanumeric characters.
    %W
    - represents all non alphanumeric characters. -
    %x
    (where x is any non alphanumeric character) - +
    %x
    (where x is any non alphanumeric character) - represents the character x. This is the standard way to escape the magic characters ()%.[*-?. -
    [char-set]
    - +
    [char-set]
    - Represents the class which is the union of all characters in char-set. To include a ] in char-set, it must be the first character. A range of characters may be specified by -separating the end characters of the range with a -; -e.g., A-Z specifies the upper case characters. +separating the end characters of the range with a -. If - appears as the first or last character of char-set, then it represents itself. All classes %x described above can also be used as components in a char-set. All other characters in char-set represent themselves. -
    [^char-set]
    - +E.g., assuming an ascii character set, +[%dA-Fa-f] specifies the hexa-decimal digits. +
    [^char-set]
    - represents the complement of char-set, where char-set is interpreted as above.

    +The definitions of letter, space, etc. depend on the current locale. +In particular, the class [a-z] may not be equivalent to %l. +The second form should be preferred for more portable programs. +

    Pattern Item:

    a pattern item may be:
      @@ -1978,9 +2396,10 @@ that match captures are stored (captured) for future use. Captures are numbered according to their left parentheses. For instance, in the pattern "(a*(.)%w(%s*))", the part of the string matching "a*(.)%w(%s*)" is -stored as the first capture (and therefore has number 1); -the character matching . is captured with number 2, -and the part matching %s* has number 3. +stored as the first capture (and therefore has number 1); +the character matching . is captured with number 2, +and the part matching %s* has number 3. +

      @@ -1995,26 +2414,33 @@ The library provides the following functions: + -

      -abs acos asin atan atan2 ceil cos floor log log10 -max min mod sin sqrt tan random randomseed - +
      +abs acos asin atan atan2 ceil cos deg   floor log log10
      +max min  mod  rad  sin   sqrt tan frexp ldexp
      +random   randomseed
      +
      +plus a global variable PI. Most of them are only interfaces to the homonymous functions in the C library, except that, for the trigonometric functions, all angles are expressed in degrees, not radians. +Functions deg and rad can be used to convert +between radians and degrees.

      The function max returns the maximum value of its numeric arguments. Similarly, min computes the minimum. -Both can be used with an unlimited number of arguments. +Both can be used with 1, 2 or more arguments.

      The functions random and randomseed are interfaces to the simple random generator functions rand and srand, provided by ANSI C. -The function random returns pseudo-random numbers in the -range [0,1). +The function random, when called without arguments, +returns a pseudo-random real number in the range [0,1). +When called with a number n, +random returns a pseudo-random integer in the range [1,n].

      @@ -2057,7 +2483,7 @@ plus a string describing the error.

      System dependent: if filename starts with a |, -then a piped input is open, via function popen. +then a piped input is opened, via function popen. Not all systems implement pipes. Moreover, the number of files that can be open at the same time is @@ -2072,7 +2498,7 @@ it opens the named file, sets its handle as the value of _OUTPUT, and returns this value. It does not close the current output file. -Notice that, if the file already exists, +Note that, if the file already exists, then it will be completely erased with this operation. When called without parameters, this function closes the _OUTPUT file, @@ -2084,7 +2510,7 @@ plus a string describing the error.

      System dependent: if filename starts with a |, -then a piped output is open, via function popen. +then a piped output is opened, via function popen. Not all systems implement pipes. Moreover, the number of files that can be open at the same time is @@ -2100,7 +2526,8 @@ this function does not erase any previous content of the file. If this function fails, it returns nil, plus a string describing the error.

      -Notice that function writeto is available to close an output file. +Note that function writeto is +available to close an output file opened by appendto.

      remove (filename)

      @@ -2120,11 +2547,12 @@ This function returns a string with a file name that can safely be used for a temporary file. The file must be explicitly removed when no longer needed.

      -

      read ([readpattern])

      +

      read ([filehandle] [readpattern])

      -This function reads the file _INPUT -according to a read pattern, that specifies how much to read; -characters are read from the current input file until +This function reads the file _INPUT, +or from filehandle if this argument is given, +according to a read pattern, which specifies how much to read; +characters are read from the input file until the read pattern fails or ends. The function read returns a string with the characters read, even if the pattern succeeds only partially, @@ -2145,14 +2573,12 @@ it never fails. A character class followed by * reads until a character that does not belong to the class, or end of file; since it can match a sequence of zero characters, it never fails. -\footnote{ -Notice that the behavior of read patterns is different from +Note that the behavior of read patterns is slightly different from the regular pattern matching behavior, where a * expands to the maximum length such that the rest of the pattern does not fail. With the read pattern behavior there is no need for backtracking the reading. -}

      A pattern item may contain sub-patterns enclosed in curly brackets, that describe skips. @@ -2174,10 +2600,11 @@ or nil on end of file. or nil if the next characters do not conform to an integer format.

    -

    write (value1, ...)

    +

    write ([filehandle, ] value1, ...)

    This function writes the value of each of its arguments to the -file _OUTPUT. +file _OUTPUT, +or to filehandle if this argument is given, The arguments must be strings or numbers. To write other values, use tostring or format before write. @@ -2191,7 +2618,12 @@ formatted according to the given string format, following the same rules of the ANSI C function strftime. When called without arguments, it returns a reasonable date and time representation that depends on -the host system. +the host system and the locale. +

    +

    clock ()

    +

    +This function returns an approximation of the amount of CPU time +used by the program, in seconds.

    exit ([code])

    @@ -2202,7 +2634,7 @@ The default value for code is 1.

    getenv (varname)

    -Returns the value of the environment variable varname, +Returns the value of the process environment variable varname, or nil if the variable is not defined.

    execute (command)

    @@ -2211,6 +2643,17 @@ This function is equivalent to the C function system. It passes command to be executed by an operating system shell. It returns an error code, which is system-dependent.

    +

    setlocale (locale [, category])

    +

    +This function is an interface to the ANSI C function setlocale. +locale is a string specifying a locale; +category is an optional string describing which category to change: +"all", "collate", "ctype", +"monetary", "numeric", or "time"; +the default category is "all". +The function returns the name of the new locale, +or nil if the request cannot be honored. +

    @@ -2231,9 +2674,9 @@ This interface is declared in the header file luadebug.h.

    The main function to get information about the interpreter stack is -

    +
     lua_Function lua_stackedfunction (int level);
    -
    + It returns a handle (lua_Function) to the activation record of the function executing at a given level. Level 0 is the current running function, @@ -2250,23 +2693,24 @@ it accepts only a handle returned by lua_stackedfunction.

    Three other functions produce extra information about a function: -

    +
     void lua_funcinfo (lua_Object func, char **filename, int *linedefined);
     int lua_currentline (lua_Function func);
     char *lua_getobjname (lua_Object o, char **name);
    -
    + lua_funcinfo gives the file name and the line where the given function has been defined. If the ``function'' is in fact the main code of a chunk, then linedefined is 0. If the function is a C function, -then linedefined is -1, and filename is "(C)". +then linedefined is -1, and filename is "(C)".

    The function lua_currentline gives the current line where a given function is executing. It only works if the function has been compiled with debug information (see Section 4.9). -When no line information is available, it returns -1. +When no line information is available, +lua_currentline returns -1.

    Function lua_getobjname tries to find a reasonable name for a given function. @@ -2292,10 +2736,10 @@ The following functions allow the manipulation of the local variables of a given activation record. They only work if the function has been compiled with debug information (see Section 4.9). -

    +
     lua_Object lua_getlocal (lua_Function func, int local_number, char **name);
     int lua_setlocal (lua_Function func, int local_number);
    -
    + lua_getlocal returns the value of a local variable, and sets name to point to the variable name. local_number is an index for local variables. @@ -2309,7 +2753,7 @@ Formal parameters are the first local variables.

    The function lua_setlocal sets the local variable local_number to the value previously pushed on the stack -(see Section 5.1). +(see Section 5.2). If the function succeeds, then it returns 1. If local_number is greater than the number of active local variables, @@ -2320,13 +2764,13 @@ then this function fails and returns 0.

    7.3 - Hooks

    The Lua interpreter offers two hooks for debugging purposes: -

    +
     typedef void (*lua_CHFunction) (lua_Function func, char *file, int line);
     extern lua_CHFunction lua_callhook;
     

    typedef void (*lua_LHFunction) (int line); extern lua_LHFunction lua_linehook; -

    + The first one is called whenever the interpreter enters or leaves a function. When entering a function, @@ -2363,36 +2807,41 @@ is provided with the standard distribution. This program can be called with any sequence of the following arguments:
    -v
    prints version information. -
    -
    runs interactively, accepting commands from standard input -until an EOF. +
    -d
    turns on debug information.
    -e stat
    executes stat as a Lua chunk. -
    var=exp
    executes var=exp as a Lua chunk. +
    -i
    runs interactively, +accepting commands from standard input until an EOF. +Each line entered is immediately executed. +
    -q
    same as -i, but without a prompt (quiet mode). +
    -
    executes stdin as a file. +
    var=value
    sets global var with string "value".
    filename
    executes file filename as a Lua chunk.
    +When called without arguments, +Lua behaves as lua -v -i when stdin is a terminal, +and as lua - otherwise. +

    All arguments are handled in order. For instance, an invocation like -

    -$ lua - a=1 prog.lua - +
    +$ lua -i a=test prog.lua
    +
    will first interact with the user until an EOF, -then will set a to 1, -and finally will run file prog.lua. -

    -Please notice that the interaction with the shell may lead to -unintended results. -For instance, a call like -

    -$ lua a="name" prog.lua - -will not set a to the string "name". -Instead, the quotes will be handled by the shell, -lua will get only a=name to run, -and a will finish with nil, -because the global variable name has not been initialized. -Instead, one should write --$ lua 'a="name"' prog.lua - +then will set a to "test", +and finally will run the file prog.lua. +

    +When in interactive mode, +a multi-line statement can be written finishing intermediate +lines with a backslash (\). +The prompt presented is the value of the global variable _PROMPT. +Therefore, the prompt can be changed like below: +

    +$ lua _PROMPT='myprompt> ' -i
    +
    +

    +In Unix systems, Lua scripts can be made into executable programs +by using the #! form, +as in #!/usr/local/bin/lua.


    @@ -2417,129 +2866,43 @@ the previous public versions of Lua, some differences had to be introduced. Here is a list of all these incompatibilities.

    -

    Incompatibilities with version 2.5

    +

    Incompatibilities with version 3.0

      -
    • -The whole fallback mechanism has been replaced by tag methods. -Nevertheless, the function setfallback has been rewritten in -a way that uses tag methods to fully emulate the old behavior -of fallbacks. -
    • -Tags now must be created with the function newtag. -Nevertheless, old user defined tags are still accepted -(user defined tags must be positive; -newtag uses negative numbers). -Tag methods cannot be set for such user defined tags, -and fallbacks do not affect tags created by newtag. -
    • -Lua 2.5 accepts mixed comparisons of strings and numbers, -like 2<"12", giving weird results. -Now this is an error. -
    • -Character "-" (hyphen) now is ``magic'' in pattern matching. -
    • -Some API functions have been rewritten as macros. -

    -

    Incompatibilities with version 2.4

    -The whole I/O facilities have been rewritten. -We strongly encourage programmers to adapt their code -to this new version. -The incompatibilities between the new and the old libraries are: -
      -
    • The format facility of function write has been supersed by -function format; -therefore this facility has been dropped. -
    • Function read now uses read patterns to specify -what to read; -this is incompatible with the old format options. -
    • Function strfind now accepts patterns, -so it may have a different behavior when the pattern includes -special characters. -
    +
  • To support multiple contexts, +Lua 3.1 must be explicitly opened before used, +with function lua_open. +However, all standard libraries check whether Lua is already opened, +so any existing program that opens at least one standard +library before calling Lua does not need to be modified.

    -

    Incompatibilities with version 2.2

    -
      -
    • -Functions date and time (from iolib) -have been superseded by the new, more powerful version of function date. -
    • -Function append (from iolib) now returns 1 whenever it succeeds, -whether the file is new or not. -
    • -Function int2str (from strlib) has been superseded by new -function format, with parameter "%c". -
    • -The API lock mechanism has been superseded by the reference mechanism. -However, lua.h provides compatibility macros, -so there is no need to change programs. -
    • -The API function lua_pushliteral now is just a macro to -lua_pushstring. -
    +
  • Function dostring no longer accepts an optional second argument, +with a temporary error method. +This facility is now provided by function call.

    -

    Incompatibilities with version 2.1

    -
      -
    • -The function type now returns the string "function" -both for C and Lua functions. -Because Lua functions and C functions are compatible, -this behavior is usually more useful. -When needed, the second result of function type may be used -to distinguish between Lua and C functions. -
    • -A function definition only assigns the function value to the -given variable at execution time. -
    +
  • Function gsub no longer accepts an optional fourth argument +(a callback data, a table). +Closures replace this feature with advantage. +

    +

  • The syntax for function declaration is now more restricted; +for instance, the old syntax function f[exp] (x) ... end is not +accepted in Lua 3.1. +In these cases, +programs should use an explicit assignment instead, such as +f[exp] = function (x) ... end. +

    +

  • Old pre-compiled code is obsolete, and must be re-compiled. +

    +

  • The option a=b in Lua stand-alone now sets a to the +string b, and not to the value of b.

    -

    Incompatibilities with version 1.1

    -
      -
    • -The equality test operator now is denoted by ==, -instead of =. -
    • -The syntax for table construction has been greatly simplified. -The old @(size) has been substituted by {}. -The list constructor (formerly @[...]) and the record -constructor (formerly @{...}) now are both coded like -{...}. -When the construction involves a function call, -like in @func{...}, -the new syntax does not use the @. -More important, {\em a construction function must now -explicitly return the constructed table}. -
    • -The function lua_call no longer has the parameter nparam. -
    • -The function lua_pop is no longer available, -since it could lead to strange behavior. -In particular, -to access results returned from a Lua function, -the new macro lua_getresult should be used. -
    • -The old functions lua_storefield and lua_storeindexed -have been replaced by --int lua_storesubscript (void); - -with the parameters explicitly pushed on the stack. -
    • -The functionality of the function lua_errorfunction has been -replaced by the fallback mechanism (see Section 4.9). -
    • -When calling a function from the Lua library, -parameters passed through the stack -must be pushed just before the corresponding call, -with no intermediate calls to Lua. -Special care should be taken with macros like -lua_getindexed and lua_getfield.


    Last update: -Tue Jul 1 07:55:45 EST 1997 +Fri Jul 10 15:10:14 EST 1998 by lhf. diff --git a/etc/Makefile b/etc/Makefile new file mode 100644 index 0000000..216d3ef --- /dev/null +++ b/etc/Makefile @@ -0,0 +1,24 @@ +# makefile for etc + +LUA= .. + +include $(LUA)/config + +ALL= bin2c min trace + +all: $(ALL) + +bin2c: bin2c.c + $(CC) -o $@ $< + +min: min.c $(LIB)/liblua.a + $(CC) $(CFLAGS) -o $@ $< -L$(LIB) -llua + +trace: trace.c $(LIB)/liblua.a + $(CC) $(CFLAGS) -o $@ $< -L$(LIB) -llua + +$(LIB)/liblua.a: + cd ../src; make + +clean: + rm -f $(ALL) diff --git a/etc/README b/etc/README new file mode 100644 index 0000000..fda602d --- /dev/null +++ b/etc/README @@ -0,0 +1,25 @@ +This directory contains some code that might be useful. + +bin2c.c + This program converts files to byte arrays that are automatically + run with lua_dobuffer. + This allows C programs to include all necessary Lua code, even in + precompiled form. + Even if code is include in source form, bin2c is useful because it + avoids the hassle of having to quote special characters in C strings. + Example of usage: run bin2c file1 file2 ... > init.h. The in your C + program, just do #include "init.h" anywhere in the *body* of a + function. This will be equivalent to calling + lua_dofile("file1"); lua_dofile("file2"); ... + +min.c + The smallest Lua interpreter possible. + +setfallback.lua + An implementation of fallbacks on top of tag methods. + Useful if you have Lua code written for version 2.5 or earlier. + If you have C code that uses lua_setfallback, then define LUA_COMPAT2_5 + before building Lua (see config). + +trace.c + A simple execution tracer. An example of how to use the debugging hooks. diff --git a/etc/bin2c.c b/etc/bin2c.c new file mode 100644 index 0000000..349b7ee --- /dev/null +++ b/etc/bin2c.c @@ -0,0 +1,66 @@ +/* +* bin2c.c +* convert binary files to byte arrays +* Luiz Henrique de Figueiredo (lhf@tecgraf.puc-rio.br) +* 25 Jun 98 10:55:12 +*/ + +#include +#include + +void dump(FILE* f, int n) +{ + printf("static unsigned char B%d[]={\n"); + for (n=1;;n++) + { + int c=getc(f); + if (c==EOF) break; +#if 0 + printf("0x%02x,",c); +#else + printf("%3u,",c); +#endif + if (n==20) { putchar('\n'); n=0; } + } + printf("\n};\n\n"); +} + +void fdump(char* fn, int n) +{ + FILE* f= (fn==NULL) ? stdin : fopen(fn,"rb"); /* must open in binary mode */ + if (f==NULL) + { + fprintf(stderr,"bin2c: cannot open "); + perror(fn); + exit(1); + } + else + { + if (fn!=NULL) printf("/* %s */\n",fn); + dump(f,n); + fclose(f); + } +} + +void emit(char* fn, int n) +{ + printf(" lua_dobuffer(B%d,sizeof(B%d),\"%s\");\n",n,n,fn); +} + +int main(int argc, char* argv[]) +{ + printf("{\n"); + if (argc<2) + { + dump(stdin,0); + emit("(stdin)",0); + } + else + { + int i; + for (i=1; i +#include +#include "lua.h" +#include "luadebug.h" + +static FILE* P; /* output file */ +static int L=0; /* indentation level */ + +static void linehook(int line) +{ + fprintf(P,"%*sLINE(%d)\t-- %d\n",L,"",line,L); +} + +static void callhook(lua_Function func, char* file, int line) +{ + fprintf(P,"%*sCALL('%s',%d)\t-- %d\n",L,"",file,line,L); + if (line==0 && strcmp(file,"(return)")==0) --L; else ++L; +} + +void start_trace(void) +{ + lua_linehook=linehook; + lua_callhook=callhook; + lua_debug=1; +#if 0 + P=fopen("trace.out","w"); +#else + P=stderr; +#endif +} + +void stop_trace(void) +{ + lua_linehook=NULL; + lua_callhook=NULL; + lua_debug=0; + fclose(P); +} + +int main(void) +{ + int rc; + lua_open(); + start_trace(); + rc=lua_dofile(0); + stop_trace(); + return rc; +} diff --git a/include/Makefile b/include/Makefile index 6cd0c92..48f12a7 100644 --- a/include/Makefile +++ b/include/Makefile @@ -4,14 +4,14 @@ LUA= .. include $(LUA)/config -SRCS= lua.h lualib.h luadebug.h auxlib.h +SRCS= lua.h lualib.h luadebug.h lauxlib.h all: clean: co: - co -f -M $(SRCS) + co -q -f -M $(SRCS) klean: clean rm -f $(SRCS) diff --git a/include/auxlib.h b/include/auxlib.h deleted file mode 100644 index 09020b4..0000000 --- a/include/auxlib.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -** $Id: auxlib.h,v 1.3 1997/04/07 14:48:53 roberto Exp $ -*/ - -#ifndef auxlib_h -#define auxlib_h - -#include "lua.h" - -struct luaL_reg { - char *name; - lua_CFunction func; -}; - -void luaL_openlib (struct luaL_reg *l, int n); -void luaL_arg_check(int cond, int numarg, char *extramsg); -char *luaL_check_string (int numArg); -char *luaL_opt_string (int numArg, char *def); -double luaL_check_number (int numArg); -double luaL_opt_number (int numArg, double def); -void luaL_verror (char *fmt, ...); - - - -/* -- private part (only for Lua modules */ - -int luaI_findstring (char *name, char *list[]); - - -#endif diff --git a/include/lauxlib.h b/include/lauxlib.h new file mode 100644 index 0000000..e4d46fb --- /dev/null +++ b/include/lauxlib.h @@ -0,0 +1,47 @@ +/* +** $Id: lauxlib.h,v 1.9 1998/06/19 16:14:09 roberto Exp $ +** Auxiliary functions for building Lua libraries +** See Copyright Notice in lua.h +*/ + + +#ifndef auxlib_h +#define auxlib_h + + +#include "lua.h" + + +struct luaL_reg { + char *name; + lua_CFunction func; +}; + + +#define luaL_arg_check(cond,numarg,extramsg) if (!(cond)) \ + luaL_argerror(numarg,extramsg) + +void luaL_openlib (struct luaL_reg *l, int n); +void luaL_argerror (int numarg, char *extramsg); +#define luaL_check_string(n) (luaL_check_lstr((n), NULL)) +char *luaL_check_lstr (int numArg, long *len); +#define luaL_opt_string(n, d) (luaL_opt_lstr((n), (d), NULL)) +char *luaL_opt_lstr (int numArg, char *def, long *len); +double luaL_check_number (int numArg); +double luaL_opt_number (int numArg, double def); +lua_Object luaL_functionarg (int arg); +lua_Object luaL_tablearg (int arg); +lua_Object luaL_nonnullarg (int numArg); +void luaL_verror (char *fmt, ...); +char *luaL_openspace (int size); +void luaL_resetbuffer (void); +void luaL_addchar (int c); +int luaL_getsize (void); +void luaL_addsize (int n); +int luaL_newbuffer (int size); +void luaL_oldbuffer (int old); +char *luaL_buffer (void); +int luaL_findstring (char *name, char *list[]); + + +#endif diff --git a/include/lua.h b/include/lua.h index b0409d6..bce5a2c 100644 --- a/include/lua.h +++ b/include/lua.h @@ -1,16 +1,18 @@ /* -** LUA - An Extensible Extension Language +** $Id: lua.h,v 1.23 1998/06/18 16:51:53 roberto Exp $ +** Lua - An Extensible Extension Language ** TeCGraf: Grupo de Tecnologia em Computacao Grafica, PUC-Rio, Brazil ** e-mail: lua@tecgraf.puc-rio.br -** $Id: lua.h,v 4.11 1997/06/23 18:27:53 roberto Exp $ +** www: http://www.tecgraf.puc-rio.br/lua/ +** See Copyright Notice at the end of this file */ #ifndef lua_h #define lua_h -#define LUA_VERSION "Lua 3.0" -#define LUA_COPYRIGHT "Copyright (C) 1994-1997 TeCGraf" +#define LUA_VERSION "Lua 3.1" +#define LUA_COPYRIGHT "Copyright (C) 1994-1998 TeCGraf, PUC-Rio" #define LUA_AUTHORS "W. Celes, R. Ierusalimschy & L. H. de Figueiredo" @@ -21,16 +23,26 @@ typedef void (*lua_CFunction) (void); typedef unsigned int lua_Object; -lua_Object lua_settagmethod (int tag, char *event); /* In: new method */ +typedef struct lua_State lua_State; +extern lua_State *lua_state; + +void lua_open (void); +void lua_close (void); +lua_State *lua_setstate (lua_State *st); + +lua_Object lua_settagmethod (int tag, char *event); /* In: new method */ lua_Object lua_gettagmethod (int tag, char *event); lua_Object lua_seterrormethod (void); /* In: new method */ int lua_newtag (void); +int lua_copytagmethods (int tagto, int tagfrom); void lua_settag (int tag); /* In: object */ void lua_error (char *s); int lua_dofile (char *filename); /* Out: returns */ int lua_dostring (char *string); /* Out: returns */ +int lua_dobuffer (char *buff, int size, char *name); + /* Out: returns */ int lua_callfunction (lua_Object f); /* In: parameters; Out: returns */ @@ -49,16 +61,18 @@ int lua_isnumber (lua_Object object); int lua_isstring (lua_Object object); int lua_isfunction (lua_Object object); -float lua_getnumber (lua_Object object); +double lua_getnumber (lua_Object object); char *lua_getstring (lua_Object object); +long lua_strlen (lua_Object object); lua_CFunction lua_getcfunction (lua_Object object); void *lua_getuserdata (lua_Object object); void lua_pushnil (void); -void lua_pushnumber (float n); +void lua_pushnumber (double n); +void lua_pushlstring (char *s, long len); void lua_pushstring (char *s); -void lua_pushcfunction (lua_CFunction fn); +void lua_pushcclosure (lua_CFunction fn, int n); void lua_pushusertag (void *u, int tag); void lua_pushobject (lua_Object object); @@ -87,32 +101,37 @@ long lua_collectgarbage (long limit); /* =============================================================== */ -/* some useful macros */ +/* some useful macros/derived functions */ +int (lua_call) (char *name); #define lua_call(name) lua_callfunction(lua_getglobal(name)) +void (lua_pushref) (int ref); #define lua_pushref(ref) lua_pushobject(lua_getref(ref)) +int (lua_refobject) (lua_Object o, int l); #define lua_refobject(o,l) (lua_pushobject(o), lua_ref(l)) +void (lua_register) (char *n, lua_CFunction f); #define lua_register(n,f) (lua_pushcfunction(f), lua_setglobal(n)) +void (lua_pushuserdata) (void *u); #define lua_pushuserdata(u) lua_pushusertag(u, 0) +void (lua_pushcfunction) (lua_CFunction f); +#define lua_pushcfunction(f) lua_pushcclosure(f, 0) +int (lua_clonetag) (int t); +#define lua_clonetag(t) lua_copytagmethods(lua_newtag(), (t)) -/* ========================================================================== +/* ========================================================================== ** for compatibility with old versions. Avoid using these macros/functions -** If your program does not use any of these, define LUA_COMPAT2_5 to 0 +** If your program does need any of these, define LUA_COMPAT2_5 */ -#ifndef LUA_COMPAT2_5 -#define LUA_COMPAT2_5 1 -#endif - -#if LUA_COMPAT2_5 +#ifdef LUA_COMPAT2_5 lua_Object lua_setfallback (char *event, lua_CFunction fallback); @@ -139,3 +158,39 @@ lua_Object lua_setfallback (char *event, lua_CFunction fallback); #endif #endif + + + +/****************************************************************************** +* Copyright (c) 1994-1998 TeCGraf, PUC-Rio. All rights reserved. +* +* Permission is hereby granted, without written agreement and without license +* or royalty fees, to use, copy, modify, and distribute this software and its +* documentation for any purpose, including commercial applications, subject to +* the following conditions: +* +* - The above copyright notice and this permission notice shall appear in all +* copies or substantial portions of this software. +* +* - The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software in a +* product, an acknowledgment in the product documentation would be greatly +* appreciated (but it is not required). +* +* - Altered source versions must be plainly marked as such, and must not be +* misrepresented as being the original software. +* +* The authors specifically disclaim any warranties, including, but not limited +* to, the implied warranties of merchantability and fitness for a particular +* purpose. The software provided hereunder is on an "as is" basis, and the +* authors have no obligation to provide maintenance, support, updates, +* enhancements, or modifications. In no event shall TeCGraf, PUC-Rio, or the +* authors be held liable to any party for direct, indirect, special, +* incidental, or consequential damages arising out of the use of this software +* and its documentation. +* +* The Lua language and this implementation have been entirely designed and +* written by Waldemar Celes Filho, Roberto Ierusalimschy and +* Luiz Henrique de Figueiredo at TeCGraf, PUC-Rio. +* This implementation contains no third-party code. +******************************************************************************/ diff --git a/include/luadebug.h b/include/luadebug.h index 9392967..36726f7 100644 --- a/include/luadebug.h +++ b/include/luadebug.h @@ -1,14 +1,14 @@ /* -** LUA - Linguagem para Usuarios de Aplicacao -** Grupo de Tecnologia em Computacao Grafica -** TeCGraf - PUC-Rio -** $Id: luadebug.h,v 1.6 1996/03/20 17:05:44 roberto Exp $ +** $Id: luadebug.h,v 1.2 1998/06/19 16:14:09 roberto Exp $ +** Debugging API +** See Copyright Notice in lua.h */ #ifndef luadebug_h #define luadebug_h + #include "lua.h" typedef lua_Object lua_Function; @@ -24,8 +24,10 @@ char *lua_getobjname (lua_Object o, char **name); lua_Object lua_getlocal (lua_Function func, int local_number, char **name); int lua_setlocal (lua_Function func, int local_number); + extern lua_LHFunction lua_linehook; extern lua_CHFunction lua_callhook; extern int lua_debug; + #endif diff --git a/include/lualib.h b/include/lualib.h dissimilarity index 85% index 38baf45..583f1b5 100644 --- a/include/lualib.h +++ b/include/lualib.h @@ -1,29 +1,34 @@ -/* -** Libraries to be used in LUA programs -** Grupo de Tecnologia em Computacao Grafica -** TeCGraf - PUC-Rio -** $Id: lualib.h,v 1.13 1997/03/26 22:23:15 roberto Exp $ -*/ - -#ifndef lualib_h -#define lualib_h - -#include "lua.h" - -void iolib_open (void); -void strlib_open (void); -void mathlib_open (void); - - - -/* auxiliar functions (private) */ - -char *luaI_addchar (int c); -void luaI_emptybuff (void); -void luaI_addquoted (char *s); - -char *luaL_item_end (char *p); -int luaL_singlematch (int c, char *p); - -#endif - +/* +** $Id: lualib.h,v 1.4 1998/06/19 16:14:09 roberto Exp $ +** Lua standard libraries +** See Copyright Notice in lua.h +*/ + + +#ifndef lualib_h +#define lualib_h + +#include "lua.h" + + +void lua_iolibopen (void); +void lua_strlibopen (void); +void lua_mathlibopen (void); + + + + +/* To keep compatibility with old versions */ + +#define iolib_open lua_iolibopen +#define strlib_open lua_strlibopen +#define mathlib_open lua_mathlibopen + + + +/* Auxiliary functions (private) */ + +int luaI_singlematch (int c, char *p, char **ep); + +#endif + diff --git a/src/Makefile b/src/Makefile dissimilarity index 88% index 9fe13c8..7d01a92 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,72 +1,79 @@ -# makefile for lua distribution (main library) - -LUA= .. - -include $(LUA)/config - -OBJS= auxlib.o\ - fallback.o\ - func.o\ - hash.o\ - inout.o\ - lex.o\ - luamem.o\ - opcode.o\ - parser.o\ - table.o\ - tree.o\ - undump.o\ - zio.o - -SRCS= auxlib.c\ - auxlib.h\ - fallback.c\ - fallback.h\ - func.c\ - func.h\ - hash.c\ - hash.h\ - inout.c\ - inout.h\ - lex.c\ - lex.h\ - luamem.c\ - luamem.h\ - opcode.c\ - opcode.h\ - parser.c\ - parser.h\ - table.c\ - table.h\ - tree.c\ - tree.h\ - types.h\ - undump.c\ - undump.h\ - zio.c\ - zio.h\ - lua.stx - -SLIB= $(LIB)/liblua.a - -all: $(SLIB) - -$(SLIB): $(OBJS) - ar rcu $@ $(OBJS) - $(RANLIB) $@ - -clean: - rm -f $(OBJS) $(SLIB) - -co: - co -f -M $(SRCS) - -parser: - yacc -d lua.stx - rm -f parser.c parser.h - sed -e 's/yy/luaY_/g' y.tab.c > parser.c - sed -e 's/yy/luaY_/g' y.tab.h > parser.h - rm y.tab.c y.tab.h - -klean: clean - rm -f $(SRCS) +# makefile for lua basic library + +LUA= .. + +include $(LUA)/config + +OBJS= \ + lapi.o \ + lauxlib.o \ + lbuffer.o \ + lbuiltin.o \ + ldo.o \ + lfunc.o \ + lgc.o \ + llex.o \ + lmem.o \ + lobject.o \ + lparser.o \ + lstate.o \ + lstring.o \ + ltable.o \ + ltm.o \ + lundump.o \ + lvm.o \ + lzio.o + +SRCS= \ + lapi.c \ + lauxlib.c \ + lbuffer.c \ + lbuiltin.c \ + ldo.c \ + lfunc.c \ + lgc.c \ + llex.c \ + lmem.c \ + lobject.c \ + lparser.c \ + lstate.c \ + lstring.c \ + ltable.c \ + ltm.c \ + lundump.c \ + lvm.c \ + lzio.c \ + lapi.h \ + lbuiltin.h \ + ldo.h \ + lfunc.h \ + lgc.h \ + llex.h \ + lmem.h \ + lobject.h \ + lopcodes.h \ + lparser.h \ + lstate.h \ + lstring.h \ + ltable.h \ + ltm.h \ + lundump.h \ + lvm.h \ + lzio.h + +T= $(LIB)/liblua.a + +all: $T + +$T: $(OBJS) + $(AR) $@ $(OBJS) + $(RANLIB) $@ + +clean: + rm -f $(OBJS) $T + +co: + co -q -f -M $(SRCS) + +klean: clean + rm -f $(SRCS) diff --git a/src/auxlib.c b/src/auxlib.c deleted file mode 100644 index e6f71f2..0000000 --- a/src/auxlib.c +++ /dev/null @@ -1,81 +0,0 @@ -char *rcs_auxlib="$Id: auxlib.c,v 1.5 1997/04/14 15:30:03 roberto Exp $"; - -#include -#include -#include - -#include "lua.h" -#include "auxlib.h" -#include "luadebug.h" - - - -int luaI_findstring (char *name, char *list[]) -{ - int i; - for (i=0; list[i]; i++) - if (strcmp(list[i], name) == 0) - return i; - return -1; /* name not found */ -} - - -void luaL_arg_check(int cond, int numarg, char *extramsg) -{ - if (!cond) { - char *funcname; - lua_getobjname(lua_stackedfunction(0), &funcname); - if (funcname == NULL) - funcname = "???"; - if (extramsg == NULL) - luaL_verror("bad argument #%d to function `%s'", numarg, funcname); - else - luaL_verror("bad argument #%d to function `%s' (%s)", - numarg, funcname, extramsg); - } -} - -char *luaL_check_string (int numArg) -{ - lua_Object o = lua_getparam(numArg); - luaL_arg_check(lua_isstring(o), numArg, "string expected"); - return lua_getstring(o); -} - -char *luaL_opt_string (int numArg, char *def) -{ - return (lua_getparam(numArg) == LUA_NOOBJECT) ? def : - luaL_check_string(numArg); -} - -double luaL_check_number (int numArg) -{ - lua_Object o = lua_getparam(numArg); - luaL_arg_check(lua_isnumber(o), numArg, "number expected"); - return lua_getnumber(o); -} - - -double luaL_opt_number (int numArg, double def) -{ - return (lua_getparam(numArg) == LUA_NOOBJECT) ? def : - luaL_check_number(numArg); -} - -void luaL_openlib (struct luaL_reg *l, int n) -{ - int i; - for (i=0; i -#include - -#include "auxlib.h" -#include "luamem.h" -#include "fallback.h" -#include "opcode.h" -#include "lua.h" -#include "table.h" -#include "tree.h" -#include "hash.h" - - - -/* ------------------------------------------- -** Reference routines -*/ - -static struct ref { - TObject o; - enum {LOCK, HOLD, FREE, COLLECTED} status; -} *refArray = NULL; -static int refSize = 0; - -int luaI_ref (TObject *object, int lock) -{ - int i; - int oldSize; - if (ttype(object) == LUA_T_NIL) - return -1; /* special ref for nil */ - for (i=0; i= 0 && ref < refSize) - refArray[ref].status = FREE; -} - - -TObject *luaI_getref (int ref) -{ - static TObject nul = {LUA_T_NIL, {0}}; - if (ref == -1) - return &nul; - if (ref >= 0 && ref < refSize && - (refArray[ref].status == LOCK || refArray[ref].status == HOLD)) - return &refArray[ref].o; - else - return NULL; -} - - -void luaI_travlock (int (*fn)(TObject *)) -{ - int i; - for (i=0; i= IMtable_size) { - luaI_initfallbacks(); - IMtable_size = growvector(&luaI_IMtable, IMtable_size, - struct IM, memEM, MAX_INT); - } - init_entry(last_tag); - return last_tag; -} - - -static void checktag (int tag) -{ - if (!(last_tag <= tag && tag <= 0)) - luaL_verror("%d is not a valid tag", tag); -} - -void luaI_realtag (int tag) -{ - if (!(last_tag <= tag && tag < LUA_T_NIL)) - luaL_verror("tag %d is not result of `newtag'", tag); -} - - -void luaI_settag (int tag, TObject *o) -{ - luaI_realtag(tag); - switch (ttype(o)) { - case LUA_T_ARRAY: - o->value.a->htag = tag; - break; - case LUA_T_USERDATA: - o->value.ts->tag = tag; - break; - default: - luaL_verror("cannot change the tag of a %s", luaI_typenames[-ttype(o)]); - } -} - - -int luaI_efectivetag (TObject *o) -{ - lua_Type t = ttype(o); - if (t == LUA_T_USERDATA) { - int tag = o->value.ts->tag; - return (tag >= 0) ? LUA_T_USERDATA : tag; - } - else if (t == LUA_T_ARRAY) - return o->value.a->htag; - else return t; -} - - -void luaI_gettagmethod (void) -{ - int t = (int)luaL_check_number(1); - int e = luaI_checkevent(luaL_check_string(2), luaI_eventname); - checktag(t); - if (validevent(t, e)) - luaI_pushobject(luaI_getim(t,e)); -} - - -void luaI_settagmethod (void) -{ - int t = (int)luaL_check_number(1); - int e = luaI_checkevent(luaL_check_string(2), luaI_eventname); - lua_Object func = lua_getparam(3); - checktag(t); - if (!validevent(t, e)) - luaL_verror("cannot change internal method `%s' for tag %d", - luaI_eventname[e], t); - luaL_arg_check(lua_isnil(func) || lua_isfunction(func), - 3, "function expected"); - luaI_pushobject(luaI_getim(t,e)); - *luaI_getim(t, e) = *luaI_Address(func); -} - - -static void stderrorim (void) -{ - lua_Object s = lua_getparam(1); - if (lua_isstring(s)) - fprintf(stderr, "lua: %s\n", lua_getstring(s)); -} - -static TObject errorim = {LUA_T_CFUNCTION, {stderrorim}}; - - -TObject *luaI_geterrorim (void) -{ - return &errorim; -} - -void luaI_seterrormethod (void) -{ - lua_Object func = lua_getparam(1); - luaL_arg_check(lua_isnil(func) || lua_isfunction(func), - 1, "function expected"); - luaI_pushobject(&errorim); - errorim = *luaI_Address(func); -} - -char *luaI_travfallbacks (int (*fn)(TObject *)) -{ - int e; - if (fn(&errorim)) - return "error"; - for (e=IM_GETTABLE; e<=IM_FUNCTION; e++) { /* ORDER IM */ - int t; - for (t=0; t>=last_tag; t--) - if (fn(luaI_getim(t,e))) - return luaI_eventname[e]; - } - return NULL; -} - - -/* -* =================================================================== -* compatibility with old fallback system -*/ -#if LUA_COMPAT2_5 - -static void errorFB (void) -{ - lua_Object o = lua_getparam(1); - if (lua_isstring(o)) - fprintf (stderr, "lua: %s\n", lua_getstring(o)); - else - fprintf(stderr, "lua: unknown error\n"); -} - - -static void nilFB (void) { } - - -static void typeFB (void) -{ - lua_error("unexpected type"); -} - - -static void fillvalids (IMS e, TObject *func) -{ - int t; - for (t=LUA_T_NIL; t<=LUA_T_USERDATA; t++) - if (validevent(t, e)) - *luaI_getim(t, e) = *func; -} - - -void luaI_setfallback (void) -{ - static char *oldnames [] = {"error", "getglobal", "arith", "order", NULL}; - TObject oldfunc; - lua_CFunction replace; - char *name = luaL_check_string(1); - lua_Object func = lua_getparam(2); - luaI_initfallbacks(); - luaL_arg_check(lua_isfunction(func), 2, "function expected"); - switch (luaI_findstring(name, oldnames)) { - case 0: /* old error fallback */ - oldfunc = errorim; - errorim = *luaI_Address(func); - replace = errorFB; - break; - case 1: /* old getglobal fallback */ - oldfunc = *luaI_getim(LUA_T_NIL, IM_GETGLOBAL); - *luaI_getim(LUA_T_NIL, IM_GETGLOBAL) = *luaI_Address(func); - replace = nilFB; - break; - case 2: { /* old arith fallback */ - int i; - oldfunc = *luaI_getim(LUA_T_NUMBER, IM_POW); - for (i=IM_ADD; i<=IM_UNM; i++) /* ORDER IM */ - fillvalids(i, luaI_Address(func)); - replace = typeFB; - break; - } - case 3: { /* old order fallback */ - int i; - oldfunc = *luaI_getim(LUA_T_LINE, IM_LT); - for (i=IM_LT; i<=IM_GE; i++) /* ORDER IM */ - fillvalids(i, luaI_Address(func)); - replace = typeFB; - break; - } - default: { - int e; - if ((e = luaI_findstring(name, luaI_eventname)) >= 0) { - oldfunc = *luaI_getim(LUA_T_LINE, e); - fillvalids(e, luaI_Address(func)); - replace = (e == IM_GC || e == IM_INDEX) ? nilFB : typeFB; - } - else { - luaL_verror("`%s' is not a valid fallback name", name); - replace = NULL; /* to avoid warnings */ - } - } - } - if (oldfunc.ttype != LUA_T_NIL) - luaI_pushobject(&oldfunc); - else - lua_pushcfunction(replace); -} -#endif diff --git a/src/fallback.h b/src/fallback.h deleted file mode 100644 index 7e314c9..0000000 --- a/src/fallback.h +++ /dev/null @@ -1,65 +0,0 @@ -/* -** $Id: fallback.h,v 1.23 1997/04/24 22:59:57 roberto Exp $ -*/ - -#ifndef fallback_h -#define fallback_h - -#include "lua.h" -#include "opcode.h" - -/* -* WARNING: if you change the order of this enumeration, -* grep "ORDER IM" -*/ -typedef enum { - IM_GETTABLE = 0, - IM_SETTABLE, - IM_INDEX, - IM_GETGLOBAL, - IM_SETGLOBAL, - IM_ADD, - IM_SUB, - IM_MUL, - IM_DIV, - IM_POW, - IM_UNM, - IM_LT, - IM_LE, - IM_GT, - IM_GE, - IM_CONCAT, - IM_GC, - IM_FUNCTION -} IMS; - -#define IM_N 18 - - -extern struct IM { - TObject int_method[IM_N]; -} *luaI_IMtable; - -extern char *luaI_eventname[]; - -#define luaI_getim(tag,event) (&luaI_IMtable[-(tag)].int_method[event]) -#define luaI_getimbyObj(o,e) (luaI_getim(luaI_efectivetag(o),(e))) - -void luaI_setfallback (void); -int luaI_ref (TObject *object, int lock); -TObject *luaI_getref (int ref); -void luaI_travlock (int (*fn)(TObject *)); -void luaI_invalidaterefs (void); -char *luaI_travfallbacks (int (*fn)(TObject *)); - -void luaI_settag (int tag, TObject *o); -void luaI_realtag (int tag); -TObject *luaI_geterrorim (void); -int luaI_efectivetag (TObject *o); -void luaI_settagmethod (void); -void luaI_gettagmethod (void); -void luaI_seterrormethod (void); -void luaI_initfallbacks (void); - -#endif - diff --git a/src/func.c b/src/func.c deleted file mode 100644 index 36f7e19..0000000 --- a/src/func.c +++ /dev/null @@ -1,166 +0,0 @@ -#include - -#include "luadebug.h" -#include "table.h" -#include "luamem.h" -#include "func.h" -#include "opcode.h" -#include "inout.h" - - -static TFunc *function_root = NULL; -static LocVar *currvars = NULL; -static int numcurrvars = 0; -static int maxcurrvars = 0; - - -/* -** Initialize TFunc struct -*/ -void luaI_initTFunc (TFunc *f) -{ - f->next = NULL; - f->marked = 0; - f->size = 0; - f->code = NULL; - f->lineDefined = 0; - f->fileName = lua_parsedfile; - f->locvars = NULL; -} - -/* -** Insert function in list for GC -*/ -void luaI_insertfunction (TFunc *f) -{ - lua_pack(); - f->next = function_root; - function_root = f; - f->marked = 0; -} - - -/* -** Free function -*/ -void luaI_freefunc (TFunc *f) -{ - luaI_free (f->code); - luaI_free (f->locvars); - luaI_free (f); -} - - -void luaI_funcfree (TFunc *l) -{ - while (l) { - TFunc *next = l->next; - luaI_freefunc(l); - l = next; - } -} - -/* -** Garbage collection function. -*/ -TFunc *luaI_funccollector (long *acum) -{ - TFunc *curr = function_root; - TFunc *prev = NULL; - TFunc *frees = NULL; - long counter = 0; - while (curr) { - TFunc *next = curr->next; - if (!curr->marked) { - if (prev == NULL) - function_root = next; - else - prev->next = next; - curr->next = frees; - frees = curr; - ++counter; - } - else { - curr->marked = 0; - prev = curr; - } - curr = next; - } - *acum += counter; - return frees; -} - - -void lua_funcinfo (lua_Object func, char **filename, int *linedefined) -{ - TObject *f = luaI_Address(func); - if (f->ttype == LUA_T_MARK || f->ttype == LUA_T_FUNCTION) - { - *filename = f->value.tf->fileName; - *linedefined = f->value.tf->lineDefined; - } - else if (f->ttype == LUA_T_CMARK || f->ttype == LUA_T_CFUNCTION) - { - *filename = "(C)"; - *linedefined = -1; - } -} - -/* -** Stores information to know that variable has been declared in given line -*/ -void luaI_registerlocalvar (TaggedString *varname, int line) -{ - if (numcurrvars >= maxcurrvars) - maxcurrvars = growvector(&currvars, maxcurrvars, LocVar, "", MAX_WORD); - currvars[numcurrvars].varname = varname; - currvars[numcurrvars].line = line; - numcurrvars++; -} - -/* -** Stores information to know that variable has been out of scope in given line -*/ -void luaI_unregisterlocalvar (int line) -{ - luaI_registerlocalvar(NULL, line); -} - -/* -** Copies "currvars" into a new area and store it in function header. -** The values (varname = NULL, line = -1) signal the end of vector. -*/ -void luaI_closelocalvars (TFunc *func) -{ - func->locvars = newvector (numcurrvars+1, LocVar); - memcpy (func->locvars, currvars, numcurrvars*sizeof(LocVar)); - func->locvars[numcurrvars].varname = NULL; - func->locvars[numcurrvars].line = -1; - numcurrvars = 0; /* prepares for next function */ -} - -/* -** Look for n-esim local variable at line "line" in function "func". -** Returns NULL if not found. -*/ -char *luaI_getlocalname (TFunc *func, int local_number, int line) -{ - int count = 0; - char *varname = NULL; - LocVar *lv = func->locvars; - if (lv == NULL) - return NULL; - for (; lv->line != -1 && lv->line < line; lv++) - { - if (lv->varname) /* register */ - { - if (++count == local_number) - varname = lv->varname->str; - } - else /* unregister */ - if (--count < local_number) - varname = NULL; - } - return varname; -} - diff --git a/src/func.h b/src/func.h deleted file mode 100644 index c79bbb7..0000000 --- a/src/func.h +++ /dev/null @@ -1,45 +0,0 @@ -/* -** $Id: func.h,v 1.9 1997/05/14 18:38:29 roberto Exp $ -*/ - -#ifndef func_h -#define func_h - -#include "types.h" -#include "lua.h" -#include "tree.h" - -typedef struct LocVar -{ - TaggedString *varname; /* NULL signals end of scope */ - int line; -} LocVar; - - -/* -** Function Headers -*/ -typedef struct TFunc -{ - struct TFunc *next; - int marked; - int size; - Byte *code; - int lineDefined; - char *fileName; - LocVar *locvars; -} TFunc; - -TFunc *luaI_funccollector (long *cont); -void luaI_funcfree (TFunc *l); -void luaI_insertfunction (TFunc *f); - -void luaI_initTFunc (TFunc *f); -void luaI_freefunc (TFunc *f); - -void luaI_registerlocalvar (TaggedString *varname, int line); -void luaI_unregisterlocalvar (int line); -void luaI_closelocalvars (TFunc *func); -char *luaI_getlocalname (TFunc *func, int local_number, int line); - -#endif diff --git a/src/hash.c b/src/hash.c deleted file mode 100644 index b927602..0000000 --- a/src/hash.c +++ /dev/null @@ -1,332 +0,0 @@ -/* -** hash.c -** hash manager for lua -*/ - -char *rcs_hash="$Id: hash.c,v 2.43 1997/05/14 18:38:29 roberto Exp $"; - - -#include "luamem.h" -#include "opcode.h" -#include "hash.h" -#include "table.h" -#include "lua.h" -#include "auxlib.h" - - -#define nhash(t) ((t)->nhash) -#define nuse(t) ((t)->nuse) -#define markarray(t) ((t)->mark) -#define nodevector(t) ((t)->node) -#define node(t,i) (&(t)->node[i]) -#define ref(n) (&(n)->ref) -#define val(n) (&(n)->val) - - -#define REHASH_LIMIT 0.70 /* avoid more than this % full */ - -#define TagDefault LUA_T_ARRAY; - - -static Hash *listhead = NULL; - - -/* hash dimensions values */ -static Long dimensions[] = - {5L, 11L, 23L, 47L, 97L, 197L, 397L, 797L, 1597L, 3203L, 6421L, - 12853L, 25717L, 51437L, 102811L, 205619L, 411233L, 822433L, - 1644817L, 3289613L, 6579211L, 13158023L, MAX_INT}; - -int luaI_redimension (int nhash) -{ - int i; - for (i=0; dimensions[i] nhash) - return dimensions[i]; - } - lua_error("table overflow"); - return 0; /* to avoid warnings */ -} - - -int lua_equalObj (TObject *t1, TObject *t2) -{ - if (ttype(t1) != ttype(t2)) return 0; - switch (ttype(t1)) - { - case LUA_T_NIL: return 1; - case LUA_T_NUMBER: return nvalue(t1) == nvalue(t2); - case LUA_T_STRING: case LUA_T_USERDATA: return svalue(t1) == svalue(t2); - case LUA_T_ARRAY: return avalue(t1) == avalue(t2); - case LUA_T_FUNCTION: return t1->value.tf == t2->value.tf; - case LUA_T_CFUNCTION: return fvalue(t1) == fvalue(t2); - default: - lua_error("internal error in `lua_equalObj'"); - return 0; /* UNREACHEABLE */ - } -} - - -static long int hashindex (TObject *ref) -{ - long int h; - switch (ttype(ref)) { - case LUA_T_NUMBER: - h = (long int)nvalue(ref); break; - case LUA_T_STRING: case LUA_T_USERDATA: - h = tsvalue(ref)->hash; break; - case LUA_T_FUNCTION: - h = (IntPoint)ref->value.tf; break; - case LUA_T_CFUNCTION: - h = (IntPoint)fvalue(ref); break; - case LUA_T_ARRAY: - h = (IntPoint)avalue(ref); break; - default: - lua_error ("unexpected type to index table"); - h = 0; /* UNREACHEABLE */ - } - if (h < 0) h = -h; - return h; -} - - -static int present (Hash *t, TObject *key) -{ - long int h = hashindex(key); - int tsize = nhash(t); - int h1 = h%tsize; - TObject *rf = ref(node(t, h1)); - if (ttype(rf) != LUA_T_NIL && !lua_equalObj(key, rf)) { - int h2 = h%(tsize-2) + 1; - do { - h1 = (h1+h2)%tsize; - rf = ref(node(t, h1)); - } while (ttype(rf) != LUA_T_NIL && !lua_equalObj(key, rf)); - } - return h1; -} - - -/* -** Alloc a vector node -*/ -static Node *hashnodecreate (int nhash) -{ - int i; - Node *v = newvector (nhash, Node); - for (i=0; ihtag = TagDefault; - return t; -} - -/* -** Delete a hash -*/ -static void hashdelete (Hash *t) -{ - luaI_free (nodevector(t)); - luaI_free(t); -} - - -/* -** Mark a hash and check its elements -*/ -void lua_hashmark (Hash *h) -{ - if (markarray(h) == 0) - { - int i; - markarray(h) = 1; - for (i=0; iref); - lua_markobject(&n->val); - } - } - } -} - - -void luaI_hashcallIM (Hash *l) -{ - TObject t; - ttype(&t) = LUA_T_ARRAY; - for (; l; l=l->next) { - avalue(&t) = l; - luaI_gcIM(&t); - } -} - - -void luaI_hashfree (Hash *frees) -{ - while (frees) { - Hash *next = frees->next; - hashdelete(frees); - frees = next; - } -} - - -Hash *luaI_hashcollector (long *acum) -{ - Hash *curr_array = listhead, *prev = NULL, *frees = NULL; - long counter = 0; - while (curr_array != NULL) { - Hash *next = curr_array->next; - if (markarray(curr_array) != 1) { - if (prev == NULL) - listhead = next; - else - prev->next = next; - curr_array->next = frees; - frees = curr_array; - ++counter; - } - else { - markarray(curr_array) = 0; - prev = curr_array; - } - curr_array = next; - } - *acum += counter; - return frees; -} - - -/* -** Create a new array -** This function inserts the new array in the array list. It also -** executes garbage collection if the number of arrays created -** exceed a pre-defined range. -*/ -Hash *lua_createarray (int nhash) -{ - Hash *array; - lua_pack(); - array = hashcreate(nhash); - array->next = listhead; - listhead = array; - return array; -} - - -/* -** Rehash: -** Check if table has deleted slots. It it has, it does not need to -** grow, since rehash will reuse them. -*/ -static int emptyslots (Hash *t) -{ - int i; - for (i=nhash(t)-1; i>=0; i--) { - Node *n = node(t, i); - if (ttype(ref(n)) != LUA_T_NIL && ttype(val(n)) == LUA_T_NIL) - return 1; - } - return 0; -} - -static void rehash (Hash *t) -{ - int nold = nhash(t); - Node *vold = nodevector(t); - int i; - if (!emptyslots(t)) - nhash(t) = luaI_redimension(nhash(t)); - nodevector(t) = hashnodecreate(nhash(t)); - for (i=0; i (float)nhash(t)*REHASH_LIMIT) { - rehash(t); - n = node(t, present(t, ref)); - } - *ref(n) = *ref; - ttype(val(n)) = LUA_T_NIL; - } - return (val(n)); -} - - -/* -** Internal function to manipulate arrays. -** Given an array object and a reference value, return the next element -** in the hash. -** This function pushs the element value and its reference to the stack. -*/ -static void hashnext (Hash *t, int i) -{ - Node *n; - int tsize = nhash(t); - if (i >= tsize) - return; - n = node(t, i); - while (ttype(ref(n)) == LUA_T_NIL || ttype(val(n)) == LUA_T_NIL) { - if (++i >= tsize) - return; - n = node(t, i); - } - luaI_pushobject(ref(node(t,i))); - luaI_pushobject(val(node(t,i))); -} - -void lua_next (void) -{ - Hash *t; - lua_Object o = lua_getparam(1); - lua_Object r = lua_getparam(2); - luaL_arg_check(lua_istable(o), 1, "table expected"); - luaL_arg_check(r != LUA_NOOBJECT, 2, "value expected"); - t = avalue(luaI_Address(o)); - if (lua_isnil(r)) - hashnext(t, 0); - else - hashnext(t, present(t, luaI_Address(r))+1); -} diff --git a/src/hash.h b/src/hash.h deleted file mode 100644 index 1bc758b..0000000 --- a/src/hash.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -** hash.h -** hash manager for lua -** $Id: hash.h,v 2.16 1997/05/14 18:38:29 roberto Exp $ -*/ - -#ifndef hash_h -#define hash_h - -#include "types.h" -#include "opcode.h" - -typedef struct node { - TObject ref; - TObject val; -} Node; - -typedef struct Hash { - struct Hash *next; - Node *node; - int nhash; - int nuse; - int htag; - char mark; -} Hash; - - -int lua_equalObj (TObject *t1, TObject *t2); -int luaI_redimension (int nhash); -Hash *lua_createarray (int nhash); -void lua_hashmark (Hash *h); -Hash *luaI_hashcollector (long *count); -void luaI_hashcallIM (Hash *l); -void luaI_hashfree (Hash *frees); -TObject *lua_hashget (Hash *t, TObject *ref); -TObject *lua_hashdefine (Hash *t, TObject *ref); -void lua_next (void); - -#endif diff --git a/src/inout.c b/src/inout.c deleted file mode 100644 index 5d71061..0000000 --- a/src/inout.c +++ /dev/null @@ -1,408 +0,0 @@ -/* -** inout.c -** Provide function to realise the input/output function and debugger -** facilities. -** Also provides some predefined lua functions. -*/ - -char *rcs_inout="$Id: inout.c,v 2.69 1997/06/27 22:38:49 roberto Exp $"; - -#include -#include - -#include "auxlib.h" -#include "fallback.h" -#include "hash.h" -#include "inout.h" -#include "lex.h" -#include "lua.h" -#include "luamem.h" -#include "luamem.h" -#include "opcode.h" -#include "table.h" -#include "tree.h" -#include "undump.h" -#include "zio.h" - - -/* Exported variables */ -Word lua_linenumber; -char *lua_parsedfile; - - -char *luaI_typenames[] = { /* ORDER LUA_T */ - "userdata", "line", "cmark", "mark", "function", - "function", "table", "string", "number", "nil", - NULL -}; - - - -void luaI_setparsedfile (char *name) -{ - lua_parsedfile = luaI_createfixedstring(name)->str; -} - - -int lua_doFILE (FILE *f, int bin) -{ - ZIO z; - luaZ_Fopen(&z, f); - if (bin) - return luaI_undump(&z); - else { - lua_setinput(&z); - return lua_domain(); - } -} - - -int lua_dofile (char *filename) -{ - int status; - int c; - FILE *f = (filename == NULL) ? stdin : fopen(filename, "r"); - if (f == NULL) - return 2; - luaI_setparsedfile(filename?filename:"(stdin)"); - c = fgetc(f); - ungetc(c, f); - if (c == ID_CHUNK) { - f = freopen(filename, "rb", f); /* set binary mode */ - status = lua_doFILE(f, 1); - } - else { - if (c == '#') - while ((c=fgetc(f)) != '\n') /* skip first line */; - status = lua_doFILE(f, 0); - } - if (f != stdin) - fclose(f); - return status; -} - - - -#define SIZE_PREF 20 /* size of string prefix to appear in error messages */ - - -int lua_dobuffer (char *buff, int size) -{ - int status; - ZIO z; - luaI_setparsedfile("(buffer)"); - luaZ_mopen(&z, buff, size); - status = luaI_undump(&z); - return status; -} - - -int lua_dostring (char *str) -{ - int status; - char buff[SIZE_PREF+25]; - char *temp; - ZIO z; - if (str == NULL) return 1; - sprintf(buff, "(dostring) >> %.20s", str); - temp = strchr(buff, '\n'); - if (temp) *temp = 0; /* end string after first line */ - luaI_setparsedfile(buff); - luaZ_sopen(&z, str); - lua_setinput(&z); - status = lua_domain(); - return status; -} - - - - -static int passresults (void) -{ - int arg = 0; - lua_Object obj; - while ((obj = lua_getresult(++arg)) != LUA_NOOBJECT) - lua_pushobject(obj); - return arg-1; -} - - -static void packresults (void) -{ - int arg = 0; - lua_Object obj; - lua_Object table = lua_createtable(); - while ((obj = lua_getresult(++arg)) != LUA_NOOBJECT) { - lua_pushobject(table); - lua_pushnumber(arg); - lua_pushobject(obj); - lua_rawsettable(); - } - lua_pushobject(table); - lua_pushstring("n"); - lua_pushnumber(arg-1); - lua_rawsettable(); - lua_pushobject(table); /* final result */ -} - -/* -** Internal function: do a string -*/ -static void lua_internaldostring (void) -{ - lua_Object err = lua_getparam(2); - if (err != LUA_NOOBJECT) { /* set new error method */ - luaL_arg_check(lua_isnil(err) || lua_isfunction(err), 2, - "must be a valid error handler"); - lua_pushobject(err); - err = lua_seterrormethod(); - } - if (lua_dostring(luaL_check_string(1)) == 0) - if (passresults() == 0) - lua_pushuserdata(NULL); /* at least one result to signal no errors */ - if (err != LUA_NOOBJECT) { /* restore old error method */ - lua_pushobject(err); - lua_seterrormethod(); - } -} - -/* -** Internal function: do a file -*/ -static void lua_internaldofile (void) -{ - char *fname = luaL_opt_string(1, NULL); - if (lua_dofile(fname) == 0) - if (passresults() == 0) - lua_pushuserdata(NULL); /* at least one result to signal no errors */ -} - - -static char *tostring (lua_Object obj) -{ - TObject *o = luaI_Address(obj); - switch (ttype(o)) { - case LUA_T_NUMBER: case LUA_T_STRING: - return lua_getstring(obj); - case LUA_T_ARRAY: case LUA_T_FUNCTION: - case LUA_T_CFUNCTION: case LUA_T_NIL: - return luaI_typenames[-ttype(o)]; - case LUA_T_USERDATA: { - char *buff = luaI_buffer(30); - sprintf(buff, "userdata: %p", o->value.ts->u.v); - return buff; - } - default: return ""; - } -} - -static void luaI_tostring (void) -{ - lua_pushstring(tostring(lua_getparam(1))); -} - -static void luaI_print (void) -{ - int i = 1; - lua_Object obj; - while ((obj = lua_getparam(i++)) != LUA_NOOBJECT) - printf("%s\n", tostring(obj)); -} - -static void luaI_type (void) -{ - lua_Object o = lua_getparam(1); - luaL_arg_check(o != LUA_NOOBJECT, 1, "no argument"); - lua_pushstring(luaI_typenames[-ttype(luaI_Address(o))]); - lua_pushnumber(lua_tag(o)); -} - -/* -** Internal function: convert an object to a number -*/ -static void lua_obj2number (void) -{ - lua_Object o = lua_getparam(1); - if (lua_isnumber(o)) - lua_pushnumber(lua_getnumber(o)); -} - - -static void luaI_error (void) -{ - char *s = lua_getstring(lua_getparam(1)); - if (s == NULL) s = "(no message)"; - lua_error(s); -} - -static void luaI_assert (void) -{ - lua_Object p = lua_getparam(1); - if (p == LUA_NOOBJECT || lua_isnil(p)) - lua_error("assertion failed!"); -} - -static void luaI_setglobal (void) -{ - lua_Object value = lua_getparam(2); - luaL_arg_check(value != LUA_NOOBJECT, 2, NULL); - lua_pushobject(value); - lua_setglobal(luaL_check_string(1)); - lua_pushobject(value); /* return given value */ -} - -static void luaI_rawsetglobal (void) -{ - lua_Object value = lua_getparam(2); - luaL_arg_check(value != LUA_NOOBJECT, 2, NULL); - lua_pushobject(value); - lua_rawsetglobal(luaL_check_string(1)); - lua_pushobject(value); /* return given value */ -} - -static void luaI_getglobal (void) -{ - lua_pushobject(lua_getglobal(luaL_check_string(1))); -} - -static void luaI_rawgetglobal (void) -{ - lua_pushobject(lua_rawgetglobal(luaL_check_string(1))); -} - -static void luatag (void) -{ - lua_pushnumber(lua_tag(lua_getparam(1))); -} - - -static int getnarg (lua_Object table) -{ - lua_Object temp; - /* temp = table.n */ - lua_pushobject(table); lua_pushstring("n"); temp = lua_gettable(); - return (lua_isnumber(temp) ? lua_getnumber(temp) : MAX_WORD); -} - -static void luaI_call (void) -{ - lua_Object f = lua_getparam(1); - lua_Object arg = lua_getparam(2); - int withtable = (strcmp(luaL_opt_string(3, ""), "pack") == 0); - int narg, i; - luaL_arg_check(lua_isfunction(f), 1, "function expected"); - luaL_arg_check(lua_istable(arg), 2, "table expected"); - narg = getnarg(arg); - /* push arg[1...n] */ - for (i=0; i - - -extern Word lua_linenumber; -extern Word lua_debugline; -extern char *lua_parsedfile; - -void luaI_setparsedfile (char *name); - -void luaI_predefine (void); - -int lua_dobuffer (char *buff, int size); -int lua_doFILE (FILE *f, int bin); - - -#endif diff --git a/src/lapi.c b/src/lapi.c new file mode 100644 index 0000000..9db0278 --- /dev/null +++ b/src/lapi.c @@ -0,0 +1,631 @@ +/* +** $Id: lapi.c,v 1.25 1998/06/05 22:17:44 roberto Exp $ +** Lua API +** See Copyright Notice in lua.h +*/ + + +#include +#include + +#include "lapi.h" +#include "lauxlib.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lua.h" +#include "luadebug.h" +#include "lvm.h" + + +char lua_ident[] = "$Lua: " LUA_VERSION " " LUA_COPYRIGHT " $\n" + "$Autores: " LUA_AUTHORS " $"; + + + +TObject *luaA_Address (lua_Object o) +{ + return Address(o); +} + + +static int normalized_type (TObject *o) +{ + int t = ttype(o); + switch (t) { + case LUA_T_PMARK: + return LUA_T_PROTO; + case LUA_T_CMARK: + return LUA_T_CPROTO; + case LUA_T_CLMARK: + return LUA_T_CLOSURE; + default: + return t; + } +} + + +static void set_normalized (TObject *d, TObject *s) +{ + d->value = s->value; + d->ttype = normalized_type(s); +} + + +static TObject *luaA_protovalue (TObject *o) +{ + return (normalized_type(o) == LUA_T_CLOSURE) ? protovalue(o) : o; +} + + +void luaA_packresults (void) +{ + luaV_pack(L->Cstack.lua2C, L->Cstack.num, L->stack.top); + incr_top; +} + + +int luaA_passresults (void) +{ + luaD_checkstack(L->Cstack.num); + memcpy(L->stack.top, L->Cstack.lua2C+L->stack.stack, + L->Cstack.num*sizeof(TObject)); + L->stack.top += L->Cstack.num; + return L->Cstack.num; +} + + +static void checkCparams (int nParams) +{ + if (L->stack.top-L->stack.stack < L->Cstack.base+nParams) + lua_error("API error - wrong number of arguments in C2lua stack"); +} + + +static lua_Object put_luaObject (TObject *o) +{ + luaD_openstack((L->stack.top-L->stack.stack)-L->Cstack.base); + L->stack.stack[L->Cstack.base++] = *o; + return L->Cstack.base; /* this is +1 real position (see Ref) */ +} + + +static lua_Object put_luaObjectonTop (void) +{ + luaD_openstack((L->stack.top-L->stack.stack)-L->Cstack.base); + L->stack.stack[L->Cstack.base++] = *(--L->stack.top); + return L->Cstack.base; /* this is +1 real position (see Ref) */ +} + + +lua_Object lua_pop (void) +{ + checkCparams(1); + return put_luaObjectonTop(); +} + + +/* +** Get a parameter, returning the object handle or LUA_NOOBJECT on error. +** 'number' must be 1 to get the first parameter. +*/ +lua_Object lua_lua2C (int number) +{ + if (number <= 0 || number > L->Cstack.num) return LUA_NOOBJECT; + /* Ref(L->stack.stack+(L->Cstack.lua2C+number-1)) == + L->stack.stack+(L->Cstack.lua2C+number-1)-L->stack.stack+1 == */ + return L->Cstack.lua2C+number; +} + + +int lua_callfunction (lua_Object function) +{ + if (function == LUA_NOOBJECT) + return 1; + else { + luaD_openstack((L->stack.top-L->stack.stack)-L->Cstack.base); + set_normalized(L->stack.stack+L->Cstack.base, Address(function)); + return luaD_protectedrun(MULT_RET); + } +} + + +lua_Object lua_gettagmethod (int tag, char *event) +{ + return put_luaObject(luaT_gettagmethod(tag, event)); +} + + +lua_Object lua_settagmethod (int tag, char *event) +{ + checkCparams(1); + luaT_settagmethod(tag, event, L->stack.top-1); + return put_luaObjectonTop(); +} + + +lua_Object lua_seterrormethod (void) +{ + TObject temp = L->errorim; + checkCparams(1); + L->errorim = *(--L->stack.top); + return put_luaObject(&temp); +} + + +lua_Object lua_gettable (void) +{ + checkCparams(2); + luaV_gettable(); + return put_luaObjectonTop(); +} + + +lua_Object lua_rawgettable (void) +{ + checkCparams(2); + if (ttype(L->stack.top-2) != LUA_T_ARRAY) + lua_error("indexed expression not a table in rawgettable"); + else { + TObject *h = luaH_get(avalue(L->stack.top-2), L->stack.top-1); + --L->stack.top; + if (h != NULL) + *(L->stack.top-1) = *h; + else + ttype(L->stack.top-1) = LUA_T_NIL; + } + return put_luaObjectonTop(); +} + + +void lua_settable (void) +{ + checkCparams(3); + luaV_settable(L->stack.top-3, 1); +} + + +void lua_rawsettable (void) +{ + checkCparams(3); + luaV_settable(L->stack.top-3, 0); +} + + +lua_Object lua_createtable (void) +{ + TObject o; + luaC_checkGC(); + avalue(&o) = luaH_new(0); + ttype(&o) = LUA_T_ARRAY; + return put_luaObject(&o); +} + + +lua_Object lua_getglobal (char *name) +{ + luaD_checkstack(2); /* may need that to call T.M. */ + luaV_getglobal(luaS_new(name)); + return put_luaObjectonTop(); +} + + +lua_Object lua_rawgetglobal (char *name) +{ + TaggedString *ts = luaS_new(name); + return put_luaObject(&ts->u.s.globalval); +} + + +void lua_setglobal (char *name) +{ + checkCparams(1); + luaD_checkstack(2); /* may need that to call T.M. */ + luaV_setglobal(luaS_new(name)); +} + + +void lua_rawsetglobal (char *name) +{ + TaggedString *ts = luaS_new(name); + checkCparams(1); + luaS_rawsetglobal(ts, --L->stack.top); +} + + + +int lua_isnil (lua_Object o) +{ + return (o!= LUA_NOOBJECT) && (ttype(Address(o)) == LUA_T_NIL); +} + +int lua_istable (lua_Object o) +{ + return (o!= LUA_NOOBJECT) && (ttype(Address(o)) == LUA_T_ARRAY); +} + +int lua_isuserdata (lua_Object o) +{ + return (o!= LUA_NOOBJECT) && (ttype(Address(o)) == LUA_T_USERDATA); +} + +int lua_iscfunction (lua_Object o) +{ + return (lua_tag(o) == LUA_T_CPROTO); +} + +int lua_isnumber (lua_Object o) +{ + return (o!= LUA_NOOBJECT) && (tonumber(Address(o)) == 0); +} + +int lua_isstring (lua_Object o) +{ + int t = lua_tag(o); + return (t == LUA_T_STRING) || (t == LUA_T_NUMBER); +} + +int lua_isfunction (lua_Object o) +{ + int t = lua_tag(o); + return (t == LUA_T_PROTO) || (t == LUA_T_CPROTO); +} + + +double lua_getnumber (lua_Object object) +{ + if (object == LUA_NOOBJECT) return 0.0; + if (tonumber(Address(object))) return 0.0; + else return (nvalue(Address(object))); +} + +char *lua_getstring (lua_Object object) +{ + luaC_checkGC(); /* "tostring" may create a new string */ + if (object == LUA_NOOBJECT || tostring(Address(object))) + return NULL; + else return (svalue(Address(object))); +} + +long lua_strlen (lua_Object object) +{ + luaC_checkGC(); /* "tostring" may create a new string */ + if (object == LUA_NOOBJECT || tostring(Address(object))) + return 0L; + else return (tsvalue(Address(object))->u.s.len); +} + +void *lua_getuserdata (lua_Object object) +{ + if (object == LUA_NOOBJECT || ttype(Address(object)) != LUA_T_USERDATA) + return NULL; + else return tsvalue(Address(object))->u.d.v; +} + +lua_CFunction lua_getcfunction (lua_Object object) +{ + if (!lua_iscfunction(object)) + return NULL; + else return fvalue(luaA_protovalue(Address(object))); +} + + +void lua_pushnil (void) +{ + ttype(L->stack.top) = LUA_T_NIL; + incr_top; +} + +void lua_pushnumber (double n) +{ + ttype(L->stack.top) = LUA_T_NUMBER; + nvalue(L->stack.top) = n; + incr_top; +} + +void lua_pushlstring (char *s, long len) +{ + tsvalue(L->stack.top) = luaS_newlstr(s, len); + ttype(L->stack.top) = LUA_T_STRING; + incr_top; + luaC_checkGC(); +} + +void lua_pushstring (char *s) +{ + if (s == NULL) + lua_pushnil(); + else + lua_pushlstring(s, strlen(s)); +} + +void lua_pushcclosure (lua_CFunction fn, int n) +{ + if (fn == NULL) + lua_error("API error - attempt to push a NULL Cfunction"); + checkCparams(n); + ttype(L->stack.top) = LUA_T_CPROTO; + fvalue(L->stack.top) = fn; + incr_top; + luaV_closure(n); + luaC_checkGC(); +} + +void lua_pushusertag (void *u, int tag) +{ + if (tag < 0 && tag != LUA_ANYTAG) + luaT_realtag(tag); /* error if tag is not valid */ + tsvalue(L->stack.top) = luaS_createudata(u, tag); + ttype(L->stack.top) = LUA_T_USERDATA; + incr_top; + luaC_checkGC(); +} + +void luaA_pushobject (TObject *o) +{ + *L->stack.top = *o; + incr_top; +} + +void lua_pushobject (lua_Object o) +{ + if (o == LUA_NOOBJECT) + lua_error("API error - attempt to push a NOOBJECT"); + else { + set_normalized(L->stack.top, Address(o)); + incr_top; + } +} + + +int lua_tag (lua_Object lo) +{ + if (lo == LUA_NOOBJECT) + return LUA_T_NIL; + else { + TObject *o = Address(lo); + int t; + switch (t = ttype(o)) { + case LUA_T_USERDATA: + return o->value.ts->u.d.tag; + case LUA_T_ARRAY: + return o->value.a->htag; + case LUA_T_PMARK: + return LUA_T_PROTO; + case LUA_T_CMARK: + return LUA_T_CPROTO; + case LUA_T_CLOSURE: case LUA_T_CLMARK: + return o->value.cl->consts[0].ttype; +#ifdef DEBUG + case LUA_T_LINE: + LUA_INTERNALERROR("invalid type"); +#endif + default: + return t; + } + } +} + + +void lua_settag (int tag) +{ + checkCparams(1); + luaT_realtag(tag); + switch (ttype(L->stack.top-1)) { + case LUA_T_ARRAY: + (L->stack.top-1)->value.a->htag = tag; + break; + case LUA_T_USERDATA: + (L->stack.top-1)->value.ts->u.d.tag = tag; + break; + default: + luaL_verror("cannot change the tag of a %.20s", + luaO_typenames[-ttype((L->stack.top-1))]); + } + L->stack.top--; +} + + +/* +** ======================================================= +** Debug interface +** ======================================================= +*/ + + +/* Hooks */ +lua_CHFunction lua_callhook = NULL; +lua_LHFunction lua_linehook = NULL; + + +lua_Function lua_stackedfunction (int level) +{ + StkId i; + for (i = (L->stack.top-1)-L->stack.stack; i>=0; i--) { + int t = L->stack.stack[i].ttype; + if (t == LUA_T_CLMARK || t == LUA_T_PMARK || t == LUA_T_CMARK) + if (level-- == 0) + return Ref(L->stack.stack+i); + } + return LUA_NOOBJECT; +} + + +int lua_currentline (lua_Function func) +{ + TObject *f = Address(func); + return (f+1 < L->stack.top && (f+1)->ttype == LUA_T_LINE) ? + (f+1)->value.i : -1; +} + + +lua_Object lua_getlocal (lua_Function func, int local_number, char **name) +{ + /* check whether func is a Lua function */ + if (lua_tag(func) != LUA_T_PROTO) + return LUA_NOOBJECT; + else { + TObject *f = Address(func); + TProtoFunc *fp = luaA_protovalue(f)->value.tf; + *name = luaF_getlocalname(fp, local_number, lua_currentline(func)); + if (*name) { + /* if "*name", there must be a LUA_T_LINE */ + /* therefore, f+2 points to function base */ + return Ref((f+2)+(local_number-1)); + } + else + return LUA_NOOBJECT; + } +} + + +int lua_setlocal (lua_Function func, int local_number) +{ + /* check whether func is a Lua function */ + if (lua_tag(func) != LUA_T_PROTO) + return 0; + else { + TObject *f = Address(func); + TProtoFunc *fp = luaA_protovalue(f)->value.tf; + char *name = luaF_getlocalname(fp, local_number, lua_currentline(func)); + checkCparams(1); + --L->stack.top; + if (name) { + /* if "name", there must be a LUA_T_LINE */ + /* therefore, f+2 points to function base */ + *((f+2)+(local_number-1)) = *L->stack.top; + return 1; + } + else + return 0; + } +} + + +void lua_funcinfo (lua_Object func, char **filename, int *linedefined) +{ + if (!lua_isfunction(func)) + lua_error("API - `funcinfo' called with a non-function value"); + else { + TObject *f = luaA_protovalue(Address(func)); + if (normalized_type(f) == LUA_T_PROTO) { + *filename = tfvalue(f)->fileName->str; + *linedefined = tfvalue(f)->lineDefined; + } + else { + *filename = "(C)"; + *linedefined = -1; + } + } +} + + +static int checkfunc (TObject *o) +{ + return luaO_equalObj(o, L->stack.top); +} + + +char *lua_getobjname (lua_Object o, char **name) +{ /* try to find a name for given function */ + set_normalized(L->stack.top, Address(o)); /* to be accessed by "checkfunc */ + if ((*name = luaT_travtagmethods(checkfunc)) != NULL) + return "tag-method"; + else if ((*name = luaS_travsymbol(checkfunc)) != NULL) + return "global"; + else return ""; +} + +/* +** ======================================================= +** BLOCK mechanism +** ======================================================= +*/ + + +void lua_beginblock (void) +{ + if (L->numCblocks >= MAX_C_BLOCKS) + lua_error("too many nested blocks"); + L->Cblocks[L->numCblocks] = L->Cstack; + L->numCblocks++; +} + +void lua_endblock (void) +{ + --L->numCblocks; + L->Cstack = L->Cblocks[L->numCblocks]; + luaD_adjusttop(L->Cstack.base); +} + + + +int lua_ref (int lock) +{ + int ref; + checkCparams(1); + ref = luaC_ref(L->stack.top-1, lock); + L->stack.top--; + return ref; +} + + + +lua_Object lua_getref (int ref) +{ + TObject *o = luaC_getref(ref); + return (o ? put_luaObject(o) : LUA_NOOBJECT); +} + + +/* +** ======================================================= +** Derived functions +** ======================================================= +*/ +int (lua_call) (char *name) { return lua_call(name); } + +void (lua_pushref) (int ref) { lua_pushref(ref); } + +int (lua_refobject) (lua_Object o, int l) { return lua_refobject(o, l); } + +void (lua_register) (char *n, lua_CFunction f) { lua_register(n, f); } + +void (lua_pushuserdata) (void *u) { lua_pushuserdata(u); } + +void (lua_pushcfunction) (lua_CFunction f) { lua_pushcfunction(f); } + +int (lua_clonetag) (int t) { return lua_clonetag(t); } + + + + +#ifdef LUA_COMPAT2_5 +/* +** API: set a function as a fallback +*/ + +static void do_unprotectedrun (lua_CFunction f, int nParams, int nResults) +{ + StkId base = (L->stack.top-L->stack.stack)-nParams; + luaD_openstack(nParams); + L->stack.stack[base].ttype = LUA_T_CPROTO; + L->stack.stack[base].value.f = f; + luaD_call(base+1, nResults); +} + +lua_Object lua_setfallback (char *name, lua_CFunction fallback) +{ + lua_pushstring(name); + lua_pushcfunction(fallback); + do_unprotectedrun(luaT_setfallback, 2, 1); + return put_luaObjectonTop(); +} +#endif + diff --git a/src/lapi.h b/src/lapi.h new file mode 100644 index 0000000..ca9a117 --- /dev/null +++ b/src/lapi.h @@ -0,0 +1,20 @@ +/* +** $Id: lapi.h,v 1.2 1998/06/19 16:14:09 roberto Exp $ +** Auxiliary functions from Lua API +** See Copyright Notice in lua.h +*/ + +#ifndef lapi_h +#define lapi_h + + +#include "lua.h" +#include "lobject.h" + + +TObject *luaA_Address (lua_Object o); +void luaA_pushobject (TObject *o); +void luaA_packresults (void); +int luaA_passresults (void); + +#endif diff --git a/src/lauxlib.c b/src/lauxlib.c new file mode 100644 index 0000000..0a972af --- /dev/null +++ b/src/lauxlib.c @@ -0,0 +1,111 @@ +/* +** $Id: lauxlib.c,v 1.12 1998/06/19 16:14:09 roberto Exp $ +** Auxiliary functions for building Lua libraries +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include + +/* Please Notice: This file uses only the official API of Lua +** Any function declared here could be written as an application +** function. With care, these functions can be used by other libraries. +*/ +#include "lauxlib.h" +#include "lua.h" +#include "luadebug.h" + + + +int luaL_findstring (char *name, char *list[]) { + int i; + for (i=0; list[i]; i++) + if (strcmp(list[i], name) == 0) + return i; + return -1; /* name not found */ +} + +void luaL_argerror (int numarg, char *extramsg) +{ + char *funcname; + lua_getobjname(lua_stackedfunction(0), &funcname); + if (funcname == NULL) + funcname = "???"; + if (extramsg == NULL) + luaL_verror("bad argument #%d to function `%.50s'", numarg, funcname); + else + luaL_verror("bad argument #%d to function `%.50s' (%.100s)", + numarg, funcname, extramsg); +} + +char *luaL_check_lstr (int numArg, long *len) +{ + lua_Object o = lua_getparam(numArg); + luaL_arg_check(lua_isstring(o), numArg, "string expected"); + if (len) *len = lua_strlen(o); + return lua_getstring(o); +} + +char *luaL_opt_lstr (int numArg, char *def, long *len) +{ + return (lua_getparam(numArg) == LUA_NOOBJECT) ? def : + luaL_check_lstr(numArg, len); +} + +double luaL_check_number (int numArg) +{ + lua_Object o = lua_getparam(numArg); + luaL_arg_check(lua_isnumber(o), numArg, "number expected"); + return lua_getnumber(o); +} + + +double luaL_opt_number (int numArg, double def) +{ + return (lua_getparam(numArg) == LUA_NOOBJECT) ? def : + luaL_check_number(numArg); +} + + +lua_Object luaL_tablearg (int arg) +{ + lua_Object o = lua_getparam(arg); + luaL_arg_check(lua_istable(o), arg, "table expected"); + return o; +} + +lua_Object luaL_functionarg (int arg) +{ + lua_Object o = lua_getparam(arg); + luaL_arg_check(lua_isfunction(o), arg, "function expected"); + return o; +} + +lua_Object luaL_nonnullarg (int numArg) +{ + lua_Object o = lua_getparam(numArg); + luaL_arg_check(o != LUA_NOOBJECT, numArg, "value expected"); + return o; +} + +void luaL_openlib (struct luaL_reg *l, int n) +{ + int i; + lua_open(); /* make sure lua is already open */ + for (i=0; i + +#include "lauxlib.h" +#include "lmem.h" +#include "lstate.h" + + +/*------------------------------------------------------- +** Auxiliary buffer +-------------------------------------------------------*/ + +#define BUFF_STEP 32 + +#define openspace(size) if (L->Mbuffnext+(size) > L->Mbuffsize) Openspace(size) + +static void Openspace (int size) +{ + lua_State *l = L; /* to optimize */ + int base = l->Mbuffbase-l->Mbuffer; + l->Mbuffsize *= 2; + if (l->Mbuffnext+size > l->Mbuffsize) /* still not big enough? */ + l->Mbuffsize = l->Mbuffnext+size; + l->Mbuffer = luaM_realloc(l->Mbuffer, l->Mbuffsize); + l->Mbuffbase = l->Mbuffer+base; +} + + +char *luaL_openspace (int size) +{ + openspace(size); + return L->Mbuffer+L->Mbuffnext; +} + + +void luaL_addchar (int c) +{ + openspace(BUFF_STEP); + L->Mbuffer[L->Mbuffnext++] = c; +} + + +void luaL_resetbuffer (void) +{ + L->Mbuffnext = L->Mbuffbase-L->Mbuffer; +} + + +void luaL_addsize (int n) +{ + L->Mbuffnext += n; +} + +int luaL_getsize (void) +{ + return L->Mbuffnext-(L->Mbuffbase-L->Mbuffer); +} + +int luaL_newbuffer (int size) +{ + int old = L->Mbuffbase-L->Mbuffer; + openspace(size); + L->Mbuffbase = L->Mbuffer+L->Mbuffnext; + return old; +} + + +void luaL_oldbuffer (int old) +{ + L->Mbuffnext = L->Mbuffbase-L->Mbuffer; + L->Mbuffbase = L->Mbuffer+old; +} + + +char *luaL_buffer (void) +{ + return L->Mbuffbase; +} + diff --git a/src/lbuiltin.c b/src/lbuiltin.c new file mode 100644 index 0000000..0fd39f7 --- /dev/null +++ b/src/lbuiltin.c @@ -0,0 +1,526 @@ +/* +** $Id: lbuiltin.c,v 1.32 1998/06/29 18:24:06 roberto Exp $ +** Built-in functions +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include +#include + +#include "lapi.h" +#include "lauxlib.h" +#include "lbuiltin.h" +#include "ldo.h" +#include "lfunc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lua.h" +#include "lundump.h" + + + +static void pushstring (TaggedString *s) +{ + TObject o; + o.ttype = LUA_T_STRING; + o.value.ts = s; + luaA_pushobject(&o); +} + + +static void nextvar (void) +{ + TObject *o = luaA_Address(luaL_nonnullarg(1)); + TaggedString *g; + if (ttype(o) == LUA_T_NIL) + g = (TaggedString *)L->rootglobal.next; + else { + luaL_arg_check(ttype(o) == LUA_T_STRING, 1, "variable name expected"); + g = tsvalue(o); + /* check whether name is in global var list */ + luaL_arg_check((GCnode *)g != g->head.next, 1, "variable name expected"); + g = (TaggedString *)g->head.next; + } + while (g && g->u.s.globalval.ttype == LUA_T_NIL) /* skip globals with nil */ + g = (TaggedString *)g->head.next; + if (g) { + pushstring(g); + luaA_pushobject(&g->u.s.globalval); + } + else lua_pushnil(); +} + + +static void foreachvar (void) +{ + TObject f = *luaA_Address(luaL_functionarg(1)); + GCnode *g; + StkId name = L->Cstack.base++; /* place to keep var name (to avoid GC) */ + ttype(L->stack.stack+name) = LUA_T_NIL; + L->stack.top++; + for (g = L->rootglobal.next; g; g = g->next) { + TaggedString *s = (TaggedString *)g; + if (s->u.s.globalval.ttype != LUA_T_NIL) { + ttype(L->stack.stack+name) = LUA_T_STRING; + tsvalue(L->stack.stack+name) = s; /* keep s on stack to avoid GC */ + luaA_pushobject(&f); + pushstring(s); + luaA_pushobject(&s->u.s.globalval); + luaD_call((L->stack.top-L->stack.stack)-2, 1); + if (ttype(L->stack.top-1) != LUA_T_NIL) + return; + L->stack.top--; + } + } +} + + +static void next (void) +{ + lua_Object o = luaL_tablearg(1); + lua_Object r = luaL_nonnullarg(2); + Node *n = luaH_next(luaA_Address(o), luaA_Address(r)); + if (n) { + luaA_pushobject(&n->ref); + luaA_pushobject(&n->val); + } + else lua_pushnil(); +} + + +static void foreach (void) +{ + TObject t = *luaA_Address(luaL_tablearg(1)); + TObject f = *luaA_Address(luaL_functionarg(2)); + int i; + for (i=0; inhash; i++) { + Node *nd = &(avalue(&t)->node[i]); + if (ttype(ref(nd)) != LUA_T_NIL && ttype(val(nd)) != LUA_T_NIL) { + luaA_pushobject(&f); + luaA_pushobject(ref(nd)); + luaA_pushobject(val(nd)); + luaD_call((L->stack.top-L->stack.stack)-2, 1); + if (ttype(L->stack.top-1) != LUA_T_NIL) + return; + L->stack.top--; + } + } +} + + +static void internaldostring (void) +{ + long l; + char *s = luaL_check_lstr(1, &l); + if (*s == ID_CHUNK) + lua_error("`dostring' cannot run pre-compiled code"); + if (lua_dobuffer(s, l, luaL_opt_string(2, NULL)) == 0) + if (luaA_passresults() == 0) + lua_pushuserdata(NULL); /* at least one result to signal no errors */ +} + + +static void internaldofile (void) +{ + char *fname = luaL_opt_string(1, NULL); + if (lua_dofile(fname) == 0) + if (luaA_passresults() == 0) + lua_pushuserdata(NULL); /* at least one result to signal no errors */ +} + + +static void to_string (void) { + lua_Object obj = lua_getparam(1); + char *buff = luaL_openspace(30); + TObject *o = luaA_Address(obj); + switch (ttype(o)) { + case LUA_T_NUMBER: + lua_pushstring(lua_getstring(obj)); + return; + case LUA_T_STRING: + lua_pushobject(obj); + return; + case LUA_T_ARRAY: { + sprintf(buff, "table: %p", (void *)o->value.a); + break; + } + case LUA_T_CLOSURE: { + sprintf(buff, "function: %p", (void *)o->value.cl); + break; + } + case LUA_T_PROTO: { + sprintf(buff, "function: %p", (void *)o->value.tf); + break; + } + case LUA_T_CPROTO: { + sprintf(buff, "function: %p", (void *)o->value.f); + break; + } + case LUA_T_USERDATA: { + sprintf(buff, "userdata: %p", o->value.ts->u.d.v); + break; + } + case LUA_T_NIL: + lua_pushstring("nil"); + return; + default: + LUA_INTERNALERROR("invalid type"); + } + lua_pushstring(buff); +} + + +static void luaI_print (void) { + TaggedString *ts = luaS_new("tostring"); + lua_Object obj; + int i = 1; + while ((obj = lua_getparam(i++)) != LUA_NOOBJECT) { + luaA_pushobject(&ts->u.s.globalval); + lua_pushobject(obj); + luaD_call((L->stack.top-L->stack.stack)-1, 1); + if (ttype(L->stack.top-1) != LUA_T_STRING) + lua_error("`tostring' must return a string to `print'"); + printf("%s\t", svalue(L->stack.top-1)); + L->stack.top--; + } + printf("\n"); +} + + +static void luaI_type (void) +{ + lua_Object o = luaL_nonnullarg(1); + lua_pushstring(luaO_typenames[-ttype(luaA_Address(o))]); + lua_pushnumber(lua_tag(o)); +} + + +static void tonumber (void) +{ + int base = luaL_opt_number(2, 10); + if (base == 10) { /* standard conversion */ + lua_Object o = lua_getparam(1); + if (lua_isnumber(o)) + lua_pushnumber(lua_getnumber(o)); + } + else { + char *s = luaL_check_string(1); + unsigned long n; + luaL_arg_check(0 <= base && base <= 36, 2, "base out of range"); + n = strtol(s, &s, base); + while (isspace(*s)) s++; /* skip trailing spaces */ + if (*s) lua_pushnil(); /* invalid format: return nil */ + else lua_pushnumber(n); + } +} + + +static void luaI_error (void) +{ + lua_error(lua_getstring(lua_getparam(1))); +} + + +static void luaI_assert (void) +{ + lua_Object p = lua_getparam(1); + if (p == LUA_NOOBJECT || lua_isnil(p)) + luaL_verror("assertion failed! %.100s", luaL_opt_string(2, "")); +} + + +static void setglobal (void) +{ + char *n = luaL_check_string(1); + lua_Object value = luaL_nonnullarg(2); + lua_pushobject(value); + lua_setglobal(n); + lua_pushobject(value); /* return given value */ +} + +static void rawsetglobal (void) +{ + char *n = luaL_check_string(1); + lua_Object value = luaL_nonnullarg(2); + lua_pushobject(value); + lua_rawsetglobal(n); + lua_pushobject(value); /* return given value */ +} + +static void getglobal (void) +{ + lua_pushobject(lua_getglobal(luaL_check_string(1))); +} + +static void rawgetglobal (void) +{ + lua_pushobject(lua_rawgetglobal(luaL_check_string(1))); +} + +static void luatag (void) +{ + lua_pushnumber(lua_tag(lua_getparam(1))); +} + + +static int getnarg (lua_Object table) +{ + lua_Object temp; + /* temp = table.n */ + lua_pushobject(table); lua_pushstring("n"); temp = lua_rawgettable(); + return (lua_isnumber(temp) ? lua_getnumber(temp) : MAX_INT); +} + +static void luaI_call (void) +{ + lua_Object f = luaL_nonnullarg(1); + lua_Object arg = luaL_tablearg(2); + char *options = luaL_opt_string(3, ""); + lua_Object err = lua_getparam(4); + int narg = getnarg(arg); + int i, status; + if (err != LUA_NOOBJECT) { /* set new error method */ + lua_pushobject(err); + err = lua_seterrormethod(); + } + /* push arg[1...n] */ + for (i=0; iroottable.next : (s[0]=='c') ? L->rootcl.next : + (s[0]=='p') ? L->rootproto.next : L->rootglobal.next; + int i=0; + while (l) { + i++; + l = l->next; + } + lua_pushnumber(i); +} + + +static void testC (void) +{ +#define getnum(s) ((*s++) - '0') +#define getname(s) (nome[0] = *s++, nome) + + static int locks[10]; + lua_Object reg[10]; + char nome[2]; + char *s = luaL_check_string(1); + nome[1] = 0; + while (1) { + switch (*s++) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + lua_pushnumber(*(s-1) - '0'); + break; + + case 'c': reg[getnum(s)] = lua_createtable(); break; + case 'C': { lua_CFunction f = lua_getcfunction(lua_getglobal(getname(s))); + lua_pushcclosure(f, getnum(s)); + break; + } + case 'P': reg[getnum(s)] = lua_pop(); break; + case 'g': { int n=getnum(s); reg[n]=lua_getglobal(getname(s)); break; } + case 'G': { int n = getnum(s); + reg[n] = lua_rawgetglobal(getname(s)); + break; + } + case 'l': locks[getnum(s)] = lua_ref(1); break; + case 'L': locks[getnum(s)] = lua_ref(0); break; + case 'r': { int n=getnum(s); reg[n]=lua_getref(locks[getnum(s)]); break; } + case 'u': lua_unref(locks[getnum(s)]); break; + case 'p': { int n = getnum(s); reg[n] = lua_getparam(getnum(s)); break; } + case '=': lua_setglobal(getname(s)); break; + case 's': lua_pushstring(getname(s)); break; + case 'o': lua_pushobject(reg[getnum(s)]); break; + case 'f': (lua_call)(getname(s)); break; + case 'i': reg[getnum(s)] = lua_gettable(); break; + case 'I': reg[getnum(s)] = lua_rawgettable(); break; + case 't': lua_settable(); break; + case 'T': lua_rawsettable(); break; + default: luaL_verror("unknown command in `testC': %c", *(s-1)); + } + if (*s == 0) return; + if (*s++ != ' ') lua_error("missing ` ' between commands in `testC'"); + } +} + +#endif + + +/* +** Internal functions +*/ +static struct luaL_reg int_funcs[] = { +#ifdef LUA_COMPAT2_5 + {"setfallback", luaT_setfallback}, +#endif +#ifdef DEBUG + {"testC", testC}, + {"totalmem", mem_query}, + {"count", countlist}, +#endif + {"assert", luaI_assert}, + {"call", luaI_call}, + {"collectgarbage", luaI_collectgarbage}, + {"dofile", internaldofile}, + {"copytagmethods", copytagmethods}, + {"dostring", internaldostring}, + {"error", luaI_error}, + {"foreach", foreach}, + {"foreachvar", foreachvar}, + {"getglobal", getglobal}, + {"newtag", newtag}, + {"next", next}, + {"nextvar", nextvar}, + {"print", luaI_print}, + {"rawgetglobal", rawgetglobal}, + {"rawgettable", rawgettable}, + {"rawsetglobal", rawsetglobal}, + {"rawsettable", rawsettable}, + {"seterrormethod", seterrormethod}, + {"setglobal", setglobal}, + {"settagmethod", settagmethod}, + {"gettagmethod", gettagmethod}, + {"settag", settag}, + {"tonumber", tonumber}, + {"tostring", to_string}, + {"tag", luatag}, + {"type", luaI_type} +}; + + +#define INTFUNCSIZE (sizeof(int_funcs)/sizeof(int_funcs[0])) + + +void luaB_predefine (void) +{ + /* pre-register mem error messages, to avoid loop when error arises */ + luaS_newfixedstring(tableEM); + luaS_newfixedstring(memEM); + luaL_openlib(int_funcs, (sizeof(int_funcs)/sizeof(int_funcs[0]))); + lua_pushstring(LUA_VERSION); + lua_setglobal("_VERSION"); +} + diff --git a/src/lbuiltin.h b/src/lbuiltin.h new file mode 100644 index 0000000..bcb11fc --- /dev/null +++ b/src/lbuiltin.h @@ -0,0 +1,14 @@ +/* +** $Id: lbuiltin.h,v 1.1 1997/09/16 19:25:59 roberto Exp $ +** Built-in functions +** See Copyright Notice in lua.h +*/ + +#ifndef lbuiltin_h +#define lbuiltin_h + + +void luaB_predefine (void); + + +#endif diff --git a/src/ldo.c b/src/ldo.c new file mode 100644 index 0000000..f7a9f27 --- /dev/null +++ b/src/ldo.c @@ -0,0 +1,427 @@ +/* +** $Id: ldo.c,v 1.27 1998/06/19 18:47:06 roberto Exp $ +** Stack and Call structure of Lua +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include +#include + +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lparser.h" +#include "lstate.h" +#include "ltm.h" +#include "lua.h" +#include "luadebug.h" +#include "lundump.h" +#include "lvm.h" +#include "lzio.h" + + + +#ifndef STACK_LIMIT +#define STACK_LIMIT 6000 +#endif + + + +/* +** Error messages +*/ + +static void stderrorim (void) +{ + fprintf(stderr, "lua error: %s\n", lua_getstring(lua_getparam(1))); +} + + + +#define STACK_UNIT 128 + + +void luaD_init (void) +{ + L->stack.stack = luaM_newvector(STACK_UNIT, TObject); + L->stack.top = L->stack.stack; + L->stack.last = L->stack.stack+(STACK_UNIT-1); + ttype(&L->errorim) = LUA_T_CPROTO; + fvalue(&L->errorim) = stderrorim; +} + + +void luaD_checkstack (int n) +{ + struct Stack *S = &L->stack; + if (S->last-S->top <= n) { + StkId top = S->top-S->stack; + int stacksize = (S->last-S->stack)+1+STACK_UNIT+n; + S->stack = luaM_reallocvector(S->stack, stacksize, TObject); + S->last = S->stack+(stacksize-1); + S->top = S->stack + top; + if (stacksize >= STACK_LIMIT) { /* stack overflow? */ + if (lua_stackedfunction(100) == LUA_NOOBJECT) /* 100 funcs on stack? */ + lua_error("Lua2C - C2Lua overflow"); /* doesn't look like a rec. loop */ + else + lua_error("stack size overflow"); + } + } +} + + +/* +** Adjust stack. Set top to the given value, pushing NILs if needed. +*/ +void luaD_adjusttop (StkId newtop) +{ + int diff = newtop-(L->stack.top-L->stack.stack); + if (diff <= 0) + L->stack.top += diff; + else { + luaD_checkstack(diff); + while (diff--) + ttype(L->stack.top++) = LUA_T_NIL; + } +} + + +/* +** Open a hole below "nelems" from the L->stack.top. +*/ +void luaD_openstack (int nelems) +{ + luaO_memup(L->stack.top-nelems+1, L->stack.top-nelems, + nelems*sizeof(TObject)); + incr_top; +} + + +void luaD_lineHook (int line) +{ + struct C_Lua_Stack oldCLS = L->Cstack; + StkId old_top = L->Cstack.lua2C = L->Cstack.base = L->stack.top-L->stack.stack; + L->Cstack.num = 0; + (*lua_linehook)(line); + L->stack.top = L->stack.stack+old_top; + L->Cstack = oldCLS; +} + + +void luaD_callHook (StkId base, TProtoFunc *tf, int isreturn) +{ + struct C_Lua_Stack oldCLS = L->Cstack; + StkId old_top = L->Cstack.lua2C = L->Cstack.base = L->stack.top-L->stack.stack; + L->Cstack.num = 0; + if (isreturn) + (*lua_callhook)(LUA_NOOBJECT, "(return)", 0); + else { + TObject *f = L->stack.stack+base-1; + if (tf) + (*lua_callhook)(Ref(f), tf->fileName->str, tf->lineDefined); + else + (*lua_callhook)(Ref(f), "(C)", -1); + } + L->stack.top = L->stack.stack+old_top; + L->Cstack = oldCLS; +} + + +/* +** Call a C function. +** Cstack.num is the number of arguments; Cstack.lua2C points to the +** first argument. Returns an index to the first result from C. +*/ +static StkId callC (lua_CFunction f, StkId base) +{ + struct C_Lua_Stack *CS = &L->Cstack; + struct C_Lua_Stack oldCLS = *CS; + StkId firstResult; + int numarg = (L->stack.top-L->stack.stack) - base; + CS->num = numarg; + CS->lua2C = base; + CS->base = base+numarg; /* == top-stack */ + if (lua_callhook) + luaD_callHook(base, NULL, 0); + (*f)(); /* do the actual call */ + if (lua_callhook) /* func may have changed lua_callhook */ + luaD_callHook(base, NULL, 1); + firstResult = CS->base; + *CS = oldCLS; + return firstResult; +} + + +static StkId callCclosure (struct Closure *cl, lua_CFunction f, StkId base) +{ + TObject *pbase; + int nup = cl->nelems; /* number of upvalues */ + luaD_checkstack(nup); + pbase = L->stack.stack+base; /* care: previous call may change this */ + /* open space for upvalues as extra arguments */ + luaO_memup(pbase+nup, pbase, (L->stack.top-pbase)*sizeof(TObject)); + /* copy upvalues into stack */ + memcpy(pbase, cl->consts+1, nup*sizeof(TObject)); + L->stack.top += nup; + return callC(f, base); +} + + +void luaD_callTM (TObject *f, int nParams, int nResults) +{ + luaD_openstack(nParams); + *(L->stack.top-nParams-1) = *f; + luaD_call((L->stack.top-L->stack.stack)-nParams, nResults); +} + + +/* +** Call a function (C or Lua). The parameters must be on the L->stack.stack, +** between [L->stack.stack+base,L->stack.top). The function to be called is at L->stack.stack+base-1. +** When returns, the results are on the L->stack.stack, between [L->stack.stack+base-1,L->stack.top). +** The number of results is nResults, unless nResults=MULT_RET. +*/ +void luaD_call (StkId base, int nResults) +{ + StkId firstResult; + TObject *func = L->stack.stack+base-1; + int i; + switch (ttype(func)) { + case LUA_T_CPROTO: + ttype(func) = LUA_T_CMARK; + firstResult = callC(fvalue(func), base); + break; + case LUA_T_PROTO: + ttype(func) = LUA_T_PMARK; + firstResult = luaV_execute(NULL, tfvalue(func), base); + break; + case LUA_T_CLOSURE: { + Closure *c = clvalue(func); + TObject *proto = &(c->consts[0]); + ttype(func) = LUA_T_CLMARK; + firstResult = (ttype(proto) == LUA_T_CPROTO) ? + callCclosure(c, fvalue(proto), base) : + luaV_execute(c, tfvalue(proto), base); + break; + } + default: { /* func is not a function */ + /* Check the tag method for invalid functions */ + TObject *im = luaT_getimbyObj(func, IM_FUNCTION); + if (ttype(im) == LUA_T_NIL) + lua_error("call expression not a function"); + luaD_callTM(im, (L->stack.top-L->stack.stack)-(base-1), nResults); + return; + } + } + /* adjust the number of results */ + if (nResults != MULT_RET) + luaD_adjusttop(firstResult+nResults); + /* move results to base-1 (to erase parameters and function) */ + base--; + nResults = L->stack.top - (L->stack.stack+firstResult); /* actual number of results */ + for (i=0; istack.stack+base+i) = *(L->stack.stack+firstResult+i); + L->stack.top -= firstResult-base; +} + + + +/* +** Traverse all objects on L->stack.stack +*/ +void luaD_travstack (int (*fn)(TObject *)) +{ + StkId i; + for (i = (L->stack.top-1)-L->stack.stack; i>=0; i--) + fn(L->stack.stack+i); +} + + + +static void message (char *s) +{ + TObject im = L->errorim; + if (ttype(&im) != LUA_T_NIL) { + lua_pushstring(s); + luaD_callTM(&im, 1, 0); + } +} + +/* +** Reports an error, and jumps up to the available recover label +*/ +void lua_error (char *s) +{ + if (s) message(s); + if (L->errorJmp) + longjmp(*((jmp_buf *)L->errorJmp), 1); + else { + fprintf (stderr, "lua: exit(1). Unable to recover\n"); + exit(1); + } +} + +/* +** Call the function at L->Cstack.base, and incorporate results on +** the Lua2C structure. +*/ +static void do_callinc (int nResults) +{ + StkId base = L->Cstack.base; + luaD_call(base+1, nResults); + L->Cstack.lua2C = base; /* position of the luaM_new results */ + L->Cstack.num = (L->stack.top-L->stack.stack) - base; /* number of results */ + L->Cstack.base = base + L->Cstack.num; /* incorporate results on L->stack.stack */ +} + + +/* +** Execute a protected call. Assumes that function is at L->Cstack.base and +** parameters are on top of it. Leave nResults on the stack. +*/ +int luaD_protectedrun (int nResults) +{ + jmp_buf myErrorJmp; + int status; + volatile struct C_Lua_Stack oldCLS = L->Cstack; + jmp_buf *volatile oldErr = L->errorJmp; + L->errorJmp = &myErrorJmp; + if (setjmp(myErrorJmp) == 0) { + do_callinc(nResults); + status = 0; + } + else { /* an error occurred: restore L->Cstack and L->stack.top */ + L->Cstack = oldCLS; + L->stack.top = L->stack.stack+L->Cstack.base; + status = 1; + } + L->errorJmp = oldErr; + return status; +} + + +/* +** returns 0 = chunk loaded; 1 = error; 2 = no more chunks to load +*/ +static int protectedparser (ZIO *z, int bin) +{ + volatile int status; + TProtoFunc *volatile tf; + jmp_buf myErrorJmp; + jmp_buf *volatile oldErr = L->errorJmp; + L->errorJmp = &myErrorJmp; + if (setjmp(myErrorJmp) == 0) { + tf = bin ? luaU_undump1(z) : luaY_parser(z); + status = 0; + } + else { + tf = NULL; + status = 1; + } + L->errorJmp = oldErr; + if (status) return 1; /* error code */ + if (tf == NULL) return 2; /* 'natural' end */ + luaD_adjusttop(L->Cstack.base+1); /* one slot for the pseudo-function */ + L->stack.stack[L->Cstack.base].ttype = LUA_T_PROTO; + L->stack.stack[L->Cstack.base].value.tf = tf; + luaV_closure(0); + return 0; +} + + +static int do_main (ZIO *z, int bin) +{ + int status; + do { + long old_blocks = (luaC_checkGC(), L->nblocks); + status = protectedparser(z, bin); + if (status == 1) return 1; /* error */ + else if (status == 2) return 0; /* 'natural' end */ + else { + unsigned long newelems2 = 2*(L->nblocks-old_blocks); + L->GCthreshold += newelems2; + status = luaD_protectedrun(MULT_RET); + L->GCthreshold -= newelems2; + } + } while (bin && status == 0); + return status; +} + + +void luaD_gcIM (TObject *o) +{ + TObject *im = luaT_getimbyObj(o, IM_GC); + if (ttype(im) != LUA_T_NIL) { + *L->stack.top = *o; + incr_top; + luaD_callTM(im, 1, 0); + } +} + + +int lua_dofile (char *filename) +{ + ZIO z; + int status; + int c; + int bin; + FILE *f = (filename == NULL) ? stdin : fopen(filename, "r"); + if (f == NULL) + return 2; + if (filename == NULL) + filename = "(stdin)"; + c = fgetc(f); + ungetc(c, f); + bin = (c == ID_CHUNK); + if (bin) + f = freopen(filename, "rb", f); /* set binary mode */ + luaZ_Fopen(&z, f, filename); + status = do_main(&z, bin); + if (f != stdin) + fclose(f); + return status; +} + + +#define SIZE_PREF 20 /* size of string prefix to appear in error messages */ +#define SSIZE_PREF "20" + + +static void build_name (char *str, char *name) { + if (str == NULL || *str == ID_CHUNK) + strcpy(name, "(buffer)"); + else { + char *temp; + sprintf(name, "(dostring) >> \"%." SSIZE_PREF "s\"", str); + temp = strchr(name, '\n'); + if (temp) { /* end string after first line */ + *temp = '"'; + *(temp+1) = 0; + } + } +} + + +int lua_dostring (char *str) { + return lua_dobuffer(str, strlen(str), NULL); +} + + +int lua_dobuffer (char *buff, int size, char *name) { + char newname[SIZE_PREF+25]; + ZIO z; + int status; + if (name==NULL) { + build_name(buff, newname); + name = newname; + } + luaZ_mopen(&z, buff, size, name); + status = do_main(&z, buff[0]==ID_CHUNK); + return status; +} + diff --git a/src/ldo.h b/src/ldo.h new file mode 100644 index 0000000..0e981fb --- /dev/null +++ b/src/ldo.h @@ -0,0 +1,46 @@ +/* +** $Id: ldo.h,v 1.4 1997/12/15 16:17:20 roberto Exp $ +** Stack and Call structure of Lua +** See Copyright Notice in lua.h +*/ + +#ifndef ldo_h +#define ldo_h + + +#include "lobject.h" +#include "lstate.h" + + +#define MULT_RET 255 + + + +/* +** macro to increment stack top. +** There must be always an empty slot at the L->stack.top +*/ +#define incr_top { if (L->stack.top >= L->stack.last) luaD_checkstack(1); \ + L->stack.top++; } + + +/* macros to convert from lua_Object to (TObject *) and back */ + +#define Address(lo) ((lo)+L->stack.stack-1) +#define Ref(st) ((st)-L->stack.stack+1) + + +void luaD_init (void); +void luaD_adjusttop (StkId newtop); +void luaD_openstack (int nelems); +void luaD_lineHook (int line); +void luaD_callHook (StkId base, TProtoFunc *tf, int isreturn); +void luaD_call (StkId base, int nResults); +void luaD_callTM (TObject *f, int nParams, int nResults); +int luaD_protectedrun (int nResults); +void luaD_gcIM (TObject *o); +void luaD_travstack (int (*fn)(TObject *)); +void luaD_checkstack (int n); + + +#endif diff --git a/src/lex.c b/src/lex.c deleted file mode 100644 index 5f19dd0..0000000 --- a/src/lex.c +++ /dev/null @@ -1,470 +0,0 @@ -char *rcs_lex = "$Id: lex.c,v 3.5 1997/06/16 16:50:22 roberto Exp $"; - - -#include -#include - -#include "auxlib.h" -#include "luamem.h" -#include "tree.h" -#include "table.h" -#include "lex.h" -#include "inout.h" -#include "luadebug.h" -#include "parser.h" - -#define MINBUFF 250 - -static int current; /* look ahead character */ -static ZIO *lex_z; - - -#define next() (current = zgetc(lex_z)) -#define save(x) (yytext[tokensize++] = (x)) -#define save_and_next() (save(current), next()) - - -#define MAX_IFS 5 - -/* "ifstate" keeps the state of each nested $if the lexical is dealing with. */ - -static struct { - int elsepart; /* true if its in the $else part */ - int condition; /* true if $if condition is true */ - int skip; /* true if part must be skiped */ -} ifstate[MAX_IFS]; - -static int iflevel; /* level of nested $if's */ - - -void lua_setinput (ZIO *z) -{ - current = '\n'; - lua_linenumber = 0; - iflevel = 0; - ifstate[0].skip = 0; - ifstate[0].elsepart = 1; /* to avoid a free $else */ - lex_z = z; -} - - -static void luaI_auxsyntaxerror (char *s) -{ - luaL_verror("%s;\n> at line %d in file %s", - s, lua_linenumber, lua_parsedfile); -} - -static void luaI_auxsynterrbf (char *s, char *token) -{ - if (token[0] == 0) - token = ""; - luaL_verror("%s;\n> last token read: \"%s\" at line %d in file %s", - s, token, lua_linenumber, lua_parsedfile); -} - -void luaI_syntaxerror (char *s) -{ - luaI_auxsynterrbf(s, luaI_buffer(1)); -} - - -static struct - { - char *name; - int token; - } reserved [] = { - {"and", AND}, - {"do", DO}, - {"else", ELSE}, - {"elseif", ELSEIF}, - {"end", END}, - {"function", FUNCTION}, - {"if", IF}, - {"local", LOCAL}, - {"nil", NIL}, - {"not", NOT}, - {"or", OR}, - {"repeat", REPEAT}, - {"return", RETURN}, - {"then", THEN}, - {"until", UNTIL}, - {"while", WHILE} }; - - -#define RESERVEDSIZE (sizeof(reserved)/sizeof(reserved[0])) - - -void luaI_addReserved (void) -{ - int i; - for (i=0; imarked = reserved[i].token; /* reserved word (always > 255) */ - } -} - - -/* -** Pragma handling -*/ - -#define PRAGMASIZE 20 - -static void skipspace (void) -{ - while (current == ' ' || current == '\t') next(); -} - - -static int checkcond (char *buff) -{ - static char *opts[] = {"nil", "1"}; - int i = luaI_findstring(buff, opts); - if (i >= 0) return i; - else if (isalpha((unsigned char)buff[0]) || buff[0] == '_') - return luaI_globaldefined(buff); - else { - luaI_auxsynterrbf("invalid $if condition", buff); - return 0; /* to avoid warnings */ - } -} - - -static void readname (char *buff) -{ - int i = 0; - skipspace(); - while (isalnum((unsigned char)current) || current == '_') { - if (i >= PRAGMASIZE) { - buff[PRAGMASIZE] = 0; - luaI_auxsynterrbf("pragma too long", buff); - } - buff[i++] = current; - next(); - } - buff[i] = 0; -} - - -static void inclinenumber (void); - - -static void ifskip (void) -{ - while (ifstate[iflevel].skip) { - if (current == '\n') - inclinenumber(); - else if (current == EOZ) - luaI_auxsyntaxerror("input ends inside a $if"); - else next(); - } -} - - -static void inclinenumber (void) -{ - static char *pragmas [] = - {"debug", "nodebug", "endinput", "end", "ifnot", "if", "else", NULL}; - next(); /* skip '\n' */ - ++lua_linenumber; - if (current == '$') { /* is a pragma? */ - char buff[PRAGMASIZE+1]; - int ifnot = 0; - int skip = ifstate[iflevel].skip; - next(); /* skip $ */ - readname(buff); - switch (luaI_findstring(buff, pragmas)) { - case 0: /* debug */ - if (!skip) lua_debug = 1; - break; - case 1: /* nodebug */ - if (!skip) lua_debug = 0; - break; - case 2: /* endinput */ - if (!skip) { - current = EOZ; - iflevel = 0; /* to allow $endinput inside a $if */ - } - break; - case 3: /* end */ - if (iflevel-- == 0) - luaI_auxsyntaxerror("unmatched $endif"); - break; - case 4: /* ifnot */ - ifnot = 1; - /* go through */ - case 5: /* if */ - if (iflevel == MAX_IFS-1) - luaI_auxsyntaxerror("too many nested `$ifs'"); - readname(buff); - iflevel++; - ifstate[iflevel].elsepart = 0; - ifstate[iflevel].condition = checkcond(buff) ? !ifnot : ifnot; - ifstate[iflevel].skip = skip || !ifstate[iflevel].condition; - break; - case 6: /* else */ - if (ifstate[iflevel].elsepart) - luaI_auxsyntaxerror("unmatched $else"); - ifstate[iflevel].elsepart = 1; - ifstate[iflevel].skip = - ifstate[iflevel-1].skip || ifstate[iflevel].condition; - break; - default: - luaI_auxsynterrbf("invalid pragma", buff); - } - skipspace(); - if (current == '\n') /* pragma must end with a '\n' ... */ - inclinenumber(); - else if (current != EOZ) /* or eof */ - luaI_auxsyntaxerror("invalid pragma format"); - ifskip(); - } -} - -static int read_long_string (char *yytext, int buffsize) -{ - int cont = 0; - int tokensize = 2; /* '[[' already stored */ - while (1) - { - if (buffsize-tokensize <= 2) /* may read more than 1 char in one cicle */ - yytext = luaI_buffer(buffsize *= 2); - switch (current) - { - case EOZ: - save(0); - return WRONGTOKEN; - case '[': - save_and_next(); - if (current == '[') - { - cont++; - save_and_next(); - } - continue; - case ']': - save_and_next(); - if (current == ']') - { - if (cont == 0) goto endloop; - cont--; - save_and_next(); - } - continue; - case '\n': - save('\n'); - inclinenumber(); - continue; - default: - save_and_next(); - } - } endloop: - save_and_next(); /* pass the second ']' */ - yytext[tokensize-2] = 0; /* erases ']]' */ - luaY_lval.vWord = luaI_findconstantbyname(yytext+2); - yytext[tokensize-2] = ']'; /* restores ']]' */ - save(0); - return STRING; -} - -int luaY_lex (void) -{ - static int linelasttoken = 0; - double a; - int buffsize = MINBUFF; - char *yytext = luaI_buffer(buffsize); - yytext[1] = yytext[2] = yytext[3] = 0; - if (lua_debug) - luaI_codedebugline(linelasttoken); - linelasttoken = lua_linenumber; - while (1) - { - int tokensize = 0; - switch (current) - { - case '\n': - inclinenumber(); - linelasttoken = lua_linenumber; - continue; - - case ' ': case '\t': case '\r': /* CR: to avoid problems with DOS */ - next(); - continue; - - case '-': - save_and_next(); - if (current != '-') return '-'; - do { next(); } while (current != '\n' && current != EOZ); - continue; - - case '[': - save_and_next(); - if (current != '[') return '['; - else - { - save_and_next(); /* pass the second '[' */ - return read_long_string(yytext, buffsize); - } - - case '=': - save_and_next(); - if (current != '=') return '='; - else { save_and_next(); return EQ; } - - case '<': - save_and_next(); - if (current != '=') return '<'; - else { save_and_next(); return LE; } - - case '>': - save_and_next(); - if (current != '=') return '>'; - else { save_and_next(); return GE; } - - case '~': - save_and_next(); - if (current != '=') return '~'; - else { save_and_next(); return NE; } - - case '"': - case '\'': - { - int del = current; - save_and_next(); - while (current != del) - { - if (buffsize-tokensize <= 2) /* may read more than 1 char in one cicle */ - yytext = luaI_buffer(buffsize *= 2); - switch (current) - { - case EOZ: - case '\n': - save(0); - return WRONGTOKEN; - case '\\': - next(); /* do not save the '\' */ - switch (current) - { - case 'n': save('\n'); next(); break; - case 't': save('\t'); next(); break; - case 'r': save('\r'); next(); break; - case '\n': save('\n'); inclinenumber(); break; - default : save_and_next(); break; - } - break; - default: - save_and_next(); - } - } - next(); /* skip delimiter */ - save(0); - luaY_lval.vWord = luaI_findconstantbyname(yytext+1); - tokensize--; - save(del); save(0); /* restore delimiter */ - return STRING; - } - - case 'a': case 'b': case 'c': case 'd': case 'e': - case 'f': case 'g': case 'h': case 'i': case 'j': - case 'k': case 'l': case 'm': case 'n': case 'o': - case 'p': case 'q': case 'r': case 's': case 't': - case 'u': case 'v': case 'w': case 'x': case 'y': - case 'z': - case 'A': case 'B': case 'C': case 'D': case 'E': - case 'F': case 'G': case 'H': case 'I': case 'J': - case 'K': case 'L': case 'M': case 'N': case 'O': - case 'P': case 'Q': case 'R': case 'S': case 'T': - case 'U': case 'V': case 'W': case 'X': case 'Y': - case 'Z': - case '_': - { - TaggedString *ts; - do { - save_and_next(); - } while (isalnum((unsigned char)current) || current == '_'); - save(0); - ts = lua_createstring(yytext); - if (ts->marked > 2) - return ts->marked; /* reserved word */ - luaY_lval.pTStr = ts; - ts->marked = 2; /* avoid GC */ - return NAME; - } - - case '.': - save_and_next(); - if (current == '.') - { - save_and_next(); - if (current == '.') - { - save_and_next(); - return DOTS; /* ... */ - } - else return CONC; /* .. */ - } - else if (!isdigit((unsigned char)current)) return '.'; - /* current is a digit: goes through to number */ - a=0.0; - goto fraction; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - a=0.0; - do { - a=10.0*a+(current-'0'); - save_and_next(); - } while (isdigit((unsigned char)current)); - if (current == '.') { - save_and_next(); - if (current == '.') - luaI_syntaxerror( - "ambiguous syntax (decimal point x string concatenation)"); - } - fraction: - { double da=0.1; - while (isdigit((unsigned char)current)) - { - a+=(current-'0')*da; - da/=10.0; - save_and_next(); - } - if (current == 'e' || current == 'E') - { - int e=0; - int neg; - double ea; - save_and_next(); - neg=(current=='-'); - if (current == '+' || current == '-') save_and_next(); - if (!isdigit((unsigned char)current)) { - save(0); return WRONGTOKEN; } - do { - e=10.0*e+(current-'0'); - save_and_next(); - } while (isdigit((unsigned char)current)); - for (ea=neg?0.1:10.0; e>0; e>>=1) - { - if (e & 1) a*=ea; - ea*=ea; - } - } - luaY_lval.vFloat = a; - save(0); - return NUMBER; - } - - case EOZ: - save(0); - if (iflevel > 0) - luaI_syntaxerror("missing $endif"); - return 0; - - default: - save_and_next(); - return yytext[0]; - } - } -} - diff --git a/src/lex.h b/src/lex.h deleted file mode 100644 index a942cf6..0000000 --- a/src/lex.h +++ /dev/null @@ -1,18 +0,0 @@ -/* -** lex.h -** TecCGraf - PUC-Rio -** $Id: lex.h,v 1.4 1997/06/16 16:50:22 roberto Exp $ -*/ - -#ifndef lex_h -#define lex_h - -#include "zio.h" - -void lua_setinput (ZIO *z); -void luaI_syntaxerror (char *s); -int luaY_lex (void); -void luaI_addReserved (void); - - -#endif diff --git a/src/lfunc.c b/src/lfunc.c new file mode 100644 index 0000000..fae5966 --- /dev/null +++ b/src/lfunc.c @@ -0,0 +1,98 @@ +/* +** $Id: lfunc.c,v 1.9 1998/06/19 16:14:09 roberto Exp $ +** Auxiliary functions to manipulate prototypes and closures +** See Copyright Notice in lua.h +*/ + + +#include + +#include "lfunc.h" +#include "lmem.h" +#include "lstate.h" + +#define gcsizeproto(p) 5 /* approximate "weight" for a prototype */ +#define gcsizeclosure(c) 1 /* approximate "weight" for a closure */ + + + +Closure *luaF_newclosure (int nelems) +{ + Closure *c = (Closure *)luaM_malloc(sizeof(Closure)+nelems*sizeof(TObject)); + luaO_insertlist(&(L->rootcl), (GCnode *)c); + L->nblocks += gcsizeclosure(c); + c->nelems = nelems; + return c; +} + + +TProtoFunc *luaF_newproto (void) +{ + TProtoFunc *f = luaM_new(TProtoFunc); + f->code = NULL; + f->lineDefined = 0; + f->fileName = NULL; + f->consts = NULL; + f->nconsts = 0; + f->locvars = NULL; + luaO_insertlist(&(L->rootproto), (GCnode *)f); + L->nblocks += gcsizeproto(f); + return f; +} + + + +static void freefunc (TProtoFunc *f) +{ + luaM_free(f->code); + luaM_free(f->locvars); + luaM_free(f->consts); + luaM_free(f); +} + + +void luaF_freeproto (TProtoFunc *l) +{ + while (l) { + TProtoFunc *next = (TProtoFunc *)l->head.next; + L->nblocks -= gcsizeproto(l); + freefunc(l); + l = next; + } +} + + +void luaF_freeclosure (Closure *l) +{ + while (l) { + Closure *next = (Closure *)l->head.next; + L->nblocks -= gcsizeclosure(l); + luaM_free(l); + l = next; + } +} + + +/* +** Look for n-th local variable at line "line" in function "func". +** Returns NULL if not found. +*/ +char *luaF_getlocalname (TProtoFunc *func, int local_number, int line) +{ + int count = 0; + char *varname = NULL; + LocVar *lv = func->locvars; + if (lv == NULL) + return NULL; + for (; lv->line != -1 && lv->line < line; lv++) { + if (lv->varname) { /* register */ + if (++count == local_number) + varname = lv->varname->str; + } + else /* unregister */ + if (--count < local_number) + varname = NULL; + } + return varname; +} + diff --git a/src/lfunc.h b/src/lfunc.h new file mode 100644 index 0000000..cade80a --- /dev/null +++ b/src/lfunc.h @@ -0,0 +1,23 @@ +/* +** $Id: lfunc.h,v 1.5 1997/12/15 16:17:20 roberto Exp $ +** Lua Function structures +** See Copyright Notice in lua.h +*/ + +#ifndef lfunc_h +#define lfunc_h + + +#include "lobject.h" + + + +TProtoFunc *luaF_newproto (void); +Closure *luaF_newclosure (int nelems); +void luaF_freeproto (TProtoFunc *l); +void luaF_freeclosure (Closure *l); + +char *luaF_getlocalname (TProtoFunc *func, int local_number, int line); + + +#endif diff --git a/src/lgc.c b/src/lgc.c new file mode 100644 index 0000000..f982a82 --- /dev/null +++ b/src/lgc.c @@ -0,0 +1,288 @@ +/* +** $Id: lgc.c,v 1.18 1998/03/09 21:49:52 roberto Exp $ +** Garbage Collector +** See Copyright Notice in lua.h +*/ + + +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "lua.h" + + + +static int markobject (TObject *o); + + + +/* +** ======================================================= +** REF mechanism +** ======================================================= +*/ + + +int luaC_ref (TObject *o, int lock) +{ + int ref; + if (ttype(o) == LUA_T_NIL) + ref = -1; /* special ref for nil */ + else { + for (ref=0; refrefSize; ref++) + if (L->refArray[ref].status == FREE) + goto found; + /* no more empty spaces */ { + int oldSize = L->refSize; + L->refSize = luaM_growvector(&L->refArray, L->refSize, struct ref, + refEM, MAX_INT); + for (ref=oldSize; refrefSize; ref++) + L->refArray[ref].status = FREE; + ref = oldSize; + } found: + L->refArray[ref].o = *o; + L->refArray[ref].status = lock ? LOCK : HOLD; + } + return ref; +} + + +void lua_unref (int ref) +{ + if (ref >= 0 && ref < L->refSize) + L->refArray[ref].status = FREE; +} + + +TObject* luaC_getref (int ref) +{ + if (ref == -1) + return &luaO_nilobject; + if (ref >= 0 && ref < L->refSize && + (L->refArray[ref].status == LOCK || L->refArray[ref].status == HOLD)) + return &L->refArray[ref].o; + else + return NULL; +} + + +static void travlock (void) +{ + int i; + for (i=0; irefSize; i++) + if (L->refArray[i].status == LOCK) + markobject(&L->refArray[i].o); +} + + +static int ismarked (TObject *o) +{ + /* valid only for locked objects */ + switch (o->ttype) { + case LUA_T_STRING: case LUA_T_USERDATA: + return o->value.ts->head.marked; + case LUA_T_ARRAY: + return o->value.a->head.marked; + case LUA_T_CLOSURE: + return o->value.cl->head.marked; + case LUA_T_PROTO: + return o->value.tf->head.marked; +#ifdef DEBUG + case LUA_T_LINE: case LUA_T_CLMARK: + case LUA_T_CMARK: case LUA_T_PMARK: + LUA_INTERNALERROR("invalid type"); +#endif + default: /* nil, number or cproto */ + return 1; + } +} + + +static void invalidaterefs (void) +{ + int i; + for (i=0; irefSize; i++) + if (L->refArray[i].status == HOLD && !ismarked(&L->refArray[i].o)) + L->refArray[i].status = COLLECTED; +} + + + +void luaC_hashcallIM (Hash *l) +{ + TObject t; + ttype(&t) = LUA_T_ARRAY; + for (; l; l=(Hash *)l->head.next) { + avalue(&t) = l; + luaD_gcIM(&t); + } +} + + +void luaC_strcallIM (TaggedString *l) +{ + TObject o; + ttype(&o) = LUA_T_USERDATA; + for (; l; l=(TaggedString *)l->head.next) + if (l->constindex == -1) { /* is userdata? */ + tsvalue(&o) = l; + luaD_gcIM(&o); + } +} + + + +static GCnode *listcollect (GCnode *l) +{ + GCnode *frees = NULL; + while (l) { + GCnode *next = l->next; + l->marked = 0; + while (next && !next->marked) { + l->next = next->next; + next->next = frees; + frees = next; + next = l->next; + } + l = next; + } + return frees; +} + + +static void strmark (TaggedString *s) +{ + if (!s->head.marked) + s->head.marked = 1; +} + + +static void protomark (TProtoFunc *f) +{ + if (!f->head.marked) { + LocVar *v = f->locvars; + int i; + f->head.marked = 1; + if (f->fileName) + strmark(f->fileName); + for (i=0; inconsts; i++) + markobject(&f->consts[i]); + if (v) { + for (; v->line != -1; v++) + if (v->varname) + strmark(v->varname); + } + } +} + + +static void closuremark (Closure *f) +{ + if (!f->head.marked) { + int i; + f->head.marked = 1; + for (i=f->nelems; i>=0; i--) + markobject(&f->consts[i]); + } +} + + +static void hashmark (Hash *h) +{ + if (!h->head.marked) { + int i; + h->head.marked = 1; + for (i=0; iref); + markobject(&n->val); + } + } + } +} + + +static void globalmark (void) +{ + TaggedString *g; + for (g=(TaggedString *)L->rootglobal.next; g; g=(TaggedString *)g->head.next){ + LUA_ASSERT(g->constindex >= 0, "userdata in global list"); + if (g->u.s.globalval.ttype != LUA_T_NIL) { + markobject(&g->u.s.globalval); + strmark(g); /* cannot collect non nil global variables */ + } + } +} + + +static int markobject (TObject *o) +{ + switch (ttype(o)) { + case LUA_T_USERDATA: case LUA_T_STRING: + strmark(tsvalue(o)); + break; + case LUA_T_ARRAY: + hashmark(avalue(o)); + break; + case LUA_T_CLOSURE: case LUA_T_CLMARK: + closuremark(o->value.cl); + break; + case LUA_T_PROTO: case LUA_T_PMARK: + protomark(o->value.tf); + break; + default: break; /* numbers, cprotos, etc */ + } + return 0; +} + + + +static void markall (void) +{ + luaD_travstack(markobject); /* mark stack objects */ + globalmark(); /* mark global variable values and names */ + travlock(); /* mark locked objects */ + luaT_travtagmethods(markobject); /* mark fallbacks */ +} + + +long lua_collectgarbage (long limit) +{ + unsigned long recovered = L->nblocks; /* to subtract nblocks after gc */ + Hash *freetable; + TaggedString *freestr; + TProtoFunc *freefunc; + Closure *freeclos; + markall(); + invalidaterefs(); + freestr = luaS_collector(); + freetable = (Hash *)listcollect(&(L->roottable)); + freefunc = (TProtoFunc *)listcollect(&(L->rootproto)); + freeclos = (Closure *)listcollect(&(L->rootcl)); + L->GCthreshold *= 4; /* to avoid GC during GC */ + luaC_hashcallIM(freetable); /* GC tag methods for tables */ + luaC_strcallIM(freestr); /* GC tag methods for userdata */ + luaD_gcIM(&luaO_nilobject); /* GC tag method for nil (signal end of GC) */ + luaH_free(freetable); + luaS_free(freestr); + luaF_freeproto(freefunc); + luaF_freeclosure(freeclos); + recovered = recovered-L->nblocks; + L->GCthreshold = (limit == 0) ? 2*L->nblocks : L->nblocks+limit; + return recovered; +} + + +void luaC_checkGC (void) +{ + if (L->nblocks >= L->GCthreshold) + lua_collectgarbage(0); +} + diff --git a/src/lgc.h b/src/lgc.h new file mode 100644 index 0000000..38b0955 --- /dev/null +++ b/src/lgc.h @@ -0,0 +1,21 @@ +/* +** $Id: lgc.h,v 1.4 1997/12/01 20:31:25 roberto Exp $ +** Garbage Collector +** See Copyright Notice in lua.h +*/ + +#ifndef lgc_h +#define lgc_h + + +#include "lobject.h" + + +void luaC_checkGC (void); +TObject* luaC_getref (int ref); +int luaC_ref (TObject *o, int lock); +void luaC_hashcallIM (Hash *l); +void luaC_strcallIM (TaggedString *l); + + +#endif diff --git a/src/lib/Makefile b/src/lib/Makefile new file mode 100644 index 0000000..70db660 --- /dev/null +++ b/src/lib/Makefile @@ -0,0 +1,28 @@ +# makefile for lua standard library + +LUA= ../.. + +include $(LUA)/config + +# actually only used in liolib.c +EXTRA_DEFS= $(POPEN) + +OBJS= liolib.o lmathlib.o lstrlib.o +SRCS= liolib.c lmathlib.c lstrlib.c + +T= $(LIB)/liblualib.a + +all: $T + +$T: $(OBJS) + $(AR) $@ $(OBJS) + $(RANLIB) $@ + +clean: + rm -f $(OBJS) $T + +co: + co -q -f -M $(SRCS) + +klean: clean + rm -f $(SRCS) diff --git a/src/lib/README b/src/lib/README new file mode 100644 index 0000000..e8e599c --- /dev/null +++ b/src/lib/README @@ -0,0 +1,4 @@ +This is the standard Lua library. +It is implemented entirely on top of the official Lua API as declared in lua.h, +using src/lauxlib.c, which contains several useful functions. +The code can be read as an example of how to export C functions to Lua. diff --git a/src/lib/liolib.c b/src/lib/liolib.c new file mode 100644 index 0000000..15ea658 --- /dev/null +++ b/src/lib/liolib.c @@ -0,0 +1,448 @@ +/* +** $Id: liolib.c,v 1.21 1998/06/18 17:04:28 roberto Exp $ +** Standard I/O (and system) library +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include +#include +#include + +#include "lauxlib.h" +#include "lua.h" +#include "luadebug.h" +#include "lualib.h" + + +#ifndef OLD_ANSI +#include +#else +#define setlocale(a,b) 0 +#define LC_ALL 0 +#define LC_COLLATE 0 +#define LC_CTYPE 0 +#define LC_MONETARY 0 +#define LC_NUMERIC 0 +#define LC_TIME 0 +#define strerror(e) "(no error message provided by operating system)" +#endif + + +#define CLOSEDTAG 2 +#define IOTAG 1 + +#define FIRSTARG 3 /* 1st and 2nd are upvalues */ + +#define FINPUT "_INPUT" +#define FOUTPUT "_OUTPUT" + + +#ifdef POPEN +FILE *popen(); +int pclose(); +#else +#define popen(x,y) NULL /* that is, popen always fails */ +#define pclose(x) (-1) +#endif + + +static int gettag (int i) +{ + return lua_getnumber(lua_getparam(i)); +} + + +static void pushresult (int i) +{ + if (i) + lua_pushuserdata(NULL); + else { + lua_pushnil(); + lua_pushstring(strerror(errno)); + } +} + + +static int ishandler (lua_Object f) +{ + if (lua_isuserdata(f)) { + if (lua_tag(f) == gettag(CLOSEDTAG)) + lua_error("cannot access a closed file"); + return lua_tag(f) == gettag(IOTAG); + } + else return 0; +} + +static FILE *getfile (char *name) +{ + lua_Object f = lua_getglobal(name); + if (!ishandler(f)) + luaL_verror("global variable `%.50s' is not a file handle", name); + return lua_getuserdata(f); +} + + +static FILE *getfileparam (char *name, int *arg) +{ + lua_Object f = lua_getparam(*arg); + if (ishandler(f)) { + (*arg)++; + return lua_getuserdata(f); + } + else + return getfile(name); +} + + +static void closefile (char *name) +{ + FILE *f = getfile(name); + if (f == stdin || f == stdout) return; + if (pclose(f) == -1) + fclose(f); + lua_pushobject(lua_getglobal(name)); + lua_settag(gettag(CLOSEDTAG)); +} + + +static void setfile (FILE *f, char *name, int tag) +{ + lua_pushusertag(f, tag); + lua_setglobal(name); +} + + +static void setreturn (FILE *f, char *name) +{ + int tag = gettag(IOTAG); + setfile(f, name, tag); + lua_pushusertag(f, tag); +} + + +static void io_readfrom (void) +{ + FILE *current; + lua_Object f = lua_getparam(FIRSTARG); + if (f == LUA_NOOBJECT) { + closefile(FINPUT); + current = stdin; + } + else if (lua_tag(f) == gettag(IOTAG)) + current = lua_getuserdata(f); + else { + char *s = luaL_check_string(FIRSTARG); + current = (*s == '|') ? popen(s+1, "r") : fopen(s, "r"); + if (current == NULL) { + pushresult(0); + return; + } + } + setreturn(current, FINPUT); +} + + +static void io_writeto (void) +{ + FILE *current; + lua_Object f = lua_getparam(FIRSTARG); + if (f == LUA_NOOBJECT) { + closefile(FOUTPUT); + current = stdout; + } + else if (lua_tag(f) == gettag(IOTAG)) + current = lua_getuserdata(f); + else { + char *s = luaL_check_string(FIRSTARG); + current = (*s == '|') ? popen(s+1,"w") : fopen(s,"w"); + if (current == NULL) { + pushresult(0); + return; + } + } + setreturn(current, FOUTPUT); +} + + +static void io_appendto (void) +{ + char *s = luaL_check_string(FIRSTARG); + FILE *fp = fopen (s, "a"); + if (fp != NULL) + setreturn(fp, FOUTPUT); + else + pushresult(0); +} + + +#define NEED_OTHER (EOF-1) /* just some flag different from EOF */ + + +static void read_until (FILE *f, int lim) { + int l = 0; + int c; + for (c = getc(f); c != EOF && c != lim; c = getc(f)) { + luaL_addchar(c); + l++; + } + if (l > 0 || c == lim) /* read anything? */ + lua_pushlstring(luaL_buffer(), l); +} + +static void io_read (void) { + int arg = FIRSTARG; + FILE *f = getfileparam(FINPUT, &arg); + char *p = luaL_opt_string(arg, NULL); + luaL_resetbuffer(); + if (p == NULL) /* default: read a line */ + read_until(f, '\n'); + else if (p[0] == '.' && p[1] == '*' && p[2] == 0) /* p = ".*" */ + read_until(f, EOF); + else { + int l = 0; /* number of chars read in buffer */ + int inskip = 0; /* to control {skips} */ + int c = NEED_OTHER; + while (*p) { + switch (*p) { + case '{': + inskip++; + p++; + continue; + case '}': + if (inskip == 0) + lua_error("unbalanced braces in read pattern"); + inskip--; + p++; + continue; + default: { + char *ep; /* get what is next */ + int m; /* match result */ + if (c == NEED_OTHER) c = getc(f); + if (c == EOF) { + luaI_singlematch(0, p, &ep); /* to set "ep" */ + m = 0; + } + else { + m = luaI_singlematch(c, p, &ep); + if (m) { + if (inskip == 0) { + luaL_addchar(c); + l++; + } + c = NEED_OTHER; + } + } + switch (*ep) { + case '*': /* repetition */ + if (!m) p = ep+1; /* else stay in (repeat) the same item */ + continue; + case '?': /* optional */ + p = ep+1; /* continues reading the pattern */ + continue; + default: + if (m) p = ep; /* continues reading the pattern */ + else + goto break_while; /* pattern fails */ + } + } + } + } break_while: + if (c >= 0) /* not EOF nor NEED_OTHER? */ + ungetc(c, f); + if (l > 0 || *p == 0) /* read something or did not fail? */ + lua_pushlstring(luaL_buffer(), l); + } +} + + +static void io_write (void) +{ + int arg = FIRSTARG; + FILE *f = getfileparam(FOUTPUT, &arg); + int status = 1; + char *s; + long l; + while ((s = luaL_opt_lstr(arg++, NULL, &l)) != NULL) + status = status && (fwrite(s, 1, l, f) == l); + pushresult(status); +} + + +static void io_execute (void) +{ + lua_pushnumber(system(luaL_check_string(1))); +} + + +static void io_remove (void) +{ + pushresult(remove(luaL_check_string(1)) == 0); +} + + +static void io_rename (void) +{ + pushresult(rename(luaL_check_string(1), + luaL_check_string(2)) == 0); +} + + +static void io_tmpname (void) +{ + lua_pushstring(tmpnam(NULL)); +} + + + +static void io_getenv (void) +{ + lua_pushstring(getenv(luaL_check_string(1))); /* if NULL push nil */ +} + + +static void io_clock (void) { + lua_pushnumber(((double)clock())/CLOCKS_PER_SEC); +} + + +static void io_date (void) +{ + time_t t; + struct tm *tm; + char *s = luaL_opt_string(1, "%c"); + char b[BUFSIZ]; + time(&t); tm = localtime(&t); + if (strftime(b,sizeof(b),s,tm)) + lua_pushstring(b); + else + lua_error("invalid `date' format"); +} + + +static void setloc (void) +{ + static int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, + LC_TIME}; + static char *catnames[] = {"all", "collate", "ctype", "monetary", + "numeric", "time", NULL}; + int op = luaL_findstring(luaL_opt_string(2, "all"), catnames); + luaL_arg_check(op != -1, 2, "invalid option"); + lua_pushstring(setlocale(cat[op], luaL_check_string(1))); +} + + +static void io_exit (void) +{ + lua_Object o = lua_getparam(1); + exit(lua_isnumber(o) ? (int)lua_getnumber(o) : 1); +} + + +static void io_debug (void) +{ + while (1) { + char buffer[250]; + fprintf(stderr, "lua_debug> "); + if (fgets(buffer, sizeof(buffer), stdin) == 0) return; + if (strcmp(buffer, "cont\n") == 0) return; + lua_dostring(buffer); + } +} + + +static void lua_printstack (FILE *f) +{ + int level = 1; /* skip level 0 (it's this function) */ + lua_Object func; + while ((func = lua_stackedfunction(level++)) != LUA_NOOBJECT) { + char *name; + int currentline; + char *filename; + int linedefined; + lua_funcinfo(func, &filename, &linedefined); + fprintf(f, (level==2) ? "Active Stack:\n\t" : "\t"); + switch (*lua_getobjname(func, &name)) { + case 'g': + fprintf(f, "function %s", name); + break; + case 't': + fprintf(f, "`%s' tag method", name); + break; + default: { + if (linedefined == 0) + fprintf(f, "main of %s", filename); + else if (linedefined < 0) + fprintf(f, "%s", filename); + else + fprintf(f, "function (%s:%d)", filename, linedefined); + filename = NULL; + } + } + if ((currentline = lua_currentline(func)) > 0) + fprintf(f, " at line %d", currentline); + if (filename) + fprintf(f, " [in file %s]", filename); + fprintf(f, "\n"); + } +} + + +static void errorfb (void) +{ + fprintf(stderr, "lua: %s\n", lua_getstring(lua_getparam(1))); + lua_printstack(stderr); +} + + + +static struct luaL_reg iolib[] = { +{"setlocale", setloc}, +{"execute", io_execute}, +{"remove", io_remove}, +{"rename", io_rename}, +{"tmpname", io_tmpname}, +{"getenv", io_getenv}, +{"date", io_date}, +{"clock", io_clock}, +{"exit", io_exit}, +{"debug", io_debug}, +{"print_stack", errorfb} +}; + +static struct luaL_reg iolibtag[] = { +{"readfrom", io_readfrom}, +{"writeto", io_writeto}, +{"appendto", io_appendto}, +{"read", io_read}, +{"write", io_write} +}; + +static void openwithtags (void) +{ + int iotag = lua_newtag(); + int closedtag = lua_newtag(); + int i; + for (i=0; i +#include + +#include "lauxlib.h" +#include "lua.h" +#include "lualib.h" + +#ifdef M_PI +#define PI M_PI +#else +#define PI ((double)3.14159265358979323846) +#endif + + +#define FROMRAD(a) ((a)*(180.0/PI)) +#define TORAD(a) ((a)*(PI/180.0)) + + +static void math_abs (void) +{ + double d = luaL_check_number(1); + if (d < 0) d = -d; + lua_pushnumber(d); +} + +static void math_sin (void) +{ + lua_pushnumber(sin(TORAD(luaL_check_number(1)))); +} + +static void math_cos (void) +{ + lua_pushnumber(cos(TORAD(luaL_check_number(1)))); +} + +static void math_tan (void) +{ + lua_pushnumber(tan(TORAD(luaL_check_number(1)))); +} + +static void math_asin (void) +{ + lua_pushnumber(FROMRAD(asin(luaL_check_number(1)))); +} + +static void math_acos (void) +{ + lua_pushnumber(FROMRAD(acos(luaL_check_number(1)))); +} + +static void math_atan (void) +{ + lua_pushnumber(FROMRAD(atan(luaL_check_number(1)))); +} + +static void math_atan2 (void) +{ + lua_pushnumber(FROMRAD(atan2(luaL_check_number(1), luaL_check_number(2)))); +} + +static void math_ceil (void) +{ + lua_pushnumber(ceil(luaL_check_number(1))); +} + +static void math_floor (void) +{ + lua_pushnumber(floor(luaL_check_number(1))); +} + +static void math_mod (void) +{ + lua_pushnumber(fmod(luaL_check_number(1), luaL_check_number(2))); +} + +static void math_sqrt (void) +{ + lua_pushnumber(sqrt(luaL_check_number(1))); +} + +static void math_pow (void) +{ + lua_pushnumber(pow(luaL_check_number(1), luaL_check_number(2))); +} + +static void math_log (void) +{ + lua_pushnumber(log(luaL_check_number(1))); +} + +static void math_log10 (void) +{ + lua_pushnumber(log10(luaL_check_number(1))); +} + +static void math_exp (void) +{ + lua_pushnumber(exp(luaL_check_number(1))); +} + +static void math_deg (void) +{ + lua_pushnumber(luaL_check_number(1)*(180.0/PI)); +} + +static void math_rad (void) +{ + lua_pushnumber(luaL_check_number(1)*(PI/180.0)); +} + +static void math_frexp (void) { + int e; + lua_pushnumber(frexp(luaL_check_number(1), &e)); + lua_pushnumber(e); +} + +static void math_ldexp (void) { + lua_pushnumber(ldexp(luaL_check_number(1), luaL_check_number(2))); +} + + + +static void math_min (void) +{ + int i = 1; + double dmin = luaL_check_number(i); + while (lua_getparam(++i) != LUA_NOOBJECT) { + double d = luaL_check_number(i); + if (d < dmin) + dmin = d; + } + lua_pushnumber(dmin); +} + + +static void math_max (void) +{ + int i = 1; + double dmax = luaL_check_number(i); + while (lua_getparam(++i) != LUA_NOOBJECT) { + double d = luaL_check_number(i); + if (d > dmax) + dmax = d; + } + lua_pushnumber(dmax); +} + + +static void math_random (void) +{ + /* the '%' is needed because on some systems (SunOS!) "rand()" may */ + /* return a value bigger than RAND_MAX... */ + double r = (double)(rand()%RAND_MAX) / (double)RAND_MAX; + double l = luaL_opt_number(1, 0); + if (l == 0) + lua_pushnumber(r); + else + lua_pushnumber((int)(r*l)+1); +} + + +static void math_randomseed (void) +{ + srand(luaL_check_number(1)); +} + + +static struct luaL_reg mathlib[] = { +{"abs", math_abs}, +{"sin", math_sin}, +{"cos", math_cos}, +{"tan", math_tan}, +{"asin", math_asin}, +{"acos", math_acos}, +{"atan", math_atan}, +{"atan2", math_atan2}, +{"ceil", math_ceil}, +{"floor", math_floor}, +{"mod", math_mod}, +{"frexp", math_frexp}, +{"ldexp", math_ldexp}, +{"sqrt", math_sqrt}, +{"min", math_min}, +{"max", math_max}, +{"log", math_log}, +{"log10", math_log10}, +{"exp", math_exp}, +{"deg", math_deg}, +{"rad", math_rad}, +{"random", math_random}, +{"randomseed", math_randomseed} +}; + +/* +** Open math library +*/ +void lua_mathlibopen (void) +{ + luaL_openlib(mathlib, (sizeof(mathlib)/sizeof(mathlib[0]))); + lua_pushstring("deg"); lua_setglobal("_TRIGMODE"); + lua_pushcfunction(math_pow); + lua_pushnumber(0); /* to get its tag */ + lua_settagmethod(lua_tag(lua_pop()), "pow"); + lua_pushnumber(PI); lua_setglobal("PI"); +} + diff --git a/src/lib/lstrlib.c b/src/lib/lstrlib.c new file mode 100644 index 0000000..dc79cc7 --- /dev/null +++ b/src/lib/lstrlib.c @@ -0,0 +1,541 @@ +/* +** $Id: lstrlib.c,v 1.18 1998/07/01 14:21:57 roberto Exp $ +** Standard library for strings and pattern-matching +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include +#include + +#include "lauxlib.h" +#include "lua.h" +#include "lualib.h" + + + +static void addnchar (char *s, int n) +{ + char *b = luaL_openspace(n); + memcpy(b, s, n); + luaL_addsize(n); +} + + +static void str_len (void) +{ + long l; + luaL_check_lstr(1, &l); + lua_pushnumber(l); +} + + +static void closeandpush (void) +{ + lua_pushlstring(luaL_buffer(), luaL_getsize()); +} + + +static long posrelat (long pos, long len) +{ + /* relative string position: negative means back from end */ + return (pos>=0) ? pos : len+pos+1; +} + + +static void str_sub (void) +{ + long l; + char *s = luaL_check_lstr(1, &l); + long start = posrelat(luaL_check_number(2), l); + long end = posrelat(luaL_opt_number(3, -1), l); + if (1 <= start && start <= end && end <= l) + lua_pushlstring(s+start-1, end-start+1); + else lua_pushstring(""); +} + + +static void str_lower (void) +{ + long l; + int i; + char *s = luaL_check_lstr(1, &l); + luaL_resetbuffer(); + for (i=0; i 0) + addnchar(s, l); + closeandpush(); +} + + +static void str_byte (void) +{ + long l; + char *s = luaL_check_lstr(1, &l); + long pos = posrelat(luaL_opt_number(2, 1), l); + luaL_arg_check(0level; i++) + lua_pushlstring(cap->capture[i].init, cap->capture[i].len); +} + + +static int check_cap (int l, struct Capture *cap) +{ + l -= '1'; + if (!(0 <= l && l < cap->level && cap->capture[l].len != -1)) + lua_error("invalid capture index"); + return l; +} + + +static int capture_to_close (struct Capture *cap) +{ + int level = cap->level; + for (level--; level>=0; level--) + if (cap->capture[level].len == -1) return level; + lua_error("invalid pattern capture"); + return 0; /* to avoid warnings */ +} + + +static char *bracket_end (char *p) +{ + return (*p == 0) ? NULL : strchr((*p=='^') ? p+2 : p+1, ']'); +} + + +static int matchclass (int c, int cl) +{ + int res; + switch (tolower(cl)) { + case 'a' : res = isalpha(c); break; + case 'c' : res = iscntrl(c); break; + case 'd' : res = isdigit(c); break; + case 'l' : res = islower(c); break; + case 'p' : res = ispunct(c); break; + case 's' : res = isspace(c); break; + case 'u' : res = isupper(c); break; + case 'w' : res = isalnum(c); break; + case 'z' : res = (c == '\0'); break; + default: return (cl == c); + } + return (islower((unsigned char)cl) ? res : !res); +} + + +int luaI_singlematch (int c, char *p, char **ep) +{ + switch (*p) { + case '.': /* matches any char */ + *ep = p+1; + return 1; + case '\0': /* end of pattern; matches nothing */ + *ep = p; + return 0; + case ESC: + if (*(++p) == '\0') + luaL_verror("incorrect pattern (ends with `%c')", ESC); + *ep = p+1; + return matchclass(c, (unsigned char)*p); + case '[': { + char *end = bracket_end(p+1); + int sig = *(p+1) == '^' ? (p++, 0) : 1; + if (end == NULL) lua_error("incorrect pattern (missing `]')"); + *ep = end+1; + while (++p < end) { + if (*p == ESC) { + if (((p+1) < end) && matchclass(c, (unsigned char)*++p)) + return sig; + } + else if ((*(p+1) == '-') && (p+2 < end)) { + p+=2; + if ((unsigned char)*(p-2) <= c && c <= (unsigned char)*p) + return sig; + } + else if ((unsigned char)*p == c) return sig; + } + return !sig; + } + default: + *ep = p+1; + return ((unsigned char)*p == c); + } +} + + +static char *matchbalance (char *s, int b, int e, struct Capture *cap) +{ + if (*s != b) return NULL; + else { + int cont = 1; + while (++s < cap->src_end) { + if (*s == e) { + if (--cont == 0) return s+1; + } + else if (*s == b) cont++; + } + } + return NULL; /* string ends out of balance */ +} + + +static char *matchitem (char *s, char *p, struct Capture *cap, char **ep) +{ + if (*p == ESC) { + p++; + if (isdigit((unsigned char)*p)) { /* capture */ + int l = check_cap(*p, cap); + int len = cap->capture[l].len; + *ep = p+1; + if (cap->src_end-s >= len && memcmp(cap->capture[l].init, s, len) == 0) + return s+len; + else return NULL; + } + else if (*p == 'b') { /* balanced string */ + p++; + if (*p == 0 || *(p+1) == 0) + lua_error("unbalanced pattern"); + *ep = p+2; + return matchbalance(s, *p, *(p+1), cap); + } + else p--; /* and go through */ + } + /* "luaI_singlematch" sets "ep" (so must be called even when *s == 0) */ + return (luaI_singlematch((unsigned char)*s, p, ep) && ssrc_end) ? + s+1 : NULL; +} + + +static char *match (char *s, char *p, struct Capture *cap) +{ + init: /* using goto's to optimize tail recursion */ + switch (*p) { + case '(': { /* start capture */ + char *res; + if (cap->level >= MAX_CAPT) lua_error("too many captures"); + cap->capture[cap->level].init = s; + cap->capture[cap->level].len = -1; + cap->level++; + if ((res=match(s, p+1, cap)) == NULL) /* match failed? */ + cap->level--; /* undo capture */ + return res; + } + case ')': { /* end capture */ + int l = capture_to_close(cap); + char *res; + cap->capture[l].len = s - cap->capture[l].init; /* close capture */ + if ((res = match(s, p+1, cap)) == NULL) /* match failed? */ + cap->capture[l].len = -1; /* undo capture */ + return res; + } + case '\0': case '$': /* (possibly) end of pattern */ + if (*p == 0 || (*(p+1) == 0 && s == cap->src_end)) + return s; + /* else go through */ + default: { /* it is a pattern item */ + char *ep; /* get what is next */ + char *s1 = matchitem(s, p, cap, &ep); + switch (*ep) { + case '*': { /* repetition */ + char *res; + if (s1 && s1>s && ((res=match(s1, p, cap)) != NULL)) + return res; + p=ep+1; goto init; /* else return match(s, ep+1, cap); */ + } + case '?': { /* optional */ + char *res; + if (s1 && ((res=match(s1, ep+1, cap)) != NULL)) + return res; + p=ep+1; goto init; /* else return match(s, ep+1, cap); */ + } + case '-': { /* repetition */ + char *res; + if ((res = match(s, ep+1, cap)) != NULL) + return res; + else if (s1 && s1>s) { + s = s1; + goto init; /* return match(s1, p, cap); */ + } + else + return NULL; + } + default: + if (s1) { s=s1; p=ep; goto init; } /* return match(s1, ep, cap); */ + else return NULL; + } + } + } +} + + +static void str_find (void) +{ + long l; + char *s = luaL_check_lstr(1, &l); + char *p = luaL_check_string(2); + long init = posrelat(luaL_opt_number(3, 1), l) - 1; + struct Capture cap; + luaL_arg_check(0 <= init && init <= l, 3, "out of range"); + if (lua_getparam(4) != LUA_NOOBJECT || + strpbrk(p, SPECIALS) == NULL) { /* no special characters? */ + char *s2 = strstr(s+init, p); + if (s2) { + lua_pushnumber(s2-s+1); + lua_pushnumber(s2-s+strlen(p)); + return; + } + } + else { + int anchor = (*p == '^') ? (p++, 1) : 0; + char *s1=s+init; + cap.src_end = s+l; + do { + char *res; + cap.level = 0; + if ((res=match(s1, p, &cap)) != NULL) { + lua_pushnumber(s1-s+1); /* start */ + lua_pushnumber(res-s); /* end */ + push_captures(&cap); + return; + } + } while (s1++capture[level].init, cap->capture[level].len); + } + } + } + } + else { /* is a function */ + lua_Object res; + int status; + int oldbuff; + lua_beginblock(); + push_captures(cap); + /* function may use buffer, so save it and create a new one */ + oldbuff = luaL_newbuffer(0); + status = lua_callfunction(newp); + /* restore old buffer */ + luaL_oldbuffer(oldbuff); + if (status != 0) { + lua_endblock(); + lua_error(NULL); + } + res = lua_getresult(1); + if (lua_isstring(res)) + addnchar(lua_getstring(res), lua_strlen(res)); + lua_endblock(); + } +} + + +static void str_gsub (void) +{ + long srcl; + char *src = luaL_check_lstr(1, &srcl); + char *p = luaL_check_string(2); + lua_Object newp = lua_getparam(3); + int max_s = (int)luaL_opt_number(4, srcl+1); + int anchor = (*p == '^') ? (p++, 1) : 0; + int n = 0; + struct Capture cap; + luaL_arg_check(lua_isstring(newp) || lua_isfunction(newp), 3, + "string or function expected"); + luaL_resetbuffer(); + cap.src_end = src+srcl; + while (n < max_s) { + char *e; + cap.level = 0; + e = match(src, p, &cap); + if (e) { + n++; + add_s(newp, &cap); + } + if (e && e>src) /* non empty match? */ + src = e; /* skip it */ + else if (src < cap.src_end) + luaL_addchar(*src++); + else break; + if (anchor) break; + } + addnchar(src, cap.src_end-src); + closeandpush(); + lua_pushnumber(n); /* number of substitutions */ +} + + +static void luaI_addquoted (char *s) +{ + luaL_addchar('"'); + for (; *s; s++) { + if (strchr("\"\\\n", *s)) + luaL_addchar('\\'); + luaL_addchar(*s); + } + luaL_addchar('"'); +} + +#define MAX_FORMAT 200 + +static void str_format (void) +{ + int arg = 1; + char *strfrmt = luaL_check_string(arg); + struct Capture cap; + cap.src_end = strfrmt+strlen(strfrmt)+1; + luaL_resetbuffer(); + while (*strfrmt) { + if (*strfrmt != '%') + luaL_addchar(*strfrmt++); + else if (*++strfrmt == '%') + luaL_addchar(*strfrmt++); /* %% */ + else { /* format item */ + char form[MAX_FORMAT]; /* store the format ('%...') */ + char *buff; + char *initf = strfrmt; + form[0] = '%'; + cap.level = 0; + if (isdigit((unsigned char)initf[0]) && initf[1] == '$') { + arg = initf[0] - '0'; + initf += 2; /* skip the 'n$' */ + } + arg++; + strfrmt = match(initf, "[-+ #0]*(%d*)%.?(%d*)", &cap); + if (cap.capture[0].len > 2 || cap.capture[1].len > 2) /* < 100? */ + lua_error("invalid format (width or precision too long)"); + strncpy(form+1, initf, strfrmt-initf+1); /* +1 to include conversion */ + form[strfrmt-initf+2] = 0; + buff = luaL_openspace(1000); /* to store the formatted value */ + switch (*strfrmt++) { + case 'q': + luaI_addquoted(luaL_check_string(arg)); + continue; + case 's': { + char *s = luaL_check_string(arg); + buff = luaL_openspace(strlen(s)); + sprintf(buff, form, s); + break; + } + case 'c': case 'd': case 'i': + sprintf(buff, form, (int)luaL_check_number(arg)); + break; + case 'o': case 'u': case 'x': case 'X': + sprintf(buff, form, (unsigned int)luaL_check_number(arg)); + break; + case 'e': case 'E': case 'f': case 'g': case 'G': + sprintf(buff, form, luaL_check_number(arg)); + break; + default: /* also treat cases 'pnLlh' */ + lua_error("invalid option in `format'"); + } + luaL_addsize(strlen(buff)); + } + } + closeandpush(); /* push the result */ +} + + +static struct luaL_reg strlib[] = { +{"strlen", str_len}, +{"strsub", str_sub}, +{"strlower", str_lower}, +{"strupper", str_upper}, +{"strchar", str_char}, +{"strrep", str_rep}, +{"ascii", str_byte}, /* for compatibility */ +{"strbyte", str_byte}, +{"format", str_format}, +{"strfind", str_find}, +{"gsub", str_gsub} +}; + + +/* +** Open string library +*/ +void strlib_open (void) +{ + luaL_openlib(strlib, (sizeof(strlib)/sizeof(strlib[0]))); +} diff --git a/src/llex.c b/src/llex.c new file mode 100644 index 0000000..ec1966c --- /dev/null +++ b/src/llex.c @@ -0,0 +1,463 @@ +/* +** $Id: llex.c,v 1.23 1998/07/06 22:04:58 roberto Exp $ +** Lexical Analizer +** See Copyright Notice in lua.h +*/ + + +#include +#include + +#include "lauxlib.h" +#include "llex.h" +#include "lmem.h" +#include "lobject.h" +#include "lparser.h" +#include "lstate.h" +#include "lstring.h" +#include "luadebug.h" +#include "lzio.h" + + + +int lua_debug=0; + + +#define next(LS) (LS->current = zgetc(LS->lex_z)) + + +#define save(c) luaL_addchar(c) +#define save_and_next(LS) (save(LS->current), next(LS)) + + +char *reserved [] = {"and", "do", "else", "elseif", "end", "function", + "if", "local", "nil", "not", "or", "repeat", "return", "then", + "until", "while"}; + + +void luaX_init (void) +{ + int i; + for (i=0; i<(sizeof(reserved)/sizeof(reserved[0])); i++) { + TaggedString *ts = luaS_new(reserved[i]); + ts->head.marked = FIRST_RESERVED+i; /* reserved word (always > 255) */ + } +} + + +void luaX_syntaxerror (LexState *ls, char *s, char *token) { + if (token[0] == 0) + token = ""; + luaL_verror("%.100s;\n last token read: `%.50s' at line %d in chunk `%.50s'", + s, token, ls->linenumber, zname(ls->lex_z)); +} + + +void luaX_error (LexState *ls, char *s) { + save(0); + luaX_syntaxerror(ls, s, luaL_buffer()); +} + + +void luaX_token2str (LexState *ls, int token, char *s) { + if (token < 255) { + s[0] = token; + s[1] = 0; + } + else + strcpy(s, reserved[token-FIRST_RESERVED]); +} + + +static void luaX_invalidchar (LexState *ls, int c) { + char buff[10]; + sprintf(buff, "0x%X", c); + luaX_syntaxerror(ls, "invalid control char", buff); +} + + +static void firstline (LexState *LS) +{ + int c = zgetc(LS->lex_z); + if (c == '#') + while ((c=zgetc(LS->lex_z)) != '\n' && c != EOZ) /* skip first line */; + zungetc(LS->lex_z); +} + + +void luaX_setinput (LexState *LS, ZIO *z) +{ + LS->current = '\n'; + LS->linenumber = 0; + LS->iflevel = 0; + LS->ifstate[0].skip = 0; + LS->ifstate[0].elsepart = 1; /* to avoid a free $else */ + LS->lex_z = z; + LS->fs = NULL; + firstline(LS); + luaL_resetbuffer(); +} + + + +/* +** ======================================================= +** PRAGMAS +** ======================================================= +*/ + +#define PRAGMASIZE 20 + +static void skipspace (LexState *LS) +{ + while (LS->current == ' ' || LS->current == '\t' || LS->current == '\r') + next(LS); +} + + +static int checkcond (LexState *LS, char *buff) +{ + static char *opts[] = {"nil", "1", NULL}; + int i = luaL_findstring(buff, opts); + if (i >= 0) return i; + else if (isalpha((unsigned char)buff[0]) || buff[0] == '_') + return luaS_globaldefined(buff); + else { + luaX_syntaxerror(LS, "invalid $if condition", buff); + return 0; /* to avoid warnings */ + } +} + + +static void readname (LexState *LS, char *buff) +{ + int i = 0; + skipspace(LS); + while (isalnum(LS->current) || LS->current == '_') { + if (i >= PRAGMASIZE) { + buff[PRAGMASIZE] = 0; + luaX_syntaxerror(LS, "pragma too long", buff); + } + buff[i++] = LS->current; + next(LS); + } + buff[i] = 0; +} + + +static void inclinenumber (LexState *LS); + + +static void ifskip (LexState *LS) +{ + while (LS->ifstate[LS->iflevel].skip) { + if (LS->current == '\n') + inclinenumber(LS); + else if (LS->current == EOZ) + luaX_error(LS, "input ends inside a $if"); + else next(LS); + } +} + + +static void inclinenumber (LexState *LS) +{ + static char *pragmas [] = + {"debug", "nodebug", "endinput", "end", "ifnot", "if", "else", NULL}; + next(LS); /* skip '\n' */ + ++LS->linenumber; + if (LS->current == '$') { /* is a pragma? */ + char buff[PRAGMASIZE+1]; + int ifnot = 0; + int skip = LS->ifstate[LS->iflevel].skip; + next(LS); /* skip $ */ + readname(LS, buff); + switch (luaL_findstring(buff, pragmas)) { + case 0: /* debug */ + if (!skip) lua_debug = 1; + break; + case 1: /* nodebug */ + if (!skip) lua_debug = 0; + break; + case 2: /* endinput */ + if (!skip) { + LS->current = EOZ; + LS->iflevel = 0; /* to allow $endinput inside a $if */ + } + break; + case 3: /* end */ + if (LS->iflevel-- == 0) + luaX_syntaxerror(LS, "unmatched $end", "$end"); + break; + case 4: /* ifnot */ + ifnot = 1; + /* go through */ + case 5: /* if */ + if (LS->iflevel == MAX_IFS-1) + luaX_syntaxerror(LS, "too many nested $ifs", "$if"); + readname(LS, buff); + LS->iflevel++; + LS->ifstate[LS->iflevel].elsepart = 0; + LS->ifstate[LS->iflevel].condition = checkcond(LS, buff) ? !ifnot : ifnot; + LS->ifstate[LS->iflevel].skip = skip || !LS->ifstate[LS->iflevel].condition; + break; + case 6: /* else */ + if (LS->ifstate[LS->iflevel].elsepart) + luaX_syntaxerror(LS, "unmatched $else", "$else"); + LS->ifstate[LS->iflevel].elsepart = 1; + LS->ifstate[LS->iflevel].skip = LS->ifstate[LS->iflevel-1].skip || + LS->ifstate[LS->iflevel].condition; + break; + default: + luaX_syntaxerror(LS, "unknown pragma", buff); + } + skipspace(LS); + if (LS->current == '\n') /* pragma must end with a '\n' ... */ + inclinenumber(LS); + else if (LS->current != EOZ) /* or eof */ + luaX_syntaxerror(LS, "invalid pragma format", buff); + ifskip(LS); + } +} + + +/* +** ======================================================= +** LEXICAL ANALIZER +** ======================================================= +*/ + + + + + +static int read_long_string (LexState *LS) +{ + int cont = 0; + while (1) { + switch (LS->current) { + case EOZ: + luaX_error(LS, "unfinished long string"); + return EOS; /* to avoid warnings */ + case '[': + save_and_next(LS); + if (LS->current == '[') { + cont++; + save_and_next(LS); + } + continue; + case ']': + save_and_next(LS); + if (LS->current == ']') { + if (cont == 0) goto endloop; + cont--; + save_and_next(LS); + } + continue; + case '\n': + save('\n'); + inclinenumber(LS); + continue; + default: + save_and_next(LS); + } + } endloop: + save_and_next(LS); /* pass the second ']' */ + LS->seminfo.ts = luaS_newlstr(L->Mbuffbase+2, + L->Mbuffnext-(L->Mbuffbase-L->Mbuffer)-4); + return STRING; +} + + +int luaX_lex (LexState *LS) { + double a; + luaL_resetbuffer(); + while (1) { + switch (LS->current) { + + case ' ': case '\t': case '\r': /* CR: to avoid problems with DOS */ + next(LS); + continue; + + case '\n': + inclinenumber(LS); + continue; + + case '-': + save_and_next(LS); + if (LS->current != '-') return '-'; + do { next(LS); } while (LS->current != '\n' && LS->current != EOZ); + luaL_resetbuffer(); + continue; + + case '[': + save_and_next(LS); + if (LS->current != '[') return '['; + else { + save_and_next(LS); /* pass the second '[' */ + return read_long_string(LS); + } + + case '=': + save_and_next(LS); + if (LS->current != '=') return '='; + else { save_and_next(LS); return EQ; } + + case '<': + save_and_next(LS); + if (LS->current != '=') return '<'; + else { save_and_next(LS); return LE; } + + case '>': + save_and_next(LS); + if (LS->current != '=') return '>'; + else { save_and_next(LS); return GE; } + + case '~': + save_and_next(LS); + if (LS->current != '=') return '~'; + else { save_and_next(LS); return NE; } + + case '"': + case '\'': { + int del = LS->current; + save_and_next(LS); + while (LS->current != del) { + switch (LS->current) { + case EOZ: + case '\n': + luaX_error(LS, "unfinished string"); + return EOS; /* to avoid warnings */ + case '\\': + next(LS); /* do not save the '\' */ + switch (LS->current) { + case 'a': save('\a'); next(LS); break; + case 'b': save('\b'); next(LS); break; + case 'f': save('\f'); next(LS); break; + case 'n': save('\n'); next(LS); break; + case 'r': save('\r'); next(LS); break; + case 't': save('\t'); next(LS); break; + case 'v': save('\v'); next(LS); break; + case '\n': save('\n'); inclinenumber(LS); break; + default : { + if (isdigit(LS->current)) { + int c = 0; + int i = 0; + do { + c = 10*c + (LS->current-'0'); + next(LS); + } while (++i<3 && isdigit(LS->current)); + if (c >= 256) + luaX_error(LS, "escape sequence too large"); + save(c); + } + else { /* handles \, ", ', and ? */ + save(LS->current); + next(LS); + } + break; + } + } + break; + default: + save_and_next(LS); + } + } + save_and_next(LS); /* skip delimiter */ + LS->seminfo.ts = luaS_newlstr(L->Mbuffbase+1, + L->Mbuffnext-(L->Mbuffbase-L->Mbuffer)-2); + return STRING; + } + + case '.': + save_and_next(LS); + if (LS->current == '.') + { + save_and_next(LS); + if (LS->current == '.') + { + save_and_next(LS); + return DOTS; /* ... */ + } + else return CONC; /* .. */ + } + else if (!isdigit(LS->current)) return '.'; + /* LS->current is a digit: goes through to number */ + a=0.0; + goto fraction; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + a=0.0; + do { + a = 10.0*a + (LS->current-'0'); + save_and_next(LS); + } while (isdigit(LS->current)); + if (LS->current == '.') { + save_and_next(LS); + if (LS->current == '.') { + save('.'); + luaX_error(LS, + "ambiguous syntax (decimal point x string concatenation)"); + } + } + fraction: + { double da=0.1; + while (isdigit(LS->current)) + { + a += (LS->current-'0')*da; + da /= 10.0; + save_and_next(LS); + } + if (toupper(LS->current) == 'E') { + int e = 0; + int neg; + double ea; + save_and_next(LS); + neg = (LS->current=='-'); + if (LS->current == '+' || LS->current == '-') save_and_next(LS); + if (!isdigit(LS->current)) + luaX_error(LS, "invalid numeral format"); + do { + e = 10*e + (LS->current-'0'); + save_and_next(LS); + } while (isdigit(LS->current)); + for (ea=neg?0.1:10.0; e>0; e>>=1) + { + if (e & 1) a *= ea; + ea *= ea; + } + } + LS->seminfo.r = a; + return NUMBER; + } + + case EOZ: + if (LS->iflevel > 0) + luaX_error(LS, "input ends inside a $if"); + return EOS; + + default: + if (LS->current != '_' && !isalpha(LS->current)) { + int c = LS->current; + if (iscntrl(c)) + luaX_invalidchar(LS, c); + save_and_next(LS); + return c; + } + else { /* identifier or reserved word */ + TaggedString *ts; + do { + save_and_next(LS); + } while (isalnum(LS->current) || LS->current == '_'); + save(0); + ts = luaS_new(L->Mbuffbase); + if (ts->head.marked >= 'A') + return ts->head.marked; /* reserved word */ + LS->seminfo.ts = ts; + return NAME; + } + } + } +} + diff --git a/src/llex.h b/src/llex.h new file mode 100644 index 0000000..ba8c52a --- /dev/null +++ b/src/llex.h @@ -0,0 +1,62 @@ +/* +** $Id: llex.h,v 1.9 1998/06/19 16:14:09 roberto Exp $ +** Lexical Analizer +** See Copyright Notice in lua.h +*/ + +#ifndef llex_h +#define llex_h + +#include "lobject.h" +#include "lzio.h" + + +#define FIRST_RESERVED 260 + +/* maximum length of a reserved word (+1 for terminal 0) */ +#define TOKEN_LEN 15 + +enum RESERVED { + /* terminal symbols denoted by reserved words */ + AND = FIRST_RESERVED, + DO, ELSE, ELSEIF, END, FUNCTION, IF, LOCAL, NIL, NOT, OR, + REPEAT, RETURN, THEN, UNTIL, WHILE, + /* other terminal symbols */ + NAME, CONC, DOTS, EQ, GE, LE, NE, NUMBER, STRING, EOS}; + + +#define MAX_IFS 5 + +/* "ifstate" keeps the state of each nested $if the lexical is dealing with. */ + +struct ifState { + int elsepart; /* true if its in the $else part */ + int condition; /* true if $if condition is true */ + int skip; /* true if part must be skipped */ +}; + + +typedef struct LexState { + int current; /* look ahead character */ + int token; /* look ahead token */ + struct FuncState *fs; /* 'FuncState' is private for the parser */ + union { + real r; + TaggedString *ts; + } seminfo; /* semantics information */ + struct zio *lex_z; /* input stream */ + int linenumber; /* input line counter */ + int iflevel; /* level of nested $if's (for lexical analysis) */ + struct ifState ifstate[MAX_IFS]; +} LexState; + + +void luaX_init (void); +void luaX_setinput (LexState *LS, ZIO *z); +int luaX_lex (LexState *LS); +void luaX_syntaxerror (LexState *ls, char *s, char *token); +void luaX_error (LexState *ls, char *s); +void luaX_token2str (LexState *ls, int token, char *s); + + +#endif diff --git a/src/lmem.c b/src/lmem.c new file mode 100644 index 0000000..bcb3c8e --- /dev/null +++ b/src/lmem.c @@ -0,0 +1,113 @@ +/* +** $Id: lmem.c,v 1.7 1998/06/29 22:03:06 roberto Exp $ +** Interface to Memory Manager +** See Copyright Notice in lua.h +*/ + + +#include + +#include "lmem.h" +#include "lstate.h" +#include "lua.h" + + + +int luaM_growaux (void **block, unsigned long nelems, int size, + char *errormsg, unsigned long limit) +{ + if (nelems >= limit) + lua_error(errormsg); + nelems = (nelems == 0) ? 32 : nelems*2; + if (nelems > limit) + nelems = limit; + *block = luaM_realloc(*block, nelems*size); + return (int)nelems; +} + + + +#ifndef DEBUG + +/* +** generic allocation routine. +** real ANSI systems do not need some of these tests, +** since realloc(NULL, s)==malloc(s) and realloc(b, 0)==free(b). +** But some systems (e.g. Sun OS) are not that ANSI... +*/ +void *luaM_realloc (void *block, unsigned long size) +{ + size_t s = (size_t)size; + if (s != size) + lua_error("Allocation Error: Block too big"); + if (size == 0) { + if (block) { + free(block); + } + return NULL; + } + block = block ? realloc(block, s) : malloc(s); + if (block == NULL) + lua_error(memEM); + return block; +} + + + +#else +/* DEBUG */ + +#include + + +#define HEADER (sizeof(double)) + +#define MARK 55 + +unsigned long numblocks = 0; +unsigned long totalmem = 0; + + +static void *checkblock (void *block) +{ + unsigned long *b = (unsigned long *)((char *)block - HEADER); + unsigned long size = *b; + LUA_ASSERT(*(((char *)b)+size+HEADER) == MARK, + "corrupted block"); + numblocks--; + totalmem -= size; + return b; +} + + +void *luaM_realloc (void *block, unsigned long size) +{ + unsigned long realsize = HEADER+size+1; + if (realsize != (size_t)realsize) + lua_error("Allocation Error: Block too big"); + if (size == 0) { /* ANSI dosen't need this, but some machines... */ + if (block) { + unsigned long *b = (unsigned long *)((char *)block - HEADER); + memset(block, -1, *b); /* erase block */ + block = checkblock(block); + free(block); + } + return NULL; + } + if (block) { + block = checkblock(block); + block = (unsigned long *)realloc(block, realsize); + } + else + block = (unsigned long *)malloc(realsize); + if (block == NULL) + lua_error(memEM); + totalmem += size; + numblocks++; + *(unsigned long *)block = size; + *(((char *)block)+size+HEADER) = MARK; + return (unsigned long *)((char *)block+HEADER); +} + + +#endif diff --git a/src/lmem.h b/src/lmem.h new file mode 100644 index 0000000..3c63a53 --- /dev/null +++ b/src/lmem.h @@ -0,0 +1,43 @@ +/* +** $Id: lmem.h,v 1.5 1997/12/17 20:48:58 roberto Exp $ +** Interface to Memory Manager +** See Copyright Notice in lua.h +*/ + +#ifndef lmem_h +#define lmem_h + + +#ifndef NULL +#define NULL 0 +#endif + + +/* memory error messages */ +#define codeEM "code size overflow" +#define constantEM "constant table overflow" +#define refEM "reference table overflow" +#define tableEM "table overflow" +#define memEM "not enough memory" + +void *luaM_realloc (void *oldblock, unsigned long size); +int luaM_growaux (void **block, unsigned long nelems, int size, + char *errormsg, unsigned long limit); + +#define luaM_free(b) luaM_realloc((b), 0) +#define luaM_malloc(t) luaM_realloc(NULL, (t)) +#define luaM_new(t) ((t *)luaM_malloc(sizeof(t))) +#define luaM_newvector(n,t) ((t *)luaM_malloc((n)*sizeof(t))) +#define luaM_growvector(old,n,t,e,l) \ + (luaM_growaux((void**)old,n,sizeof(t),e,l)) +#define luaM_reallocvector(v,n,t) ((t *)luaM_realloc(v,(n)*sizeof(t))) + + +#ifdef DEBUG +extern unsigned long numblocks; +extern unsigned long totalmem; +#endif + + +#endif + diff --git a/src/lobject.c b/src/lobject.c new file mode 100644 index 0000000..8d331ef --- /dev/null +++ b/src/lobject.c @@ -0,0 +1,83 @@ +/* +** $Id: lobject.c,v 1.13 1998/06/19 16:14:09 roberto Exp $ +** Some generic functions over Lua objects +** See Copyright Notice in lua.h +*/ + +#include + +#include "lobject.h" +#include "lua.h" + + +char *luaO_typenames[] = { /* ORDER LUA_T */ + "userdata", "number", "string", "table", "function", "function", + "nil", "function", "mark", "mark", "mark", "line", NULL +}; + + +TObject luaO_nilobject = {LUA_T_NIL, {NULL}}; + + + +/* hash dimensions values */ +static long dimensions[] = + {5L, 11L, 23L, 47L, 97L, 197L, 397L, 797L, 1597L, 3203L, 6421L, + 12853L, 25717L, 51437L, 102811L, 205619L, 411233L, 822433L, + 1644817L, 3289613L, 6579211L, 13158023L, MAX_INT}; + + +int luaO_redimension (int oldsize) +{ + int i; + for (i=0; dimensions[i] oldsize) + return dimensions[i]; + } + lua_error("table overflow"); + return 0; /* to avoid warnings */ +} + + +int luaO_equalObj (TObject *t1, TObject *t2) +{ + if (ttype(t1) != ttype(t2)) return 0; + switch (ttype(t1)) { + case LUA_T_NIL: return 1; + case LUA_T_NUMBER: return nvalue(t1) == nvalue(t2); + case LUA_T_STRING: case LUA_T_USERDATA: return svalue(t1) == svalue(t2); + case LUA_T_ARRAY: return avalue(t1) == avalue(t2); + case LUA_T_PROTO: return tfvalue(t1) == tfvalue(t2); + case LUA_T_CPROTO: return fvalue(t1) == fvalue(t2); + case LUA_T_CLOSURE: return t1->value.cl == t2->value.cl; + default: + LUA_INTERNALERROR("invalid type"); + return 0; /* UNREACHABLE */ + } +} + + +void luaO_insertlist (GCnode *root, GCnode *node) +{ + node->next = root->next; + root->next = node; + node->marked = 0; +} + +#ifdef OLD_ANSI +void luaO_memup (void *dest, void *src, int size) +{ + char *d = dest; + char *s = src; + while (size--) d[size]=s[size]; +} + +void luaO_memdown (void *dest, void *src, int size) +{ + char *d = dest; + char *s = src; + int i; + for (i=0; i + +#include "lua.h" + + +#ifdef DEBUG +#include "lauxlib.h" +#define LUA_INTERNALERROR(s) \ + luaL_verror("INTERNAL ERROR - %s [%s:%d]",(s),__FILE__,__LINE__) +#define LUA_ASSERT(c,s) { if (!(c)) LUA_INTERNALERROR(s); } +#else +#define LUA_INTERNALERROR(s) /* empty */ +#define LUA_ASSERT(c,s) /* empty */ +#endif + + +/* +** "real" is the type "number" of Lua +** GREP LUA_NUMBER to change that +*/ +#ifndef LUA_NUM_TYPE +#define LUA_NUM_TYPE double +#endif + +/* +** format to convert number to strings +*/ +#define NUMBER_FMT "%g" + +typedef LUA_NUM_TYPE real; + +#define Byte lua_Byte /* some systems have Byte as a predefined type */ +typedef unsigned char Byte; /* unsigned 8 bits */ + + +#define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */ + +/* maximum value of a word of 2 bytes (-2 for safety); must fit in an "int" */ +#if MAX_INT < 65534 +#define MAX_WORD MAX_INT +#else +#define MAX_WORD 65534 +#endif + +typedef unsigned int IntPoint; /* unsigned with same size as a pointer (for hashing) */ + + +/* +** Lua TYPES +** WARNING: if you change the order of this enumeration, +** grep "ORDER LUA_T" +*/ +typedef enum { + LUA_T_USERDATA = 0, /* tag default for userdata */ + LUA_T_NUMBER = -1, /* fixed tag for numbers */ + LUA_T_STRING = -2, /* fixed tag for strings */ + LUA_T_ARRAY = -3, /* tag default for tables (or arrays) */ + LUA_T_PROTO = -4, /* fixed tag for functions */ + LUA_T_CPROTO = -5, /* fixed tag for Cfunctions */ + LUA_T_NIL = -6, /* last "pre-defined" tag */ + LUA_T_CLOSURE = -7, + LUA_T_CLMARK = -8, /* mark for closures */ + LUA_T_PMARK = -9, /* mark for Lua prototypes */ + LUA_T_CMARK = -10, /* mark for C prototypes */ + LUA_T_LINE = -11 +} lua_Type; + +#define NUM_TYPES 11 +#define NUM_TAGS 7 + + +typedef union { + lua_CFunction f; /* LUA_T_CPROTO, LUA_T_CMARK */ + real n; /* LUA_T_NUMBER */ + struct TaggedString *ts; /* LUA_T_STRING, LUA_T_USERDATA */ + struct TProtoFunc *tf; /* LUA_T_PROTO, LUA_T_PMARK */ + struct Closure *cl; /* LUA_T_CLOSURE, LUA_T_CLMARK */ + struct Hash *a; /* LUA_T_ARRAY */ + int i; /* LUA_T_LINE */ +} Value; + + +typedef struct TObject { + lua_Type ttype; + Value value; +} TObject; + + + +/* +** generic header for garbage collector lists +*/ +typedef struct GCnode { + struct GCnode *next; + int marked; +} GCnode; + + +/* +** String headers for string table +*/ + +typedef struct TaggedString { + GCnode head; + unsigned long hash; + int constindex; /* hint to reuse constants (= -1 if this is a userdata) */ + union { + struct { + TObject globalval; + long len; /* if this is a string, here is its length */ + } s; + struct { + int tag; + void *v; /* if this is a userdata, here is its value */ + } d; + } u; + char str[1]; /* \0 byte already reserved */ +} TaggedString; + + + + +/* +** Function Prototypes +*/ +typedef struct TProtoFunc { + GCnode head; + struct TObject *consts; + int nconsts; + Byte *code; /* ends with opcode ENDCODE */ + int lineDefined; + TaggedString *fileName; + struct LocVar *locvars; /* ends with line = -1 */ +} TProtoFunc; + +typedef struct LocVar { + TaggedString *varname; /* NULL signals end of scope */ + int line; +} LocVar; + + + + + +/* Macros to access structure members */ +#define ttype(o) ((o)->ttype) +#define nvalue(o) ((o)->value.n) +#define svalue(o) ((o)->value.ts->str) +#define tsvalue(o) ((o)->value.ts) +#define clvalue(o) ((o)->value.cl) +#define avalue(o) ((o)->value.a) +#define fvalue(o) ((o)->value.f) +#define tfvalue(o) ((o)->value.tf) + +#define protovalue(o) ((o)->value.cl->consts) + + +/* +** Closures +*/ +typedef struct Closure { + GCnode head; + int nelems; /* not included the first one (always the prototype) */ + TObject consts[1]; /* at least one for prototype */ +} Closure; + + + +typedef struct node { + TObject ref; + TObject val; +} Node; + +typedef struct Hash { + GCnode head; + Node *node; + int nhash; + int nuse; + int htag; +} Hash; + + +extern char *luaO_typenames[]; + +extern TObject luaO_nilobject; + +int luaO_equalObj (TObject *t1, TObject *t2); +int luaO_redimension (int oldsize); +void luaO_insertlist (GCnode *root, GCnode *node); + +#ifdef OLD_ANSI +void luaO_memup (void *dest, void *src, int size); +void luaO_memdown (void *dest, void *src, int size); +#else +#include +#define luaO_memup(d,s,n) memmove(d,s,n) +#define luaO_memdown(d,s,n) memmove(d,s,n) +#endif + +#endif diff --git a/src/lopcodes.h b/src/lopcodes.h new file mode 100644 index 0000000..27dded4 --- /dev/null +++ b/src/lopcodes.h @@ -0,0 +1,181 @@ +/* +** $Id: lopcodes.h,v 1.18 1998/06/25 14:37:00 roberto Exp $ +** Opcodes for Lua virtual machine +** See Copyright Notice in lua.h +*/ + +#ifndef lopcodes_h +#define lopcodes_h + + +/* +** NOTICE: variants of the same opcode must be consecutive: First, those +** with byte parameter, then with built-in parameters, and last with +** word parameter. +*/ + + +typedef enum { +/* name parm before after side effect +-----------------------------------------------------------------------------*/ +ENDCODE,/* - - - */ + +PUSHNIL,/* b - nil_0...nil_b */ +PUSHNIL0,/* - - nil */ + +PUSHNUMBER,/* b - (float)b */ +PUSHNUMBER0,/* - - 0.0 */ +PUSHNUMBER1,/* - - 1.0 */ +PUSHNUMBER2,/* - - 2.0 */ +PUSHNUMBERW,/* w - (float)w */ + +PUSHCONSTANT,/* b - CNST[b] */ +PUSHCONSTANT0,/*- - CNST[0] */ +PUSHCONSTANT1,/*- - CNST[1] */ +PUSHCONSTANT2,/*- - CNST[2] */ +PUSHCONSTANT3,/*- - CNST[3] */ +PUSHCONSTANT4,/*- - CNST[4] */ +PUSHCONSTANT5,/*- - CNST[5] */ +PUSHCONSTANT6,/*- - CNST[6] */ +PUSHCONSTANT7,/*- - CNST[7] */ +PUSHCONSTANTW,/*w - CNST[w] */ + +PUSHUPVALUE,/* b - Closure[b] */ +PUSHUPVALUE0,/* - - Closure[0] */ +PUSHUPVALUE1,/* - - Closure[1] */ + +PUSHLOCAL,/* b - LOC[b] */ +PUSHLOCAL0,/* - - LOC[0] */ +PUSHLOCAL1,/* - - LOC[1] */ +PUSHLOCAL2,/* - - LOC[2] */ +PUSHLOCAL3,/* - - LOC[3] */ +PUSHLOCAL4,/* - - LOC[4] */ +PUSHLOCAL5,/* - - LOC[5] */ +PUSHLOCAL6,/* - - LOC[6] */ +PUSHLOCAL7,/* - - LOC[7] */ + +GETGLOBAL,/* b - VAR[CNST[b]] */ +GETGLOBAL0,/* - - VAR[CNST[0]] */ +GETGLOBAL1,/* - - VAR[CNST[1]] */ +GETGLOBAL2,/* - - VAR[CNST[2]] */ +GETGLOBAL3,/* - - VAR[CNST[3]] */ +GETGLOBAL4,/* - - VAR[CNST[4]] */ +GETGLOBAL5,/* - - VAR[CNST[5]] */ +GETGLOBAL6,/* - - VAR[CNST[6]] */ +GETGLOBAL7,/* - - VAR[CNST[7]] */ +GETGLOBALW,/* w - VAR[CNST[w]] */ + +GETTABLE,/* - i t t[i] */ + +GETDOTTED,/* b t t[CNST[b]] */ +GETDOTTED0,/* - t t[CNST[0]] */ +GETDOTTED1,/* - t t[CNST[1]] */ +GETDOTTED2,/* - t t[CNST[2]] */ +GETDOTTED3,/* - t t[CNST[3]] */ +GETDOTTED4,/* - t t[CNST[4]] */ +GETDOTTED5,/* - t t[CNST[5]] */ +GETDOTTED6,/* - t t[CNST[6]] */ +GETDOTTED7,/* - t t[CNST[7]] */ +GETDOTTEDW,/* w t t[CNST[w]] */ + +PUSHSELF,/* b t t t[CNST[b]] */ +PUSHSELF0,/* - t t t[CNST[0]] */ +PUSHSELF1,/* - t t t[CNST[1]] */ +PUSHSELF2,/* - t t t[CNST[2]] */ +PUSHSELF3,/* - t t t[CNST[3]] */ +PUSHSELF4,/* - t t t[CNST[4]] */ +PUSHSELF5,/* - t t t[CNST[5]] */ +PUSHSELF6,/* - t t t[CNST[6]] */ +PUSHSELF7,/* - t t t[CNST[7]] */ +PUSHSELFW,/* w t t t[CNST[w]] */ + +CREATEARRAY,/* b - newarray(size = b) */ +CREATEARRAY0,/* - - newarray(size = 0) */ +CREATEARRAY1,/* - - newarray(size = 1) */ +CREATEARRAYW,/* w - newarray(size = w) */ + +SETLOCAL,/* b x - LOC[b]=x */ +SETLOCAL0,/* - x - LOC[0]=x */ +SETLOCAL1,/* - x - LOC[1]=x */ +SETLOCAL2,/* - x - LOC[2]=x */ +SETLOCAL3,/* - x - LOC[3]=x */ +SETLOCAL4,/* - x - LOC[4]=x */ +SETLOCAL5,/* - x - LOC[5]=x */ +SETLOCAL6,/* - x - LOC[6]=x */ +SETLOCAL7,/* - x - LOC[7]=x */ + +SETGLOBAL,/* b x - VAR[CNST[b]]=x */ +SETGLOBAL0,/* - x - VAR[CNST[0]]=x */ +SETGLOBAL1,/* - x - VAR[CNST[1]]=x */ +SETGLOBAL2,/* - x - VAR[CNST[2]]=x */ +SETGLOBAL3,/* - x - VAR[CNST[3]]=x */ +SETGLOBAL4,/* - x - VAR[CNST[4]]=x */ +SETGLOBAL5,/* - x - VAR[CNST[5]]=x */ +SETGLOBAL6,/* - x - VAR[CNST[6]]=x */ +SETGLOBAL7,/* - x - VAR[CNST[7]]=x */ +SETGLOBALW,/* w x - VAR[CNST[w]]=x */ + +SETTABLE0,/* - v i t - t[i]=v */ + +SETTABLE,/* b v a_b...a_1 i t a_b...a_1 i t t[i]=v */ + +SETLIST,/* b c v_c...v_1 t - t[i+b*FPF]=v_i */ +SETLIST0,/* b v_b...v_1 t - t[i]=v_i */ +SETLISTW,/* w c v_c...v_1 t - t[i+w*FPF]=v_i */ + +SETMAP,/* b v_b k_b ...v_0 k_0 t t t[k_i]=v_i */ +SETMAP0,/* - v_0 k_0 t t t[k_0]=v_0 */ + +EQOP,/* - y x (x==y)? 1 : nil */ +NEQOP,/* - y x (x~=y)? 1 : nil */ +LTOP,/* - y x (xy)? 1 : nil */ +GEOP,/* - y x (x>=y)? 1 : nil */ +ADDOP,/* - y x x+y */ +SUBOP,/* - y x x-y */ +MULTOP,/* - y x x*y */ +DIVOP,/* - y x x/y */ +POWOP,/* - y x x^y */ +CONCOP,/* - y x x..y */ +MINUSOP,/* - x -x */ +NOTOP,/* - x (x==nil)? 1 : nil */ + +ONTJMP,/* b x (x!=nil)? x : - (x!=nil)? PC+=b */ +ONTJMPW,/* w x (x!=nil)? x : - (x!=nil)? PC+=w */ +ONFJMP,/* b x (x==nil)? x : - (x==nil)? PC+=b */ +ONFJMPW,/* w x (x==nil)? x : - (x==nil)? PC+=w */ +JMP,/* b - - PC+=b */ +JMPW,/* w - - PC+=w */ +IFFJMP,/* b x - (x==nil)? PC+=b */ +IFFJMPW,/* w x - (x==nil)? PC+=w */ +IFTUPJMP,/* b x - (x!=nil)? PC-=b */ +IFTUPJMPW,/* w x - (x!=nil)? PC-=w */ +IFFUPJMP,/* b x - (x==nil)? PC-=b */ +IFFUPJMPW,/* w x - (x==nil)? PC-=w */ + +CLOSURE,/* b c v_c...v_1 closure(CNST[b], v_c...v_1) */ +CLOSUREW,/* w c v_b...v_1 closure(CNST[w], v_c...v_1) */ + +CALLFUNC,/* b c v_c...v_1 f r_b...r_1 f(v1,...,v_c) */ +CALLFUNC0,/* b v_b...v_1 f - f(v1,...,v_b) */ +CALLFUNC1,/* b v_b...v_1 f r_1 f(v1,...,v_b) */ + +RETCODE,/* b - - */ + +SETLINE,/* b - - LINE=b */ +SETLINEW,/* w - - LINE=w */ + +POP,/* b - - TOP-=(b+1) */ +POP0,/* - - - TOP-=1 */ +POP1/* - - - TOP-=2 */ + +} OpCode; + + +#define RFIELDS_PER_FLUSH 32 /* records (SETMAP) */ +#define LFIELDS_PER_FLUSH 64 /* lists (SETLIST) */ + +#define ZEROVARARG 64 + +#endif diff --git a/src/lparser.c b/src/lparser.c new file mode 100644 index 0000000..9b37d9d --- /dev/null +++ b/src/lparser.c @@ -0,0 +1,1333 @@ +/* +** $Id: lparser.c,v 1.3 1998/07/06 22:07:51 roberto Exp $ +** LL(1) Parser and code generator for Lua +** See Copyright Notice in lua.h +*/ + + +#include + +#include "lauxlib.h" +#include "ldo.h" +#include "lfunc.h" +#include "llex.h" +#include "lmem.h" +#include "lopcodes.h" +#include "lparser.h" +#include "lstate.h" +#include "lstring.h" +#include "lua.h" +#include "luadebug.h" +#include "lzio.h" + + +/* for limit numbers in error messages */ +#define MES_LIM(x) "(limit=" x ")" + + +/* size of a "normal" jump instruction: OpCode + 1 byte */ +#define JMPSIZE 2 + +/* maximum number of local variables */ +#define MAXLOCALS 32 +#define SMAXLOCALS "32" + + +/* maximum number of upvalues */ +#define MAXUPVALUES 16 +#define SMAXUPVALUES "16" + + +/* +** Variable descriptor: +** must include a "exp" option because LL(1) cannot distinguish +** between variables, upvalues and function calls on first sight. +** VGLOBAL: info is constant index of global name +** VLOCAL: info is stack index +** VDOT: info is constant index of index name +** VEXP: info is pc index of "nparam" of function call (or 0 if exp is closed) +*/ +typedef enum {VGLOBAL, VLOCAL, VDOT, VINDEXED, VEXP} varkind; + +typedef struct { + varkind k; + int info; +} vardesc; + + +/* +** Expression List descriptor: +** tells number of expressions in the list, +** and, if last expression is open (a function call), +** where is its pc index of "nparam" +*/ +typedef struct { + int n; + int pc; /* 0 if last expression is closed */ +} listdesc; + + +/* +** Constructors descriptor: +** "n" indicates number of elements, and "k" signals whether +** it is a list constructor (k = 0) or a record constructor (k = 1) +** or empty (k = ';' or '}') +*/ +typedef struct { + int n; + int k; +} constdesc; + + +/* state needed to generate code for a given function */ +typedef struct FuncState { + TProtoFunc *f; /* current function header */ + struct FuncState *prev; /* enclosuring function */ + int pc; /* next position to code */ + int stacksize; /* number of values on activation register */ + int maxstacksize; /* maximum number of values on activation register */ + int nlocalvar; /* number of active local variables */ + int nupvalues; /* number of upvalues */ + int nvars; /* number of entries in f->locvars */ + int maxcode; /* size of f->code */ + int maxvars; /* size of f->locvars (-1 if no debug information) */ + int maxconsts; /* size of f->consts */ + int lastsetline; /* line where last SETLINE was issued */ + vardesc upvalues[MAXUPVALUES]; /* upvalues */ + TaggedString *localvar[MAXLOCALS]; /* store local variable names */ +} FuncState; + + +static int assignment (LexState *ls, vardesc *v, int nvars); +static int cond (LexState *ls); +static int funcname (LexState *ls, vardesc *v); +static int funcparams (LexState *ls, int slf); +static int listfields (LexState *ls); +static int localnamelist (LexState *ls); +static int optional (LexState *ls, int c); +static int recfields (LexState *ls); +static int stat (LexState *ls); +static void block (LexState *ls); +static void body (LexState *ls, int needself, int line); +static void chunk (LexState *ls); +static void constructor (LexState *ls); +static void decinit (LexState *ls, listdesc *d); +static void exp0 (LexState *ls, vardesc *v); +static void exp1 (LexState *ls); +static void exp2 (LexState *ls, vardesc *v); +static void explist (LexState *ls, listdesc *e); +static void explist1 (LexState *ls, listdesc *e); +static void ifpart (LexState *ls); +static void parlist (LexState *ls); +static void part (LexState *ls, constdesc *cd); +static void recfield (LexState *ls); +static void ret (LexState *ls); +static void simpleexp (LexState *ls, vardesc *v); +static void statlist (LexState *ls); +static void var_or_func (LexState *ls, vardesc *v); +static void var_or_func_tail (LexState *ls, vardesc *v); + + + +static void check_pc (FuncState *fs, int n) { + if (fs->pc+n > fs->maxcode) + fs->maxcode = luaM_growvector(&fs->f->code, fs->maxcode, + Byte, codeEM, MAX_INT); +} + + +static void code_byte (FuncState *fs, Byte c) { + check_pc(fs, 1); + fs->f->code[fs->pc++] = c; +} + + +static void deltastack (LexState *ls, int delta) { + FuncState *fs = ls->fs; + fs->stacksize += delta; + if (fs->stacksize > fs->maxstacksize) { + if (fs->stacksize > 255) + luaX_error(ls, "function/expression too complex"); + fs->maxstacksize = fs->stacksize; + } +} + + +static int code_oparg_at (LexState *ls, int pc, OpCode op, int builtin, + int arg, int delta) { + Byte *code = ls->fs->f->code; + deltastack(ls, delta); + if (arg < builtin) { + code[pc] = op+1+arg; + return 1; + } + else if (arg <= 255) { + code[pc] = op; + code[pc+1] = arg; + return 2; + } + else if (arg <= MAX_WORD) { + code[pc] = op+1+builtin; + code[pc+1] = arg>>8; + code[pc+2] = arg&0xFF; + return 3; + } + else luaX_error(ls, "code too long " MES_LIM("64K")); + return 0; /* to avoid warnings */ +} + + +static int fix_opcode (LexState *ls, int pc, OpCode op, int builtin, int arg) { + FuncState *fs = ls->fs; + TProtoFunc *f = fs->f; + if (arg < builtin) { /* close space */ + luaO_memdown(f->code+pc+1, f->code+pc+2, fs->pc-(pc+2)); + fs->pc--; + } + else if (arg > 255) { /* open space */ + check_pc(fs, 1); + luaO_memup(f->code+pc+1, f->code+pc, fs->pc-pc); + fs->pc++; + } + return code_oparg_at(ls, pc, op, builtin, arg, 0) - 2; +} + +static void code_oparg (LexState *ls, OpCode op, int builtin, int arg, + int delta) { + check_pc(ls->fs, 3); /* maximum code size */ + ls->fs->pc += code_oparg_at(ls, ls->fs->pc, op, builtin, arg, delta); +} + + +static void code_opcode (LexState *ls, OpCode op, int delta) { + deltastack(ls, delta); + code_byte(ls->fs, op); +} + + +static void code_constant (LexState *ls, int c) { + code_oparg(ls, PUSHCONSTANT, 8, c, 1); +} + + +static int next_constant (FuncState *fs) { + TProtoFunc *f = fs->f; + if (f->nconsts >= fs->maxconsts) { + fs->maxconsts = luaM_growvector(&f->consts, fs->maxconsts, TObject, + constantEM, MAX_WORD); + } + return f->nconsts++; +} + + +static int string_constant (FuncState *fs, TaggedString *s) { + TProtoFunc *f = fs->f; + int c = s->constindex; + if (!(c < f->nconsts && + ttype(&f->consts[c]) == LUA_T_STRING && tsvalue(&f->consts[c]) == s)) { + c = next_constant(fs); + ttype(&f->consts[c]) = LUA_T_STRING; + tsvalue(&f->consts[c]) = s; + s->constindex = c; /* hint for next time */ + } + return c; +} + + +static void code_string (LexState *ls, TaggedString *s) { + code_constant(ls, string_constant(ls->fs, s)); +} + + +#define LIM 20 +static int real_constant (FuncState *fs, real r) { + /* check whether 'r' has appeared within the last LIM entries */ + TObject *cnt = fs->f->consts; + int c = fs->f->nconsts; + int lim = c < LIM ? 0 : c-LIM; + while (--c >= lim) { + if (ttype(&cnt[c]) == LUA_T_NUMBER && nvalue(&cnt[c]) == r) + return c; + } + /* not found; create a luaM_new entry */ + c = next_constant(fs); + cnt = fs->f->consts; /* 'next_constant' may reallocate this vector */ + ttype(&cnt[c]) = LUA_T_NUMBER; + nvalue(&cnt[c]) = r; + return c; +} + + +static void code_number (LexState *ls, real f) { + int i; + if (f >= 0 && f <= (real)MAX_WORD && (real)(i=(int)f) == f) + code_oparg(ls, PUSHNUMBER, 3, i, 1); /* f has a short integer value */ + else + code_constant(ls, real_constant(ls->fs, f)); +} + + +static void flush_record (LexState *ls, int n) { + if (n > 0) + code_oparg(ls, SETMAP, 1, n-1, -2*n); +} + + +static void flush_list (LexState *ls, int m, int n) { + if (n == 0) return; + code_oparg(ls, SETLIST, 1, m, -n); + code_byte(ls->fs, n); +} + + +static void luaI_registerlocalvar (FuncState *fs, TaggedString *varname, + int line) { + if (fs->maxvars != -1) { /* debug information? */ + TProtoFunc *f = fs->f; + if (fs->nvars >= fs->maxvars) + fs->maxvars = luaM_growvector(&f->locvars, fs->maxvars, + LocVar, "", MAX_WORD); + f->locvars[fs->nvars].varname = varname; + f->locvars[fs->nvars].line = line; + fs->nvars++; + } +} + + +static void luaI_unregisterlocalvar (FuncState *fs, int line) { + luaI_registerlocalvar(fs, NULL, line); +} + + +static void store_localvar (LexState *ls, TaggedString *name, int n) { + FuncState *fs = ls->fs; + if (fs->nlocalvar+n < MAXLOCALS) + fs->localvar[fs->nlocalvar+n] = name; + else + luaX_error(ls, "too many local variables " MES_LIM(SMAXLOCALS)); + luaI_registerlocalvar(fs, name, ls->linenumber); +} + + +static void add_localvar (LexState *ls, TaggedString *name) { + store_localvar(ls, name, 0); + ls->fs->nlocalvar++; +} + + +static int aux_localname (FuncState *fs, TaggedString *n) { + int i; + for (i=fs->nlocalvar-1; i >= 0; i--) + if (n == fs->localvar[i]) return i; /* local var index */ + return -1; /* not found */ +} + + +static void singlevar (LexState *ls, TaggedString *n, vardesc *var, int prev) { + FuncState *fs = prev ? ls->fs->prev : ls->fs; + int i = aux_localname(fs, n); + if (i >= 0) { /* local value */ + var->k = VLOCAL; + var->info = i; + } + else { /* check shadowing */ + FuncState *level = fs; + while ((level = level->prev) != NULL) + if (aux_localname(level, n) >= 0) + luaX_syntaxerror(ls, "cannot access a variable in outer scope", n->str); + var->k = VGLOBAL; + var->info = string_constant(fs, n); + } +} + + +static int indexupvalue (LexState *ls, TaggedString *n) { + FuncState *fs = ls->fs; + vardesc v; + int i; + singlevar(ls, n, &v, 1); + for (i=0; inupvalues; i++) { + if (fs->upvalues[i].k == v.k && fs->upvalues[i].info == v.info) + return i; + } + /* new one */ + if (++(fs->nupvalues) > MAXUPVALUES) + luaX_error(ls, "too many upvalues in a single function " + MES_LIM(SMAXUPVALUES)); + fs->upvalues[i] = v; /* i = fs->nupvalues - 1 */ + return i; +} + + +static void pushupvalue (LexState *ls, TaggedString *n) { + int i; + if (ls->fs->prev == NULL) + luaX_syntaxerror(ls, "cannot access upvalue in main", n->str); + if (aux_localname(ls->fs, n) >= 0) + luaX_syntaxerror(ls, "cannot access an upvalue in current scope", n->str); + i = indexupvalue(ls, n); + code_oparg(ls, PUSHUPVALUE, 2, i, 1); +} + + + +static void check_debugline (LexState *ls) { + if (lua_debug && ls->linenumber != ls->fs->lastsetline) { + code_oparg(ls, SETLINE, 0, ls->linenumber, 0); + ls->fs->lastsetline = ls->linenumber; + } +} + + +static void adjuststack (LexState *ls, int n) { + if (n > 0) + code_oparg(ls, POP, 2, n-1, -n); + else if (n < 0) + code_oparg(ls, PUSHNIL, 1, (-n)-1, -n); +} + + +static void close_exp (LexState *ls, int pc, int nresults) { + if (pc > 0) { /* expression is an open function call */ + Byte *code = ls->fs->f->code; + int nparams = code[pc]; /* save nparams */ + pc += fix_opcode(ls, pc-2, CALLFUNC, 2, nresults); + code[pc] = nparams; /* restore nparams */ + if (nresults != MULT_RET) + deltastack(ls, nresults); /* "push" results */ + deltastack(ls, -(nparams+1)); /* "pop" params and function */ + } +} + + +static void adjust_mult_assign (LexState *ls, int nvars, listdesc *d) { + int diff = d->n - nvars; + if (d->pc == 0) { /* list is closed */ + /* push or pop eventual difference between list lengths */ + adjuststack(ls, diff); + } + else { /* must correct function call */ + diff--; /* do not count function call itself */ + if (diff < 0) { /* more variables than values */ + /* function call must provide extra values */ + close_exp(ls, d->pc, -diff); + } + else { /* more values than variables */ + close_exp(ls, d->pc, 0); /* call should provide no value */ + adjuststack(ls, diff); /* pop eventual extra values */ + } + } +} + + +static void code_args (LexState *ls, int nparams, int dots) { + FuncState *fs = ls->fs; + fs->nlocalvar += nparams; /* "self" may already be there */ + nparams = fs->nlocalvar; + if (!dots) { + fs->f->code[1] = nparams; /* fill-in arg information */ + deltastack(ls, nparams); + } + else { + fs->f->code[1] = nparams+ZEROVARARG; + deltastack(ls, nparams+1); + add_localvar(ls, luaS_new("arg")); + } +} + + +static void lua_pushvar (LexState *ls, vardesc *var) { + switch (var->k) { + case VLOCAL: + code_oparg(ls, PUSHLOCAL, 8, var->info, 1); + break; + case VGLOBAL: + code_oparg(ls, GETGLOBAL, 8, var->info, 1); + break; + case VDOT: + code_oparg(ls, GETDOTTED, 8, var->info, 0); + break; + case VINDEXED: + code_opcode(ls, GETTABLE, -1); + break; + case VEXP: + close_exp(ls, var->info, 1); /* function must return 1 value */ + break; + } + var->k = VEXP; + var->info = 0; /* now this is a closed expression */ +} + + +static void storevar (LexState *ls, vardesc *var) { + switch (var->k) { + case VLOCAL: + code_oparg(ls, SETLOCAL, 8, var->info, -1); + break; + case VGLOBAL: + code_oparg(ls, SETGLOBAL, 8, var->info, -1); + break; + case VINDEXED: + code_opcode(ls, SETTABLE0, -3); + break; + default: + LUA_INTERNALERROR("invalid var kind to store"); + } +} + + +static int fix_jump (LexState *ls, int pc, OpCode op, int n) { + /* jump is relative to position following jump instruction */ + return fix_opcode(ls, pc, op, 0, n-(pc+JMPSIZE)); +} + + +static void fix_upjmp (LexState *ls, OpCode op, int pos) { + int delta = ls->fs->pc+JMPSIZE - pos; /* jump is relative */ + if (delta > 255) delta++; + code_oparg(ls, op, 0, delta, 0); +} + + +static void codeIf (LexState *ls, int thenAdd, int elseAdd) { + FuncState *fs = ls->fs; + int elseinit = elseAdd+JMPSIZE; + if (fs->pc == elseinit) { /* no else part */ + fs->pc -= JMPSIZE; + elseinit = fs->pc; + } + else + elseinit += fix_jump(ls, elseAdd, JMP, fs->pc); + fix_jump(ls, thenAdd, IFFJMP, elseinit); +} + + +static void func_onstack (LexState *ls, FuncState *func) { + FuncState *fs = ls->fs; + int i; + int c = next_constant(fs); + ttype(&fs->f->consts[c]) = LUA_T_PROTO; + fs->f->consts[c].value.tf = func->f; + if (func->nupvalues == 0) + code_constant(ls, c); + else { + for (i=0; inupvalues; i++) + lua_pushvar(ls, &func->upvalues[i]); + code_oparg(ls, CLOSURE, 0, c, -func->nupvalues+1); + code_byte(fs, func->nupvalues); + } +} + + +static void init_state (LexState *ls, FuncState *fs, TaggedString *filename) { + TProtoFunc *f = luaF_newproto(); + fs->prev = ls->fs; /* linked list of funcstates */ + ls->fs = fs; + fs->stacksize = 0; + fs->maxstacksize = 0; + fs->nlocalvar = 0; + fs->nupvalues = 0; + fs->lastsetline = 0; + fs->f = f; + f->fileName = filename; + fs->pc = 0; + fs->maxcode = 0; + f->code = NULL; + fs->maxconsts = 0; + if (lua_debug) + fs->nvars = fs->maxvars = 0; + else + fs->maxvars = -1; /* flag no debug information */ + code_byte(fs, 0); /* to be filled with stacksize */ + code_byte(fs, 0); /* to be filled with arg information */ +} + + +static void close_func (LexState *ls) { + FuncState *fs = ls->fs; + TProtoFunc *f = fs->f; + code_opcode(ls, ENDCODE, 0); + f->code[0] = fs->maxstacksize; + f->code = luaM_reallocvector(f->code, fs->pc, Byte); + f->consts = luaM_reallocvector(f->consts, f->nconsts, TObject); + if (fs->maxvars != -1) { /* debug information? */ + luaI_registerlocalvar(fs, NULL, -1); /* flag end of vector */ + f->locvars = luaM_reallocvector(f->locvars, fs->nvars, LocVar); + } + ls->fs = fs->prev; +} + + + +static int expfollow [] = {ELSE, ELSEIF, THEN, IF, WHILE, REPEAT, DO, NAME, + LOCAL, FUNCTION, END, UNTIL, RETURN, ')', ']', '}', ';', EOS, ',', 0}; + +static int is_in (int tok, int *toks) { + int *t = toks; + while (*t) { + if (*t == tok) + return t-toks; + t++; + } + return -1; +} + + +static void next (LexState *ls) { + ls->token = luaX_lex(ls); +} + + +static void error_expected (LexState *ls, int token) { + char buff[100], t[TOKEN_LEN]; + luaX_token2str(ls, token, t); + sprintf(buff, "`%s' expected", t); + luaX_error(ls, buff); +} + +static void error_unmatched (LexState *ls, int what, int who, int where) { + if (where == ls->linenumber) + error_expected(ls, what); + else { + char buff[100]; + char t_what[TOKEN_LEN], t_who[TOKEN_LEN]; + luaX_token2str(ls, what, t_what); + luaX_token2str(ls, who, t_who); + sprintf(buff, "`%s' expected (to close `%s' at line %d)", + t_what, t_who, where); + luaX_error(ls, buff); + } +} + +static void check (LexState *ls, int c) { + if (ls->token != c) + error_expected(ls, c); + next(ls); +} + +static void check_match (LexState *ls, int what, int who, int where) { + if (ls->token != what) + error_unmatched(ls, what, who, where); + check_debugline(ls); /* to 'mark' the 'what' */ + next(ls); +} + +static TaggedString *checkname (LexState *ls) { + TaggedString *ts; + if (ls->token != NAME) + luaX_error(ls, "`NAME' expected"); + ts = ls->seminfo.ts; + next(ls); + return ts; +} + + +static int optional (LexState *ls, int c) { + if (ls->token == c) { + next(ls); + return 1; + } + else return 0; +} + + +TProtoFunc *luaY_parser (ZIO *z) { + struct LexState lexstate; + struct FuncState funcstate; + luaX_setinput(&lexstate, z); + init_state(&lexstate, &funcstate, luaS_new(zname(z))); + next(&lexstate); /* read first token */ + chunk(&lexstate); + if (lexstate.token != EOS) + luaX_error(&lexstate, " expected"); + close_func(&lexstate); + return funcstate.f; +} + + + +/*============================================================*/ +/* GRAMAR RULES */ +/*============================================================*/ + +static void chunk (LexState *ls) { + /* chunk -> statlist ret */ + statlist(ls); + ret(ls); +} + +static void statlist (LexState *ls) { + /* statlist -> { stat [;] } */ + while (stat(ls)) { + LUA_ASSERT(ls->fs->stacksize == ls->fs->nlocalvar, + "stack size != # local vars"); + optional(ls, ';'); + } +} + +static int stat (LexState *ls) { + int line = ls->linenumber; /* may be needed for error messages */ + FuncState *fs = ls->fs; + switch (ls->token) { + case IF: { /* stat -> IF ifpart END */ + next(ls); + ifpart(ls); + check_match(ls, END, IF, line); + return 1; + } + + case WHILE: { /* stat -> WHILE cond DO block END */ + TProtoFunc *f = fs->f; + int while_init = fs->pc; + int cond_end, cond_size; + next(ls); + cond_end = cond(ls); + check(ls, DO); + block(ls); + check_match(ls, END, WHILE, line); + cond_size = cond_end-while_init; + check_pc(fs, cond_size); + memcpy(f->code+fs->pc, f->code+while_init, cond_size); + luaO_memdown(f->code+while_init, f->code+cond_end, fs->pc-while_init); + while_init += JMPSIZE + fix_jump(ls, while_init, JMP, fs->pc-cond_size); + fix_upjmp(ls, IFTUPJMP, while_init); + return 1; + } + + case DO: { /* stat -> DO block END */ + next(ls); + block(ls); + check_match(ls, END, DO, line); + return 1; + } + + case REPEAT: { /* stat -> REPEAT block UNTIL exp1 */ + int repeat_init = fs->pc; + next(ls); + block(ls); + check_match(ls, UNTIL, REPEAT, line); + exp1(ls); + fix_upjmp(ls, IFFUPJMP, repeat_init); + deltastack(ls, -1); /* pops condition */ + return 1; + } + + case FUNCTION: { /* stat -> FUNCTION funcname body */ + int needself; + vardesc v; + if (ls->fs->prev) /* inside other function? */ + return 0; + check_debugline(ls); + next(ls); + needself = funcname(ls, &v); + body(ls, needself, line); + storevar(ls, &v); + return 1; + } + + case LOCAL: { /* stat -> LOCAL localnamelist decinit */ + listdesc d; + int nvars; + check_debugline(ls); + next(ls); + nvars = localnamelist(ls); + decinit(ls, &d); + ls->fs->nlocalvar += nvars; + adjust_mult_assign(ls, nvars, &d); + return 1; + } + + case NAME: case '%': { /* stat -> func | ['%'] NAME assignment */ + vardesc v; + check_debugline(ls); + var_or_func(ls, &v); + if (v.k == VEXP) { /* stat -> func */ + if (v.info == 0) /* is just an upper value? */ + luaX_error(ls, "syntax error"); + close_exp(ls, v.info, 0); + } + else { + int left = assignment(ls, &v, 1); /* stat -> ['%'] NAME assignment */ + adjuststack(ls, left); /* remove eventual 'garbage' left on stack */ + } + return 1; + } + + case RETURN: case ';': case ELSE: case ELSEIF: + case END: case UNTIL: case EOS: /* 'stat' follow */ + return 0; + + default: + luaX_error(ls, " expected"); + return 0; /* to avoid warnings */ + } +} + +static int SaveWord (LexState *ls) { + int res = ls->fs->pc; + check_pc(ls->fs, JMPSIZE); + ls->fs->pc += JMPSIZE; /* open space */ + return res; +} + +static int SaveWordPop (LexState *ls) { + deltastack(ls, -1); /* pop condition */ + return SaveWord(ls); +} + +static int cond (LexState *ls) { + /* cond -> exp1 */ + exp1(ls); + return SaveWordPop(ls); +} + +static void block (LexState *ls) { + /* block -> chunk */ + FuncState *fs = ls->fs; + int nlocalvar = fs->nlocalvar; + chunk(ls); + adjuststack(ls, fs->nlocalvar - nlocalvar); + for (; fs->nlocalvar > nlocalvar; fs->nlocalvar--) + luaI_unregisterlocalvar(fs, ls->linenumber); +} + +static int funcname (LexState *ls, vardesc *v) { + /* funcname -> NAME [':' NAME | '.' NAME] */ + int needself = 0; + singlevar(ls, checkname(ls), v, 0); + if (ls->token == ':' || ls->token == '.') { + needself = (ls->token == ':'); + next(ls); + lua_pushvar(ls, v); + code_string(ls, checkname(ls)); + v->k = VINDEXED; + } + return needself; +} + +static void body (LexState *ls, int needself, int line) { + /* body -> '(' parlist ')' chunk END */ + FuncState newfs; + init_state(ls, &newfs, ls->fs->f->fileName); + newfs.f->lineDefined = line; + check(ls, '('); + if (needself) + add_localvar(ls, luaS_new("self")); + parlist(ls); + check(ls, ')'); + chunk(ls); + check_match(ls, END, FUNCTION, line); + close_func(ls); + func_onstack(ls, &newfs); +} + +static void ifpart (LexState *ls) { + /* ifpart -> cond THEN block [ELSE block | ELSEIF ifpart] */ + int c = cond(ls); + int e; + check(ls, THEN); + block(ls); + e = SaveWord(ls); + switch (ls->token) { + case ELSE: + next(ls); + block(ls); + break; + + case ELSEIF: + next(ls); + ifpart(ls); + break; + } + codeIf(ls, c, e); +} + +static void ret (LexState *ls) { + /* ret -> [RETURN explist sc] */ + if (ls->token == RETURN) { + listdesc e; + check_debugline(ls); + next(ls); + explist(ls, &e); + close_exp(ls, e.pc, MULT_RET); + code_oparg(ls, RETCODE, 0, ls->fs->nlocalvar, 0); + ls->fs->stacksize = ls->fs->nlocalvar; /* removes all temp values */ + optional(ls, ';'); + } +} + + +/* +** For parsing expressions, we use a classic stack with priorities. +** Each binary operator is represented by its index in "binop" + FIRSTBIN +** (EQ=2, NE=3, ... '^'=13). The unary NOT is 0 and UNMINUS is 1. +*/ + +/* code of first binary operator */ +#define FIRSTBIN 2 + +/* code for power operator (last operator) +** '^' needs special treatment because it is right associative +*/ +#define POW 13 + +static int binop [] = {EQ, NE, '>', '<', LE, GE, CONC, + '+', '-', '*', '/', '^', 0}; + +static int priority [POW+1] = {5, 5, 1, 1, 1, 1, 1, 1, 2, 3, 3, 4, 4, 6}; + +static OpCode opcodes [POW+1] = {NOTOP, MINUSOP, EQOP, NEQOP, GTOP, LTOP, + LEOP, GEOP, CONCOP, ADDOP, SUBOP, MULTOP, DIVOP, POWOP}; + +#define MAXOPS 20 + +typedef struct { + int ops[MAXOPS]; + int top; +} stack_op; + + +static void exp1 (LexState *ls) { + vardesc v; + exp0(ls, &v); + lua_pushvar(ls, &v); + if (is_in(ls->token, expfollow) < 0) + luaX_error(ls, "ill formed expression"); +} + + +static void exp0 (LexState *ls, vardesc *v) { + exp2(ls, v); + while (ls->token == AND || ls->token == OR) { + int is_and = (ls->token == AND); + int pc; + lua_pushvar(ls, v); + next(ls); + pc = SaveWordPop(ls); + exp2(ls, v); + lua_pushvar(ls, v); + fix_jump(ls, pc, (is_and?ONFJMP:ONTJMP), ls->fs->pc); + } +} + + +static void push (LexState *ls, stack_op *s, int op) { + if (s->top == MAXOPS) + luaX_error(ls, "expression too complex"); + s->ops[s->top++] = op; +} + + +static void prefix (LexState *ls, stack_op *s) { + while (ls->token == NOT || ls->token == '-') { + push(ls, s, ls->token==NOT?0:1); + next(ls); + } +} + +static void pop_to (LexState *ls, stack_op *s, int prio) { + int op; + while (s->top > 0 && priority[(op=s->ops[s->top-1])] >= prio) { + code_opcode(ls, opcodes[op], optop--; + } +} + +static void exp2 (LexState *ls, vardesc *v) { + stack_op s; + int op; + s.top = 0; + prefix(ls, &s); + simpleexp(ls, v); + while ((op = is_in(ls->token, binop)) >= 0) { + op += FIRSTBIN; + lua_pushvar(ls, v); + /* '^' is right associative, so must 'simulate' a higher priority */ + pop_to(ls, &s, (op == POW)?priority[op]+1:priority[op]); + push(ls, &s, op); + next(ls); + prefix(ls, &s); + simpleexp(ls, v); + lua_pushvar(ls, v); + } + if (s.top > 0) { + lua_pushvar(ls, v); + pop_to(ls, &s, 0); + } +} + + +static void simpleexp (LexState *ls, vardesc *v) { + check_debugline(ls); + switch (ls->token) { + case '(': /* simpleexp -> '(' exp0 ')' */ + next(ls); + exp0(ls, v); + check(ls, ')'); + break; + + case NUMBER: /* simpleexp -> NUMBER */ + code_number(ls, ls->seminfo.r); + next(ls); + v->k = VEXP; v->info = 0; + break; + + case STRING: /* simpleexp -> STRING */ + code_string(ls, ls->seminfo.ts); + next(ls); + v->k = VEXP; v->info = 0; + break; + + case NIL: /* simpleexp -> NIL */ + adjuststack(ls, -1); + next(ls); + v->k = VEXP; v->info = 0; + break; + + case '{': /* simpleexp -> constructor */ + constructor(ls); + v->k = VEXP; v->info = 0; + break; + + case FUNCTION: { /* simpleexp -> FUNCTION body */ + int line = ls->linenumber; + next(ls); + body(ls, 0, line); + v->k = VEXP; v->info = 0; + break; + } + + case NAME: case '%': + var_or_func(ls, v); + break; + + default: + luaX_error(ls, " expected"); + break; + } +} + +static void var_or_func (LexState *ls, vardesc *v) { + /* var_or_func -> ['%'] NAME var_or_func_tail */ + if (optional(ls, '%')) { /* upvalue? */ + pushupvalue(ls, checkname(ls)); + v->k = VEXP; + v->info = 0; /* closed expression */ + } + else /* variable name */ + singlevar(ls, checkname(ls), v, 0); + var_or_func_tail(ls, v); +} + +static void var_or_func_tail (LexState *ls, vardesc *v) { + for (;;) { + switch (ls->token) { + case '.': /* var_or_func_tail -> '.' NAME */ + next(ls); + lua_pushvar(ls, v); /* 'v' must be on stack */ + v->k = VDOT; + v->info = string_constant(ls->fs, checkname(ls)); + break; + + case '[': /* var_or_func_tail -> '[' exp1 ']' */ + next(ls); + lua_pushvar(ls, v); /* 'v' must be on stack */ + exp1(ls); + check(ls, ']'); + v->k = VINDEXED; + break; + + case ':': /* var_or_func_tail -> ':' NAME funcparams */ + next(ls); + lua_pushvar(ls, v); /* 'v' must be on stack */ + code_oparg(ls, PUSHSELF, 8, string_constant(ls->fs, checkname(ls)), 1); + v->k = VEXP; + v->info = funcparams(ls, 1); + break; + + case '(': case STRING: case '{': /* var_or_func_tail -> funcparams */ + lua_pushvar(ls, v); /* 'v' must be on stack */ + v->k = VEXP; + v->info = funcparams(ls, 0); + break; + + default: return; /* should be follow... */ + } + } +} + +static int funcparams (LexState *ls, int slf) { + FuncState *fs = ls->fs; + int nparams = 1; /* default value */ + switch (ls->token) { + case '(': { /* funcparams -> '(' explist ')' */ + listdesc e; + next(ls); + explist(ls, &e); + check(ls, ')'); + close_exp(ls, e.pc, 1); + nparams = e.n; + break; + } + + case '{': /* funcparams -> constructor */ + constructor(ls); + break; + + case STRING: /* funcparams -> STRING */ + code_string(ls, ls->seminfo.ts); + next(ls); + break; + + default: + luaX_error(ls, "function arguments expected"); + break; + } + code_byte(fs, 0); /* save space for opcode */ + code_byte(fs, 0); /* and nresult */ + code_byte(fs, nparams+slf); + return fs->pc-1; +} + +static void explist (LexState *ls, listdesc *d) { + switch (ls->token) { + case ELSE: case ELSEIF: case END: case UNTIL: + case EOS: case ';': case ')': + d->pc = 0; + d->n = 0; + break; + + default: + explist1(ls, d); + } +} + +static void explist1 (LexState *ls, listdesc *d) { + vardesc v; + exp0(ls, &v); + d->n = 1; + while (ls->token == ',') { + d->n++; + lua_pushvar(ls, &v); + next(ls); + exp0(ls, &v); + } + if (v.k == VEXP) + d->pc = v.info; + else { + lua_pushvar(ls, &v); + d->pc = 0; + } +} + +static void parlist (LexState *ls) { + int nparams = 0; + int dots = 0; + switch (ls->token) { + case DOTS: /* parlist -> DOTS */ + next(ls); + dots = 1; + break; + + case NAME: /* parlist, tailparlist -> NAME [',' tailparlist] */ + init: + store_localvar(ls, checkname(ls), nparams++); + if (ls->token == ',') { + next(ls); + switch (ls->token) { + case DOTS: /* tailparlist -> DOTS */ + next(ls); + dots = 1; + break; + + case NAME: /* tailparlist -> NAME [',' tailparlist] */ + goto init; + + default: luaX_error(ls, "NAME or `...' expected"); + } + } + break; + + case ')': break; /* parlist -> empty */ + + default: luaX_error(ls, "NAME or `...' expected"); + } + code_args(ls, nparams, dots); +} + +static int localnamelist (LexState *ls) { + /* localnamelist -> NAME {',' NAME} */ + int i = 1; + store_localvar(ls, checkname(ls), 0); + while (ls->token == ',') { + next(ls); + store_localvar(ls, checkname(ls), i++); + } + return i; +} + +static void decinit (LexState *ls, listdesc *d) { + /* decinit -> ['=' explist1] */ + if (ls->token == '=') { + next(ls); + explist1(ls, d); + } + else { + d->n = 0; + d->pc = 0; + } +} + +static int assignment (LexState *ls, vardesc *v, int nvars) { + int left = 0; + /* dotted variables must be stored like regular indexed vars */ + if (v->k == VDOT) { + code_constant(ls, v->info); + v->k = VINDEXED; + } + if (ls->token == ',') { /* assignment -> ',' NAME assignment */ + vardesc nv; + next(ls); + var_or_func(ls, &nv); + if (nv.k == VEXP) + luaX_error(ls, "syntax error"); + left = assignment(ls, &nv, nvars+1); + } + else { /* assignment -> '=' explist1 */ + listdesc d; + check(ls, '='); + explist1(ls, &d); + adjust_mult_assign(ls, nvars, &d); + } + if (v->k != VINDEXED || left+(nvars-1) == 0) { + /* global/local var or indexed var without values in between */ + storevar(ls, v); + } + else { /* indexed var with values in between*/ + code_oparg(ls, SETTABLE, 0, left+(nvars-1), -1); + left += 2; /* table/index are not popped, because they aren't on top */ + } + return left; +} + +static void constructor (LexState *ls) { + /* constructor -> '{' part [';' part] '}' */ + int line = ls->linenumber; + int pc = SaveWord(ls); + int nelems; + constdesc cd; + deltastack(ls, 1); + check(ls, '{'); + part(ls, &cd); + nelems = cd.n; + if (ls->token == ';') { + constdesc other_cd; + next(ls); + part(ls, &other_cd); + if (cd.k == other_cd.k) /* repeated parts? */ + luaX_error(ls, "invalid constructor syntax"); + nelems += other_cd.n; + } + check_match(ls, '}', '{', line); + fix_opcode(ls, pc, CREATEARRAY, 2, nelems); +} + +static void part (LexState *ls, constdesc *cd) { + switch (ls->token) { + case ';': case '}': /* part -> empty */ + cd->n = 0; + cd->k = ls->token; + return; + + case NAME: { + vardesc v; + exp0(ls, &v); + if (ls->token == '=') { + switch (v.k) { + case VGLOBAL: + code_constant(ls, v.info); + break; + case VLOCAL: + code_string(ls, ls->fs->localvar[v.info]); + break; + default: + luaX_error(ls, "`=' unexpected"); + } + next(ls); + exp1(ls); + cd->n = recfields(ls); + cd->k = 1; /* record */ + } + else { + lua_pushvar(ls, &v); + cd->n = listfields(ls); + cd->k = 0; /* list */ + } + break; + } + + case '[': /* part -> recfield recfields */ + recfield(ls); + cd->n = recfields(ls); + cd->k = 1; /* record */ + break; + + default: /* part -> exp1 listfields */ + exp1(ls); + cd->n = listfields(ls); + cd->k = 0; /* list */ + break; + } +} + +static int recfields (LexState *ls) { + /* recfields -> { ',' recfield } [','] */ + int n = 1; /* one has been read before */ + while (ls->token == ',') { + next(ls); + if (ls->token == ';' || ls->token == '}') + break; + recfield(ls); + n++; + if (n%RFIELDS_PER_FLUSH == 0) + flush_record(ls, RFIELDS_PER_FLUSH); + } + flush_record(ls, n%RFIELDS_PER_FLUSH); + return n; +} + +static int listfields (LexState *ls) { + /* listfields -> { ',' exp1 } [','] */ + int n = 1; /* one has been read before */ + while (ls->token == ',') { + next(ls); + if (ls->token == ';' || ls->token == '}') + break; + exp1(ls); + n++; + if (n%LFIELDS_PER_FLUSH == 0) + flush_list(ls, n/LFIELDS_PER_FLUSH - 1, LFIELDS_PER_FLUSH); + } + flush_list(ls, n/LFIELDS_PER_FLUSH, n%LFIELDS_PER_FLUSH); + return n; +} + +static void recfield (LexState *ls) { + /* recfield -> (NAME | '['exp1']') = exp1 */ + switch (ls->token) { + case NAME: + code_string(ls, checkname(ls)); + break; + + case '[': + next(ls); + exp1(ls); + check(ls, ']'); + break; + + default: luaX_error(ls, "NAME or `[' expected"); + } + check(ls, '='); + exp1(ls); +} + diff --git a/src/lparser.h b/src/lparser.h new file mode 100644 index 0000000..b37fd81 --- /dev/null +++ b/src/lparser.h @@ -0,0 +1,20 @@ +/* +** $Id: lparser.h,v 1.2 1997/12/22 20:57:18 roberto Exp $ +** Syntax analizer and code generator +** See Copyright Notice in lua.h +*/ + +#ifndef lparser_h +#define lparser_h + +#include "lobject.h" +#include "lzio.h" + + +void luaY_codedebugline (int line); +TProtoFunc *luaY_parser (ZIO *z); +void luaY_error (char *s); +void luaY_syntaxerror (char *s, char *token); + + +#endif diff --git a/src/lstate.c b/src/lstate.c new file mode 100644 index 0000000..43015b9 --- /dev/null +++ b/src/lstate.c @@ -0,0 +1,86 @@ +/* +** $Id: lstate.c,v 1.6 1998/06/02 20:37:04 roberto Exp $ +** Global State +** See Copyright Notice in lua.h +*/ + + +#include "lbuiltin.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "llex.h" +#include "lmem.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" + + +lua_State *lua_state = NULL; + + +void lua_open (void) +{ + if (lua_state) return; + lua_state = luaM_new(lua_State); + L->numCblocks = 0; + L->Cstack.base = 0; + L->Cstack.lua2C = 0; + L->Cstack.num = 0; + L->errorJmp = NULL; + L->rootproto.next = NULL; + L->rootproto.marked = 0; + L->rootcl.next = NULL; + L->rootcl.marked = 0; + L->rootglobal.next = NULL; + L->rootglobal.marked = 0; + L->roottable.next = NULL; + L->roottable.marked = 0; + L->refArray = NULL; + L->refSize = 0; + L->Mbuffsize = 0; + L->Mbuffnext = 0; + L->Mbuffbase = NULL; + L->Mbuffer = NULL; + L->GCthreshold = GARBAGE_BLOCK; + L->nblocks = 0; + luaD_init(); + luaS_init(); + luaX_init(); + luaT_init(); + luaB_predefine(); +} + + +void lua_close (void) +{ + TaggedString *alludata = luaS_collectudata(); + L->GCthreshold = MAX_INT; /* to avoid GC during GC */ + luaC_hashcallIM((Hash *)L->roottable.next); /* GC t.methods for tables */ + luaC_strcallIM(alludata); /* GC tag methods for userdata */ + luaD_gcIM(&luaO_nilobject); /* GC tag method for nil (signal end of GC) */ + luaH_free((Hash *)L->roottable.next); + luaF_freeproto((TProtoFunc *)L->rootproto.next); + luaF_freeclosure((Closure *)L->rootcl.next); + luaS_free(alludata); + luaS_freeall(); + luaM_free(L->stack.stack); + luaM_free(L->IMtable); + luaM_free(L->refArray); + luaM_free(L->Mbuffer); + luaM_free(L); + L = NULL; +#ifdef DEBUG + printf("total de blocos: %ld\n", numblocks); + printf("total de memoria: %ld\n", totalmem); +#endif +} + + +lua_State *lua_setstate (lua_State *st) { + lua_State *old = lua_state; + lua_state = st; + return old; +} + diff --git a/src/lstate.h b/src/lstate.h new file mode 100644 index 0000000..71d956f --- /dev/null +++ b/src/lstate.h @@ -0,0 +1,86 @@ +/* +** $Id: lstate.h,v 1.11 1998/06/24 13:33:00 roberto Exp $ +** Global State +** See Copyright Notice in lua.h +*/ + +#ifndef lstate_h +#define lstate_h + +#include + +#include "lobject.h" +#include "lua.h" + + +#define MAX_C_BLOCKS 10 + +#define GARBAGE_BLOCK 150 + + +typedef int StkId; /* index to stack elements */ + +struct Stack { + TObject *top; + TObject *stack; + TObject *last; +}; + +struct C_Lua_Stack { + StkId base; /* when Lua calls C or C calls Lua, points to */ + /* the first slot after the last parameter. */ + StkId lua2C; /* points to first element of "array" lua2C */ + int num; /* size of "array" lua2C */ +}; + + +typedef struct { + int size; + int nuse; /* number of elements (including EMPTYs) */ + TaggedString **hash; +} stringtable; + + +enum Status {LOCK, HOLD, FREE, COLLECTED}; + +struct ref { + TObject o; + enum Status status; +}; + + +struct lua_State { + /* thread-specific state */ + struct Stack stack; /* Lua stack */ + struct C_Lua_Stack Cstack; /* C2lua struct */ + jmp_buf *errorJmp; /* current error recover point */ + char *Mbuffer; /* global buffer */ + char *Mbuffbase; /* current first position of Mbuffer */ + int Mbuffsize; /* size of Mbuffer */ + int Mbuffnext; /* next position to fill in Mbuffer */ + struct C_Lua_Stack Cblocks[MAX_C_BLOCKS]; + int numCblocks; /* number of nested Cblocks */ + /* global state */ + TObject errorim; /* error tag method */ + GCnode rootproto; /* list of all prototypes */ + GCnode rootcl; /* list of all closures */ + GCnode roottable; /* list of all tables */ + GCnode rootglobal; /* list of strings with global values */ + stringtable *string_root; /* array of hash tables for strings and udata */ + struct IM *IMtable; /* table for tag methods */ + int IMtable_size; /* size of IMtable */ + int last_tag; /* last used tag in IMtable */ + struct ref *refArray; /* locked objects */ + int refSize; /* size of refArray */ + unsigned long GCthreshold; + unsigned long nblocks; /* number of 'blocks' currently allocated */ +}; + + +extern lua_State *lua_state; + + +#define L lua_state + + +#endif diff --git a/src/lstring.c b/src/lstring.c new file mode 100644 index 0000000..fd7cc58 --- /dev/null +++ b/src/lstring.c @@ -0,0 +1,313 @@ +/* +** $Id: lstring.c,v 1.13 1998/06/19 16:14:09 roberto Exp $ +** String table (keeps all strings handled by Lua) +** See Copyright Notice in lua.h +*/ + + +#include + +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "lstring.h" +#include "lua.h" + + +#define NUM_HASHS 61 + + +#define gcsizestring(l) (1+(l/64)) /* "weight" for a string with length 'l' */ + + + +static TaggedString EMPTY = {{NULL, 2}, 0L, 0, + {{{LUA_T_NIL, {NULL}}, 0L}}, {0}}; + + +void luaS_init (void) +{ + int i; + L->string_root = luaM_newvector(NUM_HASHS, stringtable); + for (i=0; istring_root[i].size = 0; + L->string_root[i].nuse = 0; + L->string_root[i].hash = NULL; + } +} + + +static unsigned long hash_s (char *s, long l) +{ + unsigned long h = 0; + while (l--) + h = ((h<<5)-h)^(unsigned char)*(s++); + return h; +} + +static int newsize (stringtable *tb) +{ + int size = tb->size; + int realuse = 0; + int i; + /* count how many entries are really in use */ + for (i=0; ihash[i] != NULL && tb->hash[i] != &EMPTY) + realuse++; + if (2*(realuse+1) <= size) /* +1 is the new element */ + return size; /* don't need to grow, just rehash to clear EMPTYs */ + else + return luaO_redimension(size); +} + + +static void grow (stringtable *tb) +{ + + int ns = newsize(tb); + TaggedString **newhash = luaM_newvector(ns, TaggedString *); + int i; + for (i=0; inuse = 0; + for (i=0; isize; i++) { + if (tb->hash[i] != NULL && tb->hash[i] != &EMPTY) { + int h = tb->hash[i]->hash%ns; + while (newhash[h]) + h = (h+1)%ns; + newhash[h] = tb->hash[i]; + tb->nuse++; + } + } + luaM_free(tb->hash); + tb->size = ns; + tb->hash = newhash; +} + + +static TaggedString *newone_s (char *str, long l, unsigned long h) +{ + TaggedString *ts = (TaggedString *)luaM_malloc(sizeof(TaggedString)+l); + memcpy(ts->str, str, l); + ts->str[l] = 0; /* ending 0 */ + ts->u.s.globalval.ttype = LUA_T_NIL; /* initialize global value */ + ts->u.s.len = l; + ts->constindex = 0; + L->nblocks += gcsizestring(l); + ts->head.marked = 0; + ts->head.next = (GCnode *)ts; /* signal it is in no list */ + ts->hash = h; + return ts; +} + +static TaggedString *newone_u (char *buff, int tag, unsigned long h) +{ + TaggedString *ts = luaM_new(TaggedString); + ts->u.d.v = buff; + ts->u.d.tag = (tag == LUA_ANYTAG) ? 0 : tag; + ts->constindex = -1; /* tag -> this is a userdata */ + L->nblocks++; + ts->head.marked = 0; + ts->head.next = (GCnode *)ts; /* signal it is in no list */ + ts->hash = h; + return ts; +} + +static TaggedString *insert_s (char *str, long l, stringtable *tb) +{ + TaggedString *ts; + unsigned long h = hash_s(str, l); + int size = tb->size; + int i; + int j = -1; + if ((long)tb->nuse*3 >= (long)size*2) { + grow(tb); + size = tb->size; + } + for (i = h%size; (ts = tb->hash[i]) != NULL; ) { + if (ts == &EMPTY) + j = i; + else if (ts->constindex >= 0 && + ts->u.s.len == l && + (memcmp(str, ts->str, l) == 0)) + return ts; + if (++i == size) i=0; + } + /* not found */ + if (j != -1) /* is there an EMPTY space? */ + i = j; + else + tb->nuse++; + ts = tb->hash[i] = newone_s(str, l, h); + return ts; +} + +static TaggedString *insert_u (void *buff, int tag, stringtable *tb) +{ + TaggedString *ts; + unsigned long h = (unsigned long)buff; + int size = tb->size; + int i; + int j = -1; + if ((long)tb->nuse*3 >= (long)size*2) { + grow(tb); + size = tb->size; + } + for (i = h%size; (ts = tb->hash[i]) != NULL; ) { + if (ts == &EMPTY) + j = i; + else if (ts->constindex < 0 && /* is a udata? */ + (tag == ts->u.d.tag || tag == LUA_ANYTAG) && + buff == ts->u.d.v) + return ts; + if (++i == size) i=0; + } + /* not found */ + if (j != -1) /* is there an EMPTY space? */ + i = j; + else + tb->nuse++; + ts = tb->hash[i] = newone_u(buff, tag, h); + return ts; +} + +TaggedString *luaS_createudata (void *udata, int tag) +{ + return insert_u(udata, tag, &L->string_root[(unsigned)udata%NUM_HASHS]); +} + +TaggedString *luaS_newlstr (char *str, long l) +{ + int i = (l==0)?0:(unsigned char)str[0]; + return insert_s(str, l, &L->string_root[i%NUM_HASHS]); +} + +TaggedString *luaS_new (char *str) +{ + return luaS_newlstr(str, strlen(str)); +} + +TaggedString *luaS_newfixedstring (char *str) +{ + TaggedString *ts = luaS_new(str); + if (ts->head.marked == 0) + ts->head.marked = 2; /* avoid GC */ + return ts; +} + + +void luaS_free (TaggedString *l) +{ + while (l) { + TaggedString *next = (TaggedString *)l->head.next; + L->nblocks -= (l->constindex == -1) ? 1 : gcsizestring(l->u.s.len); + luaM_free(l); + l = next; + } +} + + +/* +** Garbage collection functions. +*/ + +static void remove_from_list (GCnode *l) +{ + while (l) { + GCnode *next = l->next; + while (next && !next->marked) + next = l->next = next->next; + l = next; + } +} + + +TaggedString *luaS_collector (void) +{ + TaggedString *frees = NULL; + int i; + remove_from_list(&(L->rootglobal)); + for (i=0; istring_root[i]; + int j; + for (j=0; jsize; j++) { + TaggedString *t = tb->hash[j]; + if (t == NULL) continue; + if (t->head.marked == 1) + t->head.marked = 0; + else if (!t->head.marked) { + t->head.next = (GCnode *)frees; + frees = t; + tb->hash[j] = &EMPTY; + } + } + } + return frees; +} + + +TaggedString *luaS_collectudata (void) +{ + TaggedString *frees = NULL; + int i; + L->rootglobal.next = NULL; /* empty list of globals */ + for (i=0; istring_root[i]; + int j; + for (j=0; jsize; j++) { + TaggedString *t = tb->hash[j]; + if (t == NULL || t == &EMPTY || t->constindex != -1) + continue; /* get only user data */ + t->head.next = (GCnode *)frees; + frees = t; + tb->hash[j] = &EMPTY; + } + } + return frees; +} + + +void luaS_freeall (void) +{ + int i; + for (i=0; istring_root[i]; + int j; + for (j=0; jsize; j++) { + TaggedString *t = tb->hash[j]; + if (t == &EMPTY) continue; + luaM_free(t); + } + luaM_free(tb->hash); + } + luaM_free(L->string_root); +} + + +void luaS_rawsetglobal (TaggedString *ts, TObject *newval) +{ + ts->u.s.globalval = *newval; + if (ts->head.next == (GCnode *)ts) { /* is not in list? */ + ts->head.next = L->rootglobal.next; + L->rootglobal.next = (GCnode *)ts; + } +} + + +char *luaS_travsymbol (int (*fn)(TObject *)) +{ + TaggedString *g; + for (g=(TaggedString *)L->rootglobal.next; g; g=(TaggedString *)g->head.next) + if (fn(&g->u.s.globalval)) + return g->str; + return NULL; +} + + +int luaS_globaldefined (char *name) +{ + TaggedString *ts = luaS_new(name); + return ts->u.s.globalval.ttype != LUA_T_NIL; +} + diff --git a/src/lstring.h b/src/lstring.h new file mode 100644 index 0000000..6b214a2 --- /dev/null +++ b/src/lstring.h @@ -0,0 +1,28 @@ +/* +** $Id: lstring.h,v 1.7 1998/03/06 16:54:42 roberto Exp $ +** String table (keep all strings handled by Lua) +** See Copyright Notice in lua.h +*/ + +#ifndef lstring_h +#define lstring_h + + +#include "lobject.h" + + +void luaS_init (void); +TaggedString *luaS_createudata (void *udata, int tag); +TaggedString *luaS_collector (void); +void luaS_free (TaggedString *l); +TaggedString *luaS_newlstr (char *str, long l); +TaggedString *luaS_new (char *str); +TaggedString *luaS_newfixedstring (char *str); +void luaS_rawsetglobal (TaggedString *ts, TObject *newval); +char *luaS_travsymbol (int (*fn)(TObject *)); +int luaS_globaldefined (char *name); +TaggedString *luaS_collectudata (void); +void luaS_freeall (void); + + +#endif diff --git a/src/ltable.c b/src/ltable.c new file mode 100644 index 0000000..28cd2ed --- /dev/null +++ b/src/ltable.c @@ -0,0 +1,216 @@ +/* +** $Id: ltable.c,v 1.12 1998/01/28 16:50:33 roberto Exp $ +** Lua tables (hash) +** See Copyright Notice in lua.h +*/ + +#include + +#include "lauxlib.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "ltable.h" +#include "lua.h" + + +#define gcsize(n) (1+(n/16)) + +#define nuse(t) ((t)->nuse) +#define nodevector(t) ((t)->node) + + +#define REHASH_LIMIT 0.70 /* avoid more than this % full */ + +#define TagDefault LUA_T_ARRAY; + + + +static long int hashindex (TObject *ref) +{ + long int h; + switch (ttype(ref)) { + case LUA_T_NUMBER: + h = (long int)nvalue(ref); + break; + case LUA_T_STRING: case LUA_T_USERDATA: + h = (IntPoint)tsvalue(ref); + break; + case LUA_T_ARRAY: + h = (IntPoint)avalue(ref); + break; + case LUA_T_PROTO: + h = (IntPoint)tfvalue(ref); + break; + case LUA_T_CPROTO: + h = (IntPoint)fvalue(ref); + break; + case LUA_T_CLOSURE: + h = (IntPoint)clvalue(ref); + break; + default: + lua_error("unexpected type to index table"); + h = 0; /* to avoid warnings */ + } + return (h >= 0 ? h : -(h+1)); +} + + +static int present (Hash *t, TObject *key) +{ + int tsize = nhash(t); + long int h = hashindex(key); + int h1 = h%tsize; + TObject *rf = ref(node(t, h1)); + if (ttype(rf) != LUA_T_NIL && !luaO_equalObj(key, rf)) { + int h2 = h%(tsize-2) + 1; + do { + h1 += h2; + if (h1 >= tsize) h1 -= tsize; + rf = ref(node(t, h1)); + } while (ttype(rf) != LUA_T_NIL && !luaO_equalObj(key, rf)); + } + return h1; +} + + +/* +** Alloc a vector node +*/ +static Node *hashnodecreate (int nhash) +{ + Node *v = luaM_newvector(nhash, Node); + int i; + for (i=0; ihead.next; + L->nblocks -= gcsize(frees->nhash); + hashdelete(frees); + frees = next; + } +} + + +Hash *luaH_new (int nhash) +{ + Hash *t = luaM_new(Hash); + nhash = luaO_redimension((int)((float)nhash/REHASH_LIMIT)); + nodevector(t) = hashnodecreate(nhash); + nhash(t) = nhash; + nuse(t) = 0; + t->htag = TagDefault; + luaO_insertlist(&(L->roottable), (GCnode *)t); + L->nblocks += gcsize(nhash); + return t; +} + + +static int newsize (Hash *t) +{ + Node *v = t->node; + int size = nhash(t); + int realuse = 0; + int i; + for (i=0; inblocks += gcsize(nnew)-gcsize(nold); + luaM_free(vold); +} + +/* +** If the hash node is present, return its pointer, otherwise return +** null. +*/ +TObject *luaH_get (Hash *t, TObject *ref) +{ + int h = present(t, ref); + if (ttype(ref(node(t, h))) != LUA_T_NIL) return val(node(t, h)); + else return NULL; +} + + +/* +** If the hash node is present, return its pointer, otherwise create a luaM_new +** node for the given reference and also return its pointer. +*/ +TObject *luaH_set (Hash *t, TObject *ref) +{ + Node *n = node(t, present(t, ref)); + if (ttype(ref(n)) == LUA_T_NIL) { + nuse(t)++; + if ((float)nuse(t) > (float)nhash(t)*REHASH_LIMIT) { + rehash(t); + n = node(t, present(t, ref)); + } + *ref(n) = *ref; + ttype(val(n)) = LUA_T_NIL; + } + return (val(n)); +} + + +static Node *hashnext (Hash *t, int i) +{ + Node *n; + int tsize = nhash(t); + if (i >= tsize) + return NULL; + n = node(t, i); + while (ttype(ref(n)) == LUA_T_NIL || ttype(val(n)) == LUA_T_NIL) { + if (++i >= tsize) + return NULL; + n = node(t, i); + } + return node(t, i); +} + +Node *luaH_next (TObject *o, TObject *r) +{ + Hash *t = avalue(o); + if (ttype(r) == LUA_T_NIL) + return hashnext(t, 0); + else { + int i = present(t, r); + Node *n = node(t, i); + luaL_arg_check(ttype(ref(n))!=LUA_T_NIL && ttype(val(n))!=LUA_T_NIL, + 2, "key not found"); + return hashnext(t, i+1); + } +} diff --git a/src/ltable.h b/src/ltable.h new file mode 100644 index 0000000..92b0316 --- /dev/null +++ b/src/ltable.h @@ -0,0 +1,24 @@ +/* +** $Id: ltable.h,v 1.5 1997/11/26 18:53:45 roberto Exp $ +** Lua tables (hash) +** See Copyright Notice in lua.h +*/ + +#ifndef ltable_h +#define ltable_h + +#include "lobject.h" + + +#define node(t,i) (&(t)->node[i]) +#define ref(n) (&(n)->ref) +#define val(n) (&(n)->val) +#define nhash(t) ((t)->nhash) + +Hash *luaH_new (int nhash); +void luaH_free (Hash *frees); +TObject *luaH_get (Hash *t, TObject *ref); +TObject *luaH_set (Hash *t, TObject *ref); +Node *luaH_next (TObject *o, TObject *r); + +#endif diff --git a/src/ltm.c b/src/ltm.c new file mode 100644 index 0000000..0bbee22 --- /dev/null +++ b/src/ltm.c @@ -0,0 +1,263 @@ +/* +** $Id: ltm.c,v 1.16 1998/06/18 16:57:03 roberto Exp $ +** Tag methods +** See Copyright Notice in lua.h +*/ + + +#include +#include + +#include "lauxlib.h" +#include "lmem.h" +#include "lobject.h" +#include "lstate.h" +#include "ltm.h" + + +char *luaT_eventname[] = { /* ORDER IM */ + "gettable", "settable", "index", "getglobal", "setglobal", "add", + "sub", "mul", "div", "pow", "unm", "lt", "le", "gt", "ge", + "concat", "gc", "function", NULL +}; + + +static int luaI_checkevent (char *name, char *list[]) +{ + int e = luaL_findstring(name, list); + if (e < 0) + luaL_verror("`%.50s' is not a valid event name", name); + return e; +} + + + +/* events in LUA_T_NIL are all allowed, since this is used as a +* 'placeholder' for "default" fallbacks +*/ +static char validevents[NUM_TAGS][IM_N] = { /* ORDER LUA_T, ORDER IM */ +{1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1}, /* LUA_T_USERDATA */ +{1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1}, /* LUA_T_NUMBER */ +{1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, /* LUA_T_STRING */ +{0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* LUA_T_ARRAY */ +{1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0}, /* LUA_T_PROTO */ +{1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0}, /* LUA_T_CPROTO */ +{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} /* LUA_T_NIL */ +}; + + +static int validevent (int t, int e) +{ /* ORDER LUA_T */ + return (t < LUA_T_NIL) ? 1 : validevents[-t][e]; +} + + +static void init_entry (int tag) +{ + int i; + for (i=0; iIMtable_size = NUM_TAGS*2; + L->last_tag = -(NUM_TAGS-1); + L->IMtable = luaM_newvector(L->IMtable_size, struct IM); + for (t=L->last_tag; t<=0; t++) + init_entry(t); +} + + +int lua_newtag (void) +{ + --L->last_tag; + if ((-L->last_tag) >= L->IMtable_size) + L->IMtable_size = luaM_growvector(&L->IMtable, L->IMtable_size, + struct IM, memEM, MAX_INT); + init_entry(L->last_tag); + return L->last_tag; +} + + +static void checktag (int tag) +{ + if (!(L->last_tag <= tag && tag <= 0)) + luaL_verror("%d is not a valid tag", tag); +} + +void luaT_realtag (int tag) +{ + if (!(L->last_tag <= tag && tag < LUA_T_NIL)) + luaL_verror("tag %d is not result of `newtag'", tag); +} + + +int lua_copytagmethods (int tagto, int tagfrom) +{ + int e; + checktag(tagto); + checktag(tagfrom); + for (e=0; evalue.a->htag; + case LUA_T_USERDATA: { + int tag = o->value.ts->u.d.tag; + return (tag >= 0) ? LUA_T_USERDATA : tag; + } + case LUA_T_CLOSURE: + return o->value.cl->consts[0].ttype; +#ifdef DEBUG + case LUA_T_PMARK: case LUA_T_CMARK: + case LUA_T_CLMARK: case LUA_T_LINE: + LUA_INTERNALERROR("invalid type"); +#endif + default: + return t; + } +} + + +TObject *luaT_gettagmethod (int t, char *event) +{ + int e = luaI_checkevent(event, luaT_eventname); + checktag(t); + if (validevent(t, e)) + return luaT_getim(t,e); + else + return &luaO_nilobject; +} + + +void luaT_settagmethod (int t, char *event, TObject *func) +{ + TObject temp = *func; + int e = luaI_checkevent(event, luaT_eventname); + checktag(t); + if (!validevent(t, e)) + luaL_verror("settagmethod: cannot change tag method `%.20s' for tag %d", + luaT_eventname[e], t); + *func = *luaT_getim(t,e); + *luaT_getim(t, e) = temp; +} + + +char *luaT_travtagmethods (int (*fn)(TObject *)) +{ + int e; + if (fn(&L->errorim)) + return "error"; + for (e=IM_GETTABLE; e<=IM_FUNCTION; e++) { /* ORDER IM */ + int t; + for (t=0; t>=L->last_tag; t--) + if (fn(luaT_getim(t,e))) + return luaT_eventname[e]; + } + return NULL; +} + + +/* +* =================================================================== +* compatibility with old fallback system +*/ +#ifdef LUA_COMPAT2_5 + +#include "lapi.h" + +static void errorFB (void) +{ + lua_Object o = lua_getparam(1); + if (lua_isstring(o)) + fprintf(stderr, "lua: %s\n", lua_getstring(o)); + else + fprintf(stderr, "lua: unknown error\n"); +} + + +static void nilFB (void) { } + + +static void typeFB (void) +{ + lua_error("unexpected type"); +} + + +static void fillvalids (IMS e, TObject *func) +{ + int t; + for (t=LUA_T_NIL; t<=LUA_T_USERDATA; t++) + if (validevent(t, e)) + *luaT_getim(t, e) = *func; +} + + +void luaT_setfallback (void) +{ + static char *oldnames [] = {"error", "getglobal", "arith", "order", NULL}; + TObject oldfunc; + lua_CFunction replace; + char *name = luaL_check_string(1); + lua_Object func = lua_getparam(2); + luaL_arg_check(lua_isfunction(func), 2, "function expected"); + switch (luaL_findstring(name, oldnames)) { + case 0: /* old error fallback */ + oldfunc = L->errorim; + L->errorim = *luaA_Address(func); + replace = errorFB; + break; + case 1: /* old getglobal fallback */ + oldfunc = *luaT_getim(LUA_T_NIL, IM_GETGLOBAL); + *luaT_getim(LUA_T_NIL, IM_GETGLOBAL) = *luaA_Address(func); + replace = nilFB; + break; + case 2: { /* old arith fallback */ + int i; + oldfunc = *luaT_getim(LUA_T_NUMBER, IM_POW); + for (i=IM_ADD; i<=IM_UNM; i++) /* ORDER IM */ + fillvalids(i, luaA_Address(func)); + replace = typeFB; + break; + } + case 3: { /* old order fallback */ + int i; + oldfunc = *luaT_getim(LUA_T_NIL, IM_LT); + for (i=IM_LT; i<=IM_GE; i++) /* ORDER IM */ + fillvalids(i, luaA_Address(func)); + replace = typeFB; + break; + } + default: { + int e; + if ((e = luaL_findstring(name, luaT_eventname)) >= 0) { + oldfunc = *luaT_getim(LUA_T_NIL, e); + fillvalids(e, luaA_Address(func)); + replace = (e == IM_GC || e == IM_INDEX) ? nilFB : typeFB; + } + else { + luaL_verror("`%.50s' is not a valid fallback name", name); + replace = NULL; /* to avoid warnings */ + } + } + } + if (oldfunc.ttype != LUA_T_NIL) + luaA_pushobject(&oldfunc); + else + lua_pushcfunction(replace); +} +#endif + diff --git a/src/ltm.h b/src/ltm.h new file mode 100644 index 0000000..b688d1e --- /dev/null +++ b/src/ltm.h @@ -0,0 +1,62 @@ +/* +** $Id: ltm.h,v 1.4 1997/11/26 18:53:45 roberto Exp $ +** Tag methods +** See Copyright Notice in lua.h +*/ + +#ifndef ltm_h +#define ltm_h + + +#include "lobject.h" +#include "lstate.h" + +/* +* WARNING: if you change the order of this enumeration, +* grep "ORDER IM" +*/ +typedef enum { + IM_GETTABLE = 0, + IM_SETTABLE, + IM_INDEX, + IM_GETGLOBAL, + IM_SETGLOBAL, + IM_ADD, + IM_SUB, + IM_MUL, + IM_DIV, + IM_POW, + IM_UNM, + IM_LT, + IM_LE, + IM_GT, + IM_GE, + IM_CONCAT, + IM_GC, + IM_FUNCTION +} IMS; + +#define IM_N 18 + + +struct IM { + TObject int_method[IM_N]; +}; + + +#define luaT_getim(tag,event) (&L->IMtable[-(tag)].int_method[event]) +#define luaT_getimbyObj(o,e) (luaT_getim(luaT_efectivetag(o),(e))) + +extern char *luaT_eventname[]; + + +void luaT_init (void); +void luaT_realtag (int tag); +int luaT_efectivetag (TObject *o); +void luaT_settagmethod (int t, char *event, TObject *func); +TObject *luaT_gettagmethod (int t, char *event); +char *luaT_travtagmethods (int (*fn)(TObject *)); + +void luaT_setfallback (void); /* only if LUA_COMPAT2_5 */ + +#endif diff --git a/src/lua.stx b/src/lua.stx deleted file mode 100644 index 3a1bf62..0000000 --- a/src/lua.stx +++ /dev/null @@ -1,791 +0,0 @@ -%{ - -char *rcs_luastx = "$Id: lua.stx,v 3.47 1997/06/19 17:46:12 roberto Exp $"; - -#include -#include -#include - -#include "luadebug.h" -#include "luamem.h" -#include "lex.h" -#include "opcode.h" -#include "hash.h" -#include "inout.h" -#include "tree.h" -#include "table.h" -#include "lua.h" -#include "func.h" - -/* to avoid warnings generated by yacc */ -int yyparse (void); -#define malloc luaI_malloc -#define realloc luaI_realloc -#define free luaI_free - -#ifndef LISTING -#define LISTING 0 -#endif - -#ifndef CODE_BLOCK -#define CODE_BLOCK 256 -#endif -static int maxcode; -static int maxmain; -static int maxcurr; -static Byte *funcCode = NULL; -static Byte **initcode; -static Byte *basepc; -static int maincode; -static int pc; - - -#define MAXVAR 32 -static Long varbuffer[MAXVAR]; /* variables in an assignment list; - it's long to store negative Word values */ -static int nvarbuffer=0; /* number of variables at a list */ - -#define MAXLOCALS 32 -static TaggedString *localvar[MAXLOCALS]; /* store local variable names */ -static int nlocalvar=0; /* number of local variables */ - -#define MAXFIELDS FIELDS_PER_FLUSH*2 - -int lua_debug = 0; - -/* Internal functions */ - -static void yyerror (char *s) -{ - luaI_syntaxerror(s); -} - -static void check_space (int i) -{ - if (pc+i>maxcurr-1) /* 1 byte free to code HALT of main code */ - maxcurr = growvector(&basepc, maxcurr, Byte, codeEM, MAX_INT); -} - -static void code_byte (Byte c) -{ - check_space(1); - basepc[pc++] = c; -} - -static void code_word (Word n) -{ - check_space(sizeof(Word)); - memcpy(basepc+pc, &n, sizeof(Word)); - pc += sizeof(Word); -} - -static void code_float (real n) -{ - check_space(sizeof(real)); - memcpy(basepc+pc, &n, sizeof(real)); - pc += sizeof(real); -} - -static void code_code (TFunc *tf) -{ - check_space(sizeof(TFunc *)); - memcpy(basepc+pc, &tf, sizeof(TFunc *)); - pc += sizeof(TFunc *); -} - -static void code_word_at (Byte *p, int n) -{ - Word w = n; - if (w != n) - yyerror("block too big"); - memcpy(p, &w, sizeof(Word)); -} - -static void flush_record (int n) -{ - if (n == 0) return; - code_byte(STOREMAP); - code_byte(n); -} - -static void flush_list (int m, int n) -{ - if (n == 0) return; - if (m == 0) - code_byte(STORELIST0); - else - if (m < 255) - { - code_byte(STORELIST); - code_byte(m); - } - else - yyerror ("list constructor too long"); - code_byte(n); -} - -static void store_localvar (TaggedString *name, int n) -{ - if (nlocalvar+n < MAXLOCALS) - localvar[nlocalvar+n] = name; - else - yyerror ("too many local variables"); - if (lua_debug) - luaI_registerlocalvar(name, lua_linenumber); -} - -static void add_localvar (TaggedString *name) -{ - store_localvar(name, 0); - nlocalvar++; -} - -static void add_varbuffer (Long var) -{ - if (nvarbuffer < MAXVAR) - varbuffer[nvarbuffer++] = var; - else - yyerror ("variable buffer overflow"); -} - -static void code_string (Word w) -{ - code_byte(PUSHSTRING); - code_word(w); -} - -static void code_constant (TaggedString *s) -{ - code_string(luaI_findconstant(s)); -} - -static void code_number (float f) -{ - Word i; - if (f >= 0 && f <= (float)MAX_WORD && (float)(i=(Word)f) == f) { - /* f has an (short) integer value */ - if (i <= 2) code_byte(PUSH0 + i); - else if (i <= 255) - { - code_byte(PUSHBYTE); - code_byte(i); - } - else - { - code_byte(PUSHWORD); - code_word(i); - } - } - else - { - code_byte(PUSHFLOAT); - code_float(f); - } -} - -/* -** Search a local name and if find return its index. If do not find return -1 -*/ -static int lua_localname (TaggedString *n) -{ - int i; - for (i=nlocalvar-1; i >= 0; i--) - if (n == localvar[i]) return i; /* local var */ - return -1; /* global var */ -} - -/* -** Push a variable given a number. If number is positive, push global variable -** indexed by (number -1). If negative, push local indexed by ABS(number)-1. -** Otherwise, if zero, push indexed variable (record). -*/ -static void lua_pushvar (Long number) -{ - if (number > 0) /* global var */ - { - code_byte(PUSHGLOBAL); - code_word(number-1); - } - else if (number < 0) /* local var */ - { - number = (-number) - 1; - if (number < 10) code_byte(PUSHLOCAL0 + number); - else - { - code_byte(PUSHLOCAL); - code_byte(number); - } - } - else - { - code_byte(PUSHINDEXED); - } -} - -static void lua_codeadjust (int n) -{ - if (n+nlocalvar == 0) - code_byte(ADJUST0); - else - { - code_byte(ADJUST); - code_byte(n+nlocalvar); - } -} - -static void change2main (void) -{ - /* (re)store main values */ - pc=maincode; basepc=*initcode; maxcurr=maxmain; - nlocalvar=0; -} - -static void savemain (void) -{ - /* save main values */ - maincode=pc; *initcode=basepc; maxmain=maxcurr; -} - -static void init_func (void) -{ - if (funcCode == NULL) /* first function */ - { - funcCode = newvector(CODE_BLOCK, Byte); - maxcode = CODE_BLOCK; - } - savemain(); /* save main values */ - /* set func values */ - pc=0; basepc=funcCode; maxcurr=maxcode; - nlocalvar = 0; - luaI_codedebugline(lua_linenumber); -} - -static void codereturn (void) -{ - if (nlocalvar == 0) - code_byte(RETCODE0); - else - { - code_byte(RETCODE); - code_byte(nlocalvar); - } -} - -void luaI_codedebugline (int line) -{ - static int lastline = 0; - if (lua_debug && line != lastline) - { - code_byte(SETLINE); - code_word(line); - lastline = line; - } -} - -static int adjust_functioncall (Long exp, int i) -{ - if (exp <= 0) - return -exp; /* exp is -list length */ - else - { - int temp = basepc[exp]; - basepc[exp] = i; - return temp+i; - } -} - -static void adjust_mult_assign (int vars, Long exps, int temps) -{ - if (exps > 0) - { /* must correct function call */ - int diff = vars - basepc[exps]; - if (diff >= 0) - adjust_functioncall(exps, diff); - else - { - adjust_functioncall(exps, 0); - lua_codeadjust(temps); - } - } - else if (vars != -exps) - lua_codeadjust(temps); -} - -static int close_parlist (int dots) -{ - if (!dots) - lua_codeadjust(0); - else - { - code_byte(VARARGS); - code_byte(nlocalvar); - add_localvar(luaI_createfixedstring("arg")); - } - return lua_linenumber; -} - -static void storesinglevar (Long v) -{ - if (v > 0) /* global var */ - { - code_byte(STOREGLOBAL); - code_word(v-1); - } - else if (v < 0) /* local var */ - { - int number = (-v) - 1; - if (number < 10) code_byte(STORELOCAL0 + number); - else - { - code_byte(STORELOCAL); - code_byte(number); - } - } - else - code_byte(STOREINDEXED0); -} - -static void lua_codestore (int i) -{ - if (varbuffer[i] != 0) /* global or local var */ - storesinglevar(varbuffer[i]); - else /* indexed var */ - { - int j; - int upper=0; /* number of indexed variables upper */ - int param; /* number of itens until indexed expression */ - for (j=i+1; j code); - *initcode = newvector(CODE_BLOCK, Byte); - maincode = 0; - maxmain = CODE_BLOCK; - change2main(); - if (yyparse ()) lua_error("parse error"); - savemain(); - (*initcode)[maincode++] = RETCODE0; - tf->size = maincode; -#if LISTING -{ static void PrintCode (Byte *c, Byte *end); - PrintCode(*initcode,*initcode+maincode); } -#endif -} - - -%} - - -%union -{ - int vInt; - float vFloat; - char *pChar; - Word vWord; - Long vLong; - TFunc *pFunc; - TaggedString *pTStr; -} - -%start chunk - -%token WRONGTOKEN -%token NIL -%token IF THEN ELSE ELSEIF WHILE DO REPEAT UNTIL END -%token RETURN -%token LOCAL -%token FUNCTION -%token DOTS -%token NUMBER -%token STRING -%token NAME - -%type PrepJump -%type exprlist, exprlist1 /* if > 0, points to function return - counter (which has list length); if <= 0, -list lenght */ -%type functioncall, expr /* if != 0, points to function return - counter */ -%type varlist1, funcParams, funcvalue -%type fieldlist, localdeclist, decinit -%type ffieldlist, ffieldlist1, semicolonpart -%type lfieldlist, lfieldlist1 -%type parlist, parlist1, par -%type var, singlevar, funcname -%type body - -%left AND OR -%left EQ NE '>' '<' LE GE -%left CONC -%left '+' '-' -%left '*' '/' -%left UNARY NOT -%right '^' - - -%% /* beginning of rules section */ - -chunk : chunklist ret ; - -chunklist : /* empty */ - | chunklist stat sc - | chunklist function - ; - -function : FUNCTION funcname body - { - code_byte(PUSHFUNCTION); - code_code($3); - storesinglevar($2); - } - ; - -funcname : var { $$ =$1; init_func(); } - | varexp ':' NAME - { - code_constant($3); - $$ = 0; /* indexed variable */ - init_func(); - add_localvar(luaI_createfixedstring("self")); - } - ; - -body : '(' parlist ')' block END - { - codereturn(); - $$ = new(TFunc); - luaI_initTFunc($$); - $$->size = pc; - $$->code = newvector(pc, Byte); - $$->lineDefined = $2; - memcpy($$->code, basepc, pc*sizeof(Byte)); - if (lua_debug) - luaI_closelocalvars($$); - /* save func values */ - funcCode = basepc; maxcode=maxcurr; -#if LISTING - PrintCode(funcCode,funcCode+pc); -#endif - change2main(); /* change back to main code */ - } - ; - -statlist : /* empty */ - | statlist stat sc - ; - -sc : /* empty */ | ';' ; - -stat : IF expr1 THEN PrepJump block PrepJump elsepart END - { codeIf($4, $6); } - - | WHILE {$$=pc;} expr1 DO PrepJump block PrepJump END - { - basepc[$5] = IFFJMP; - code_word_at(basepc+$5+1, pc - ($5 + sizeof(Word)+1)); - basepc[$7] = UPJMP; - code_word_at(basepc+$7+1, pc - ($2)); - } - - | REPEAT {$$=pc;} block UNTIL expr1 PrepJump - { - basepc[$6] = IFFUPJMP; - code_word_at(basepc+$6+1, pc - ($2)); - } - - | varlist1 '=' exprlist1 - { - { - int i; - adjust_mult_assign(nvarbuffer, $3, $1 * 2 + nvarbuffer); - for (i=nvarbuffer-1; i>=0; i--) - lua_codestore (i); - if ($1 > 1 || ($1 == 1 && varbuffer[0] != 0)) - lua_codeadjust (0); - } - } - | functioncall {;} - | LOCAL localdeclist decinit - { nlocalvar += $2; - adjust_mult_assign($2, $3, 0); - } - ; - -elsepart : /* empty */ - | ELSE block - | ELSEIF expr1 THEN PrepJump block PrepJump elsepart - { codeIf($4, $6); } - ; - -block : {$$ = nlocalvar;} statlist ret - { - if (nlocalvar != $1) - { - if (lua_debug) - for (; nlocalvar > $1; nlocalvar--) - luaI_unregisterlocalvar(lua_linenumber); - else - nlocalvar = $1; - lua_codeadjust (0); - } - } - ; - -ret : /* empty */ - | RETURN exprlist sc - { - adjust_functioncall($2, MULT_RET); - codereturn(); - } - ; - -PrepJump : /* empty */ - { - $$ = pc; - code_byte(0); /* open space */ - code_word (0); - } - ; - -expr1 : expr { adjust_functioncall($1, 1); } - ; - -expr : '(' expr ')' { $$ = $2; } - | expr1 EQ expr1 { code_byte(EQOP); $$ = 0; } - | expr1 '<' expr1 { code_byte(LTOP); $$ = 0; } - | expr1 '>' expr1 { code_byte(GTOP); $$ = 0; } - | expr1 NE expr1 { code_byte(EQOP); code_byte(NOTOP); $$ = 0; } - | expr1 LE expr1 { code_byte(LEOP); $$ = 0; } - | expr1 GE expr1 { code_byte(GEOP); $$ = 0; } - | expr1 '+' expr1 { code_byte(ADDOP); $$ = 0; } - | expr1 '-' expr1 { code_byte(SUBOP); $$ = 0; } - | expr1 '*' expr1 { code_byte(MULTOP); $$ = 0; } - | expr1 '/' expr1 { code_byte(DIVOP); $$ = 0; } - | expr1 '^' expr1 { code_byte(POWOP); $$ = 0; } - | expr1 CONC expr1 { code_byte(CONCOP); $$ = 0; } - | '-' expr1 %prec UNARY { code_byte(MINUSOP); $$ = 0;} - | table { $$ = 0; } - | varexp { $$ = 0;} - | NUMBER { code_number($1); $$ = 0; } - | STRING - { - code_string($1); - $$ = 0; - } - | NIL {code_byte(PUSHNIL); $$ = 0; } - | functioncall { $$ = $1; } - | NOT expr1 { code_byte(NOTOP); $$ = 0;} - | expr1 AND PrepJump {code_byte(POP); } expr1 - { - basepc[$3] = ONFJMP; - code_word_at(basepc+$3+1, pc - ($3 + sizeof(Word)+1)); - $$ = 0; - } - | expr1 OR PrepJump {code_byte(POP); } expr1 - { - basepc[$3] = ONTJMP; - code_word_at(basepc+$3+1, pc - ($3 + sizeof(Word)+1)); - $$ = 0; - } - ; - -table : - { - code_byte(CREATEARRAY); - $$ = pc; code_word(0); - } - '{' fieldlist '}' - { - code_word_at(basepc+$1, $3); - } - ; - -functioncall : funcvalue funcParams - { - code_byte(CALLFUNC); - code_byte($1+$2); - $$ = pc; - code_byte(0); /* may be modified by other rules */ - } - ; - -funcvalue : varexp { $$ = 0; } - | varexp ':' NAME - { - code_byte(PUSHSELF); - code_word(luaI_findconstant($3)); - $$ = 1; - } - ; - -funcParams : '(' exprlist ')' - { $$ = adjust_functioncall($2, 1); } - | table { $$ = 1; } - ; - -exprlist : /* empty */ { $$ = 0; } - | exprlist1 { $$ = $1; } - ; - -exprlist1 : expr { if ($1 != 0) $$ = $1; else $$ = -1; } - | exprlist1 ',' { $$ = adjust_functioncall($1, 1); } expr - { - if ($4 == 0) $$ = -($3 + 1); /* -length */ - else - { - adjust_functioncall($4, $3); - $$ = $4; - } - } - ; - -parlist : /* empty */ { $$ = close_parlist(0); } - | parlist1 { $$ = close_parlist($1); } - ; - -parlist1 : par { $$ = $1; } - | parlist1 ',' par - { - if ($1) - lua_error("invalid parameter list"); - $$ = $3; - } - ; - -par : NAME { add_localvar($1); $$ = 0; } - | DOTS { $$ = 1; } - ; - -fieldlist : lfieldlist - { flush_list($1/FIELDS_PER_FLUSH, $1%FIELDS_PER_FLUSH); } - semicolonpart - { $$ = $1+$3; } - | ffieldlist1 lastcomma - { $$ = $1; flush_record($1%FIELDS_PER_FLUSH); } - ; - -semicolonpart : /* empty */ - { $$ = 0; } - | ';' ffieldlist - { $$ = $2; flush_record($2%FIELDS_PER_FLUSH); } - ; - -lastcomma : /* empty */ - | ',' - ; - -ffieldlist : /* empty */ { $$ = 0; } - | ffieldlist1 lastcomma { $$ = $1; } - ; - -ffieldlist1 : ffield {$$=1;} - | ffieldlist1 ',' ffield - { - $$=$1+1; - if ($$%FIELDS_PER_FLUSH == 0) flush_record(FIELDS_PER_FLUSH); - } - ; - -ffield : ffieldkey '=' expr1 - ; - -ffieldkey : '[' expr1 ']' - | NAME { code_constant($1); } - ; - -lfieldlist : /* empty */ { $$ = 0; } - | lfieldlist1 lastcomma { $$ = $1; } - ; - -lfieldlist1 : expr1 {$$=1;} - | lfieldlist1 ',' expr1 - { - $$=$1+1; - if ($$%FIELDS_PER_FLUSH == 0) - flush_list($$/FIELDS_PER_FLUSH - 1, FIELDS_PER_FLUSH); - } - ; - -varlist1 : var - { - nvarbuffer = 0; - add_varbuffer($1); - $$ = ($1 == 0) ? 1 : 0; - } - | varlist1 ',' var - { - add_varbuffer($3); - $$ = ($3 == 0) ? $1 + 1 : $1; - } - ; - -var : singlevar { $$ = $1; } - | varexp '[' expr1 ']' - { - $$ = 0; /* indexed variable */ - } - | varexp '.' NAME - { - code_constant($3); - $$ = 0; /* indexed variable */ - } - ; - -singlevar : NAME - { - int local = lua_localname($1); - if (local == -1) /* global var */ - $$ = luaI_findsymbol($1)+1; /* return positive value */ - else - $$ = -(local+1); /* return negative value */ - } - ; - -varexp : var { lua_pushvar($1); } - ; - -localdeclist : NAME {store_localvar($1, 0); $$ = 1;} - | localdeclist ',' NAME - { - store_localvar($3, $1); - $$ = $1+1; - } - ; - -decinit : /* empty */ { $$ = 0; } - | '=' exprlist1 { $$ = $2; } - ; - -%% diff --git a/clients/lua/Makefile b/src/lua/Makefile similarity index 68% rename from clients/lua/Makefile rename to src/lua/Makefile index 7ce90fa..1ec8370 100644 --- a/clients/lua/Makefile +++ b/src/lua/Makefile @@ -9,22 +9,24 @@ EXTRA_DEFS= $(POSIX) OBJS= lua.o SRCS= lua.c -T=$(BIN)/lua +T= $(BIN)/lua all: $T $T: $(OBJS) $(LIB)/liblua.a $(LIB)/liblualib.a $(CC) -o $@ $(OBJS) -L$(LIB) -llua -llualib -lm -dynamic: - rm -f $T - make +$(LIB)/liblua.a: + cd ..; make + +$(LIB)/liblualib.a: + cd ../lib; make clean: - rm -f $T $(OBJS) + rm -f $(OBJS) $T co: - co -f -M $(SRCS) + co -q -f -M $(SRCS) klean: clean rm -f $(SRCS) diff --git a/src/lua/README b/src/lua/README new file mode 100644 index 0000000..3134042 --- /dev/null +++ b/src/lua/README @@ -0,0 +1,20 @@ +This client is a sample lua interpreter. +It can be used as a batch interpreter and interactively. +Here are the options it understands: + + -v print version information + -d turn debug on + -e stat dostring `stat' + -q interactive mode without prompt + -i interactive mode with prompt + - executes stdin as a file + a=b sets global `a' with string `b' (no need to quote b) + name dofile `name' + +If no options are given, then it reads and executes lines from stdin. +In this case, each line must contain a complete statement. +To span a statement across several lines, end each line with a backslash '\'. +To change the prompt, set the global variable _PROMPT to whatever you want. + +This interpreter is good for using Lua as a standalone language. +For a minimal interpreter, see etc/min.c. diff --git a/src/lua/lua.c b/src/lua/lua.c new file mode 100644 index 0000000..a6a92f7 --- /dev/null +++ b/src/lua/lua.c @@ -0,0 +1,194 @@ +/* +** $Id: lua.c,v 1.14 1998/02/11 20:56:05 roberto Exp $ +** Lua stand-alone interpreter +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include +#include + +#include "lua.h" +#include "luadebug.h" +#include "lualib.h" + + +#ifndef OLD_ANSI +#include +#else +#define setlocale(a,b) 0 +#endif + +#ifdef _POSIX_SOURCE +#include +#else +#define isatty(x) (x==0) /* assume stdin is a tty */ +#endif + + +typedef void (*handler)(int); /* type for signal actions */ + +static void laction (int i); + +static handler lreset (void) +{ + lua_linehook = NULL; + lua_callhook = NULL; + return signal(SIGINT, laction); +} + +static void lstop (void) +{ + lreset(); + lua_error("interrupted!"); +} + +static void laction (int i) +{ + lua_linehook = (lua_LHFunction)lstop; + lua_callhook = (lua_CHFunction)lstop; +} + +static int ldo (int (*f)(char *), char *name) +{ + int res; + handler h = lreset(); + res = f(name); /* dostring | dofile */ + signal(SIGINT, h); /* restore old action */ + return res; +} + + +static void print_message (void) +{ + fprintf(stderr, +"Lua: command line options:\n" +" -v print version information\n" +" -d turn debug on\n" +" -e stat dostring `stat'\n" +" -q interactive mode without prompt\n" +" -i interactive mode with prompt\n" +" - executes stdin as a file\n" +" a=b sets global `a' with string `b'\n" +" name dofile `name'\n\n"); +} + + +static void assign (char *arg) +{ + if (strlen(arg) >= 500) + fprintf(stderr, "lua: shell argument too long"); + else { + char buffer[500]; + char *eq = strchr(arg, '='); + lua_pushstring(eq+1); + strncpy(buffer, arg, eq-arg); + buffer[eq-arg] = 0; + lua_setglobal(buffer); + } +} + +#define BUF_SIZE 512 + +static void manual_input (int prompt) +{ + int cont = 1; + while (cont) { + char buffer[BUF_SIZE]; + int i = 0; + lua_beginblock(); + if (prompt) + printf("%s", lua_getstring(lua_getglobal("_PROMPT"))); + for(;;) { + int c = getchar(); + if (c == EOF) { + cont = 0; + break; + } + else if (c == '\n') { + if (i>0 && buffer[i-1] == '\\') + buffer[i-1] = '\n'; + else break; + } + else if (i >= BUF_SIZE-1) { + fprintf(stderr, "lua: argument line too long\n"); + break; + } + else buffer[i++] = c; + } + buffer[i] = 0; + ldo(lua_dostring, buffer); + lua_endblock(); + } + printf("\n"); +} + + +int main (int argc, char *argv[]) +{ + int i; + setlocale(LC_ALL, ""); + lua_iolibopen(); + lua_strlibopen(); + lua_mathlibopen(); + lua_pushstring("> "); lua_setglobal("_PROMPT"); + if (argc < 2) { /* no arguments? */ + if (isatty(0)) { + printf("%s %s\n", LUA_VERSION, LUA_COPYRIGHT); + manual_input(1); + } + else + ldo(lua_dofile, NULL); /* executes stdin as a file */ + } + else for (i=1; iu.s.globalval.ttype=LUA_T_NUMBER; + s->u.s.globalval.value.n=1; + } else if (IS("-d")) /* debug */ - lua_debug=1; + debugging=1; else if (IS("-l")) /* list */ listing=1; else if (IS("-o")) /* output file */ d=argv[++i]; - else if (IS("-p")) /* parse only (for timing purposes) */ + else if (IS("-O")) /* optimize */ + optimizing=1; + else if (IS("-p")) /* parse only */ + { dumping=0; + parsing=1; + } else if (IS("-q")) /* quiet */ listing=0; else if (IS("-u")) /* undump */ @@ -71,120 +97,88 @@ int main(int argc, char* argv[]) } else if (IS("-v")) /* show version */ printf("%s %s\n(written by %s)\n\n",LUA_VERSION,LUA_COPYRIGHT,LUA_AUTHORS); + else if (IS("-V")) /* verbose */ + verbose=1; else /* unknown option */ usage(); } --i; /* fake new argv[0] */ argc-=i; argv+=i; - if (dumping) + if (dumping || parsing) { if (argc<2) usage(); - for (i=1; inext) PrintFunction(tf,Main); - } - if (dumping) - { - DumpHeader(D); - for (tf=Main; tf!=NULL; tf=tf->next) DumpFunction(tf,D); - } - for (tf=Main; tf!=NULL; ) - { - TFunc* nf=tf->next; - luaI_freefunc(tf); - tf=nf; - } -} - static void do_compile(ZIO* z) { - TFunc* tf=new(TFunc); - lua_setinput(z); - luaI_initTFunc(tf); - tf->fileName=lua_parsedfile; - lua_parse(tf); - do_dump(tf); + TProtoFunc* Main; + if (optimizing) lua_debug=0; /* set debugging before parsing */ + if (debugging) lua_debug=1; + Main=luaY_parser(z); + if (optimizing) OptChunk(Main); + if (listing) PrintChunk(Main); + if (dumping) DumpChunk(Main,D); } -static void compile(char* filename) +static void do_undump(ZIO* z) { - FILE* f= (filename==NULL) ? stdin : fopen(filename, "r"); - if (f==NULL) - { - fprintf(stderr,"luac: cannot open "); - perror(filename); - exit(1); - } - else + while (1) { - ZIO z; - zFopen(&z,f); - luaI_setparsedfile(filename?filename:"(stdin)"); - do_compile(&z); - fclose(f); + TProtoFunc* Main=luaU_undump1(z); + if (Main==NULL) break; + if (optimizing) OptChunk(Main); + if (listing) PrintChunk(Main); } } -static void do_undump(ZIO* z) +static void doit(int undump, char* filename) { - TFunc* Main; - while ((Main=luaI_undump1(z))) + FILE* f; + ZIO z; + if (filename==NULL) { - if (listing) - { - TFunc* tf; - for (tf=Main; tf!=NULL; tf=tf->next) - PrintFunction(tf,Main); - } - luaI_freefunc(Main); /* TODO: free others */ + f=stdin; filename="(stdin)"; + } + else + { + f=efopen(filename, undump ? "rb" : "r"); } + zFopen(&z,f,filename); + if (verbose) fprintf(stderr,"%s\n",filename); + if (undump) do_undump(&z); else do_compile(&z); + if (f!=stdin) fclose(f); } -static void undump(char* filename) +static FILE* efopen(char* name, char* mode) { - FILE* f= (filename==NULL) ? stdin : fopen(filename, "rb"); + FILE* f=fopen(name,mode); if (f==NULL) { - fprintf(stderr,"luac: cannot open "); - perror(filename); + fprintf(stderr,"luac: cannot open %sput file ",mode[0]=='r' ? "in" : "out"); + perror(name); exit(1); } - else - { - ZIO z; - zFopen(&z,f); - do_undump(&z); - fclose(f); - } + return f; } diff --git a/src/luac/luac.h b/src/luac/luac.h dissimilarity index 98% index 815824c..c3d8d73 100644 --- a/src/luac/luac.h +++ b/src/luac/luac.h @@ -1,25 +1,33 @@ -/* -** luac.h -** definitions for luac compiler -** $Id: luac.h,v 1.8 1997/06/19 17:32:08 lhf Exp $ -*/ - -#include "inout.h" -#include "luamem.h" -#include "opcode.h" -#include "table.h" -#include "undump.h" - -#define VarStr(i) (lua_table[i].varname->str) -#define VarLoc(i) (lua_table[i].varname->u.s.varindex) -#define StrStr(i) (lua_constant[i]->str) -#define StrLoc(i) (lua_constant[i]->u.s.constindex) - -extern Word lua_ntable; -extern Word lua_nconstant; -extern int lua_debug; - -void LinkFunctions(TFunc* tf); -void PrintFunction(TFunc* tf, TFunc* Main); -void DumpHeader(FILE* D); -void DumpFunction(TFunc* tf, FILE* D); +/* +** $Id: luac.h,v 1.6 1998/07/12 00:17:37 lhf Exp $ +** definitions for luac +** See Copyright Notice in lua.h +*/ + +#include "lauxlib.h" +#include "lfunc.h" +#include "lobject.h" +#include "lopcodes.h" +#include "lstring.h" +#include "lundump.h" + +typedef struct +{ + char* name; + int size; + int op; + int class; + int arg; + int arg2; +} Opcode; + +int OpcodeInfo(TProtoFunc* tf, Byte* p, Opcode* I, char* xFILE, int xLINE); +int CodeSize(TProtoFunc* tf); + +#define INFO(tf,p,I) OpcodeInfo(tf,p,I,__FILE__,__LINE__) +#define fileName(tf) ( (tf->fileName)==NULL ? NULL : tf->fileName->str ) + +#define NOP 255 +#define STACK -1 +#define ARGS -2 +#define VARARGS -3 diff --git a/src/luac/opcode.c b/src/luac/opcode.c new file mode 100644 index 0000000..c97e46a --- /dev/null +++ b/src/luac/opcode.c @@ -0,0 +1,87 @@ +/* +** $Id: opcode.c,v 1.4 1998/07/12 00:17:37 lhf Exp $ +** opcode information +** See Copyright Notice in lua.h +*/ + +#include "luac.h" + +static Opcode Info[]= /* ORDER lopcodes.h */ +{ +#include "opcode.h" +}; + +#define NOPCODES (sizeof(Info)/sizeof(Info[0])) + +int OpcodeInfo(TProtoFunc* tf, Byte* p, Opcode* I, char* xFILE, int xLINE) +{ + Opcode OP; + Byte* code=tf->code; + int op=*p; + if (p==code) + { + OP.name="STACK"; + OP.size=1; + OP.op=STACK; + OP.class=STACK; + OP.arg=op; + } + else if (p==code+1) + { + OP.size=1; + if (op>=ZEROVARARG) + { + OP.name="VARARGS"; + OP.op=VARARGS; + OP.class=VARARGS; + OP.arg=op-ZEROVARARG; + } + else + { + OP.name="ARGS"; + OP.op=ARGS; + OP.class=ARGS; + OP.arg=op; + } + } + else if (op==NOP) + { + OP.name="NOP"; + OP.size=1; + OP.op=NOP; + OP.class=NOP; + } + else if (op>=NOPCODES) /* cannot happen */ + { + luaL_verror("internal error at %s:%d: bad opcode %d at %d in tf=%p", + xFILE, xLINE,op,(int)(p-code),tf); + return 0; + } + else + { + OP=Info[op]; + if (op==SETLIST || op==CLOSURE || op==CALLFUNC) + { + OP.arg=p[1]; + OP.arg2=p[2]; + } + else if (OP.size==2) OP.arg=p[1]; + else if (OP.size>=3) OP.arg=(p[1]<<8)+p[2]; + if (op==SETLISTW || op==CLOSUREW) OP.arg2=p[3]; + } + *I=OP; + return OP.size; +} + +int CodeSize(TProtoFunc* tf) +{ + Byte* code=tf->code; + Byte* p=code; + while (1) + { + Opcode OP; + p+=INFO(tf,p,&OP); + if (OP.op==ENDCODE) break; + } + return p-code; +} diff --git a/src/luac/opcode.h b/src/luac/opcode.h new file mode 100644 index 0000000..805933c --- /dev/null +++ b/src/luac/opcode.h @@ -0,0 +1,134 @@ +/* +** $Id: opcode.h,v 1.3 1998/06/25 15:50:09 lhf Exp $ +** opcode info to be #included into opcode.c +** extracted automatically from lopcodes.h by mkopcodeh +** See Copyright Notice in lua.h +*/ +{ "ENDCODE", 1, ENDCODE, ENDCODE, ENDCODE-ENDCODE-1, 0 }, +{ "PUSHNIL", 2, PUSHNIL, PUSHNIL, PUSHNIL-PUSHNIL-1, 0 }, +{ "PUSHNIL0", 1, PUSHNIL0, PUSHNIL, PUSHNIL0-PUSHNIL-1, 0 }, +{ "PUSHNUMBER", 2, PUSHNUMBER, PUSHNUMBER, PUSHNUMBER-PUSHNUMBER-1, 0 }, +{ "PUSHNUMBER0", 1, PUSHNUMBER0, PUSHNUMBER, PUSHNUMBER0-PUSHNUMBER-1, 0 }, +{ "PUSHNUMBER1", 1, PUSHNUMBER1, PUSHNUMBER, PUSHNUMBER1-PUSHNUMBER-1, 0 }, +{ "PUSHNUMBER2", 1, PUSHNUMBER2, PUSHNUMBER, PUSHNUMBER2-PUSHNUMBER-1, 0 }, +{ "PUSHNUMBERW", 3, PUSHNUMBERW, PUSHNUMBER, PUSHNUMBERW-PUSHNUMBER-1, 0 }, +{ "PUSHCONSTANT", 2, PUSHCONSTANT, PUSHCONSTANT, PUSHCONSTANT-PUSHCONSTANT-1, 0 }, +{ "PUSHCONSTANT0", 1, PUSHCONSTANT0, PUSHCONSTANT, PUSHCONSTANT0-PUSHCONSTANT-1, 0 }, +{ "PUSHCONSTANT1", 1, PUSHCONSTANT1, PUSHCONSTANT, PUSHCONSTANT1-PUSHCONSTANT-1, 0 }, +{ "PUSHCONSTANT2", 1, PUSHCONSTANT2, PUSHCONSTANT, PUSHCONSTANT2-PUSHCONSTANT-1, 0 }, +{ "PUSHCONSTANT3", 1, PUSHCONSTANT3, PUSHCONSTANT, PUSHCONSTANT3-PUSHCONSTANT-1, 0 }, +{ "PUSHCONSTANT4", 1, PUSHCONSTANT4, PUSHCONSTANT, PUSHCONSTANT4-PUSHCONSTANT-1, 0 }, +{ "PUSHCONSTANT5", 1, PUSHCONSTANT5, PUSHCONSTANT, PUSHCONSTANT5-PUSHCONSTANT-1, 0 }, +{ "PUSHCONSTANT6", 1, PUSHCONSTANT6, PUSHCONSTANT, PUSHCONSTANT6-PUSHCONSTANT-1, 0 }, +{ "PUSHCONSTANT7", 1, PUSHCONSTANT7, PUSHCONSTANT, PUSHCONSTANT7-PUSHCONSTANT-1, 0 }, +{ "PUSHCONSTANTW", 3, PUSHCONSTANTW, PUSHCONSTANT, PUSHCONSTANTW-PUSHCONSTANT-1, 0 }, +{ "PUSHUPVALUE", 2, PUSHUPVALUE, PUSHUPVALUE, PUSHUPVALUE-PUSHUPVALUE-1, 0 }, +{ "PUSHUPVALUE0", 1, PUSHUPVALUE0, PUSHUPVALUE, PUSHUPVALUE0-PUSHUPVALUE-1, 0 }, +{ "PUSHUPVALUE1", 1, PUSHUPVALUE1, PUSHUPVALUE, PUSHUPVALUE1-PUSHUPVALUE-1, 0 }, +{ "PUSHLOCAL", 2, PUSHLOCAL, PUSHLOCAL, PUSHLOCAL-PUSHLOCAL-1, 0 }, +{ "PUSHLOCAL0", 1, PUSHLOCAL0, PUSHLOCAL, PUSHLOCAL0-PUSHLOCAL-1, 0 }, +{ "PUSHLOCAL1", 1, PUSHLOCAL1, PUSHLOCAL, PUSHLOCAL1-PUSHLOCAL-1, 0 }, +{ "PUSHLOCAL2", 1, PUSHLOCAL2, PUSHLOCAL, PUSHLOCAL2-PUSHLOCAL-1, 0 }, +{ "PUSHLOCAL3", 1, PUSHLOCAL3, PUSHLOCAL, PUSHLOCAL3-PUSHLOCAL-1, 0 }, +{ "PUSHLOCAL4", 1, PUSHLOCAL4, PUSHLOCAL, PUSHLOCAL4-PUSHLOCAL-1, 0 }, +{ "PUSHLOCAL5", 1, PUSHLOCAL5, PUSHLOCAL, PUSHLOCAL5-PUSHLOCAL-1, 0 }, +{ "PUSHLOCAL6", 1, PUSHLOCAL6, PUSHLOCAL, PUSHLOCAL6-PUSHLOCAL-1, 0 }, +{ "PUSHLOCAL7", 1, PUSHLOCAL7, PUSHLOCAL, PUSHLOCAL7-PUSHLOCAL-1, 0 }, +{ "GETGLOBAL", 2, GETGLOBAL, GETGLOBAL, GETGLOBAL-GETGLOBAL-1, 0 }, +{ "GETGLOBAL0", 1, GETGLOBAL0, GETGLOBAL, GETGLOBAL0-GETGLOBAL-1, 0 }, +{ "GETGLOBAL1", 1, GETGLOBAL1, GETGLOBAL, GETGLOBAL1-GETGLOBAL-1, 0 }, +{ "GETGLOBAL2", 1, GETGLOBAL2, GETGLOBAL, GETGLOBAL2-GETGLOBAL-1, 0 }, +{ "GETGLOBAL3", 1, GETGLOBAL3, GETGLOBAL, GETGLOBAL3-GETGLOBAL-1, 0 }, +{ "GETGLOBAL4", 1, GETGLOBAL4, GETGLOBAL, GETGLOBAL4-GETGLOBAL-1, 0 }, +{ "GETGLOBAL5", 1, GETGLOBAL5, GETGLOBAL, GETGLOBAL5-GETGLOBAL-1, 0 }, +{ "GETGLOBAL6", 1, GETGLOBAL6, GETGLOBAL, GETGLOBAL6-GETGLOBAL-1, 0 }, +{ "GETGLOBAL7", 1, GETGLOBAL7, GETGLOBAL, GETGLOBAL7-GETGLOBAL-1, 0 }, +{ "GETGLOBALW", 3, GETGLOBALW, GETGLOBAL, GETGLOBALW-GETGLOBAL-1, 0 }, +{ "GETTABLE", 1, GETTABLE, GETTABLE, GETTABLE-GETTABLE-1, 0 }, +{ "GETDOTTED", 2, GETDOTTED, GETDOTTED, GETDOTTED-GETDOTTED-1, 0 }, +{ "GETDOTTED0", 1, GETDOTTED0, GETDOTTED, GETDOTTED0-GETDOTTED-1, 0 }, +{ "GETDOTTED1", 1, GETDOTTED1, GETDOTTED, GETDOTTED1-GETDOTTED-1, 0 }, +{ "GETDOTTED2", 1, GETDOTTED2, GETDOTTED, GETDOTTED2-GETDOTTED-1, 0 }, +{ "GETDOTTED3", 1, GETDOTTED3, GETDOTTED, GETDOTTED3-GETDOTTED-1, 0 }, +{ "GETDOTTED4", 1, GETDOTTED4, GETDOTTED, GETDOTTED4-GETDOTTED-1, 0 }, +{ "GETDOTTED5", 1, GETDOTTED5, GETDOTTED, GETDOTTED5-GETDOTTED-1, 0 }, +{ "GETDOTTED6", 1, GETDOTTED6, GETDOTTED, GETDOTTED6-GETDOTTED-1, 0 }, +{ "GETDOTTED7", 1, GETDOTTED7, GETDOTTED, GETDOTTED7-GETDOTTED-1, 0 }, +{ "GETDOTTEDW", 3, GETDOTTEDW, GETDOTTED, GETDOTTEDW-GETDOTTED-1, 0 }, +{ "PUSHSELF", 2, PUSHSELF, PUSHSELF, PUSHSELF-PUSHSELF-1, 0 }, +{ "PUSHSELF0", 1, PUSHSELF0, PUSHSELF, PUSHSELF0-PUSHSELF-1, 0 }, +{ "PUSHSELF1", 1, PUSHSELF1, PUSHSELF, PUSHSELF1-PUSHSELF-1, 0 }, +{ "PUSHSELF2", 1, PUSHSELF2, PUSHSELF, PUSHSELF2-PUSHSELF-1, 0 }, +{ "PUSHSELF3", 1, PUSHSELF3, PUSHSELF, PUSHSELF3-PUSHSELF-1, 0 }, +{ "PUSHSELF4", 1, PUSHSELF4, PUSHSELF, PUSHSELF4-PUSHSELF-1, 0 }, +{ "PUSHSELF5", 1, PUSHSELF5, PUSHSELF, PUSHSELF5-PUSHSELF-1, 0 }, +{ "PUSHSELF6", 1, PUSHSELF6, PUSHSELF, PUSHSELF6-PUSHSELF-1, 0 }, +{ "PUSHSELF7", 1, PUSHSELF7, PUSHSELF, PUSHSELF7-PUSHSELF-1, 0 }, +{ "PUSHSELFW", 3, PUSHSELFW, PUSHSELF, PUSHSELFW-PUSHSELF-1, 0 }, +{ "CREATEARRAY", 2, CREATEARRAY, CREATEARRAY, CREATEARRAY-CREATEARRAY-1, 0 }, +{ "CREATEARRAY0", 1, CREATEARRAY0, CREATEARRAY, CREATEARRAY0-CREATEARRAY-1, 0 }, +{ "CREATEARRAY1", 1, CREATEARRAY1, CREATEARRAY, CREATEARRAY1-CREATEARRAY-1, 0 }, +{ "CREATEARRAYW", 3, CREATEARRAYW, CREATEARRAY, CREATEARRAYW-CREATEARRAY-1, 0 }, +{ "SETLOCAL", 2, SETLOCAL, SETLOCAL, SETLOCAL-SETLOCAL-1, 0 }, +{ "SETLOCAL0", 1, SETLOCAL0, SETLOCAL, SETLOCAL0-SETLOCAL-1, 0 }, +{ "SETLOCAL1", 1, SETLOCAL1, SETLOCAL, SETLOCAL1-SETLOCAL-1, 0 }, +{ "SETLOCAL2", 1, SETLOCAL2, SETLOCAL, SETLOCAL2-SETLOCAL-1, 0 }, +{ "SETLOCAL3", 1, SETLOCAL3, SETLOCAL, SETLOCAL3-SETLOCAL-1, 0 }, +{ "SETLOCAL4", 1, SETLOCAL4, SETLOCAL, SETLOCAL4-SETLOCAL-1, 0 }, +{ "SETLOCAL5", 1, SETLOCAL5, SETLOCAL, SETLOCAL5-SETLOCAL-1, 0 }, +{ "SETLOCAL6", 1, SETLOCAL6, SETLOCAL, SETLOCAL6-SETLOCAL-1, 0 }, +{ "SETLOCAL7", 1, SETLOCAL7, SETLOCAL, SETLOCAL7-SETLOCAL-1, 0 }, +{ "SETGLOBAL", 2, SETGLOBAL, SETGLOBAL, SETGLOBAL-SETGLOBAL-1, 0 }, +{ "SETGLOBAL0", 1, SETGLOBAL0, SETGLOBAL, SETGLOBAL0-SETGLOBAL-1, 0 }, +{ "SETGLOBAL1", 1, SETGLOBAL1, SETGLOBAL, SETGLOBAL1-SETGLOBAL-1, 0 }, +{ "SETGLOBAL2", 1, SETGLOBAL2, SETGLOBAL, SETGLOBAL2-SETGLOBAL-1, 0 }, +{ "SETGLOBAL3", 1, SETGLOBAL3, SETGLOBAL, SETGLOBAL3-SETGLOBAL-1, 0 }, +{ "SETGLOBAL4", 1, SETGLOBAL4, SETGLOBAL, SETGLOBAL4-SETGLOBAL-1, 0 }, +{ "SETGLOBAL5", 1, SETGLOBAL5, SETGLOBAL, SETGLOBAL5-SETGLOBAL-1, 0 }, +{ "SETGLOBAL6", 1, SETGLOBAL6, SETGLOBAL, SETGLOBAL6-SETGLOBAL-1, 0 }, +{ "SETGLOBAL7", 1, SETGLOBAL7, SETGLOBAL, SETGLOBAL7-SETGLOBAL-1, 0 }, +{ "SETGLOBALW", 3, SETGLOBALW, SETGLOBAL, SETGLOBALW-SETGLOBAL-1, 0 }, +{ "SETTABLE0", 1, SETTABLE0, SETTABLE0, SETTABLE0-SETTABLE0-1, 0 }, +{ "SETTABLE", 2, SETTABLE, SETTABLE, SETTABLE-SETTABLE-1, 0 }, +{ "SETLIST", 3, SETLIST, SETLIST, SETLIST-SETLIST-1, 0 }, +{ "SETLIST0", 2, SETLIST0, SETLIST, SETLIST0-SETLIST-1, 0 }, +{ "SETLISTW", 4, SETLISTW, SETLIST, SETLISTW-SETLIST-1, 0 }, +{ "SETMAP", 2, SETMAP, SETMAP, SETMAP-SETMAP-1, 0 }, +{ "SETMAP0", 1, SETMAP0, SETMAP, SETMAP0-SETMAP-1, 0 }, +{ "EQOP", 1, EQOP, EQOP, EQOP-EQOP-1, 0 }, +{ "NEQOP", 1, NEQOP, NEQOP, NEQOP-NEQOP-1, 0 }, +{ "LTOP", 1, LTOP, LTOP, LTOP-LTOP-1, 0 }, +{ "LEOP", 1, LEOP, LEOP, LEOP-LEOP-1, 0 }, +{ "GTOP", 1, GTOP, GTOP, GTOP-GTOP-1, 0 }, +{ "GEOP", 1, GEOP, GEOP, GEOP-GEOP-1, 0 }, +{ "ADDOP", 1, ADDOP, ADDOP, ADDOP-ADDOP-1, 0 }, +{ "SUBOP", 1, SUBOP, SUBOP, SUBOP-SUBOP-1, 0 }, +{ "MULTOP", 1, MULTOP, MULTOP, MULTOP-MULTOP-1, 0 }, +{ "DIVOP", 1, DIVOP, DIVOP, DIVOP-DIVOP-1, 0 }, +{ "POWOP", 1, POWOP, POWOP, POWOP-POWOP-1, 0 }, +{ "CONCOP", 1, CONCOP, CONCOP, CONCOP-CONCOP-1, 0 }, +{ "MINUSOP", 1, MINUSOP, MINUSOP, MINUSOP-MINUSOP-1, 0 }, +{ "NOTOP", 1, NOTOP, NOTOP, NOTOP-NOTOP-1, 0 }, +{ "ONTJMP", 2, ONTJMP, ONTJMP, ONTJMP-ONTJMP-1, 0 }, +{ "ONTJMPW", 3, ONTJMPW, ONTJMP, ONTJMPW-ONTJMP-1, 0 }, +{ "ONFJMP", 2, ONFJMP, ONFJMP, ONFJMP-ONFJMP-1, 0 }, +{ "ONFJMPW", 3, ONFJMPW, ONFJMP, ONFJMPW-ONFJMP-1, 0 }, +{ "JMP", 2, JMP, JMP, JMP-JMP-1, 0 }, +{ "JMPW", 3, JMPW, JMP, JMPW-JMP-1, 0 }, +{ "IFFJMP", 2, IFFJMP, IFFJMP, IFFJMP-IFFJMP-1, 0 }, +{ "IFFJMPW", 3, IFFJMPW, IFFJMP, IFFJMPW-IFFJMP-1, 0 }, +{ "IFTUPJMP", 2, IFTUPJMP, IFTUPJMP, IFTUPJMP-IFTUPJMP-1, 0 }, +{ "IFTUPJMPW", 3, IFTUPJMPW, IFTUPJMP, IFTUPJMPW-IFTUPJMP-1, 0 }, +{ "IFFUPJMP", 2, IFFUPJMP, IFFUPJMP, IFFUPJMP-IFFUPJMP-1, 0 }, +{ "IFFUPJMPW", 3, IFFUPJMPW, IFFUPJMP, IFFUPJMPW-IFFUPJMP-1, 0 }, +{ "CLOSURE", 3, CLOSURE, CLOSURE, CLOSURE-CLOSURE-1, 0 }, +{ "CLOSUREW", 4, CLOSUREW, CLOSURE, CLOSUREW-CLOSURE-1, 0 }, +{ "CALLFUNC", 3, CALLFUNC, CALLFUNC, CALLFUNC-CALLFUNC-1, 0 }, +{ "CALLFUNC0", 2, CALLFUNC0, CALLFUNC, CALLFUNC0-CALLFUNC-1, 0 }, +{ "CALLFUNC1", 2, CALLFUNC1, CALLFUNC, CALLFUNC1-CALLFUNC-1, 0 }, +{ "RETCODE", 2, RETCODE, RETCODE, RETCODE-RETCODE-1, 0 }, +{ "SETLINE", 2, SETLINE, SETLINE, SETLINE-SETLINE-1, 0 }, +{ "SETLINEW", 3, SETLINEW, SETLINE, SETLINEW-SETLINE-1, 0 }, +{ "POP", 2, POP, POP, POP-POP-1, 0 }, +{ "POP0", 1, POP0, POP, POP0-POP-1, 0 }, +{ "POP1", 1, POP1, POP, POP1-POP-1, 0 }, diff --git a/src/luac/opt.c b/src/luac/opt.c new file mode 100644 index 0000000..5084dde --- /dev/null +++ b/src/luac/opt.c @@ -0,0 +1,228 @@ +/* +** $Id: opt.c,v 1.4 1998/04/02 20:44:08 lhf Exp $ +** optimize bytecodes +** See Copyright Notice in lua.h +*/ + +#include +#include +#include "luac.h" +#include "lmem.h" + +static void FixConstants(TProtoFunc* tf, int* C) +{ + Byte* code=tf->code; + Byte* p=code; + while (1) + { + Opcode OP; + int n=INFO(tf,p,&OP); + int op=OP.class; + int i=OP.arg; + if (op==ENDCODE) break; + if ( op==PUSHCONSTANT || op==GETDOTTED || op==PUSHSELF || + op==GETGLOBAL || op==SETGLOBAL) + { + int j=C[i]; + if (j==i) + ; + else if (n==1) + { + p[0]=op+j+1; + } + else if (n==2) + { + if (j<8) { p[0]=op+j+1; p[1]=NOP; } else p[1]=j; + } + else + { + if (j<=255) + { + p[0]=op; + p[1]=j; + p[2]=NOP; + } + else + { + p[1]= 0x0000FF & (j>>8); + p[2]= 0x0000FF & j; + } + } + } + p+=n; + } +} + +static TProtoFunc* TF; + +static int compare(const void* a, const void *b) +{ + int ia=*(int*)a; + int ib=*(int*)b; + int t; + TObject* oa=TF->consts+ia; + TObject* ob=TF->consts+ib; + t=ttype(oa)-ttype(ob); if (t) return t; + t=oa->value.i-ob->value.i; if (t) return t; + return ia-ib; +} + +static void OptConstants(TProtoFunc* tf) +{ + static int* C=NULL; + static int* D=NULL; + int i,k; + int n=tf->nconsts; + if (n==0) return; + C=luaM_reallocvector(C,n,int); + D=luaM_reallocvector(D,n,int); + for (i=0; iconsts+k; + TObject* ob=tf->consts+j; + if (ttype(oa)==ttype(ob) && oa->value.i==ob->value.i) D[j]=k; else k=j; + } + k=0; /* build rename map & pack constants */ + for (i=0; iconsts[k]=tf->consts[i]; C[i]=k++; } else C[i]=C[D[i]]; + } + if (k>=n) return; +printf("\t\"%s\":%d reduced constants from %d to %d\n", + tf->fileName->str,tf->lineDefined,n,k); + tf->nconsts=k; + FixConstants(tf,C); +} + +static int NoDebug(TProtoFunc* tf) +{ + Byte* code=tf->code; + Byte* p=code; + int nop=0; + while (1) /* change SETLINE to NOP */ + { + Opcode OP; + int n=INFO(tf,p,&OP); + int op=OP.class; + if (op==ENDCODE) break; + if (op==NOP) ++nop; + if (op==SETLINE) { nop+=n; memset(p,NOP,n); } + p+=n; + } + return nop; +} + +static int FixJump(TProtoFunc* tf, Byte* a, Byte* b) +{ + Byte* p; + int nop=0; + for (p=a; pcode; + Byte* p=code; + while (1) + { + Opcode OP; + int n=INFO(tf,p,&OP); + int op=OP.class; + int i=OP.arg; + int nop; + if (op==ENDCODE) break; + nop=0; + if (op==IFTUPJMP || op==IFFUPJMP) nop=FixJump(tf,p-i+n,p); else + if (op==ONTJMP || op==ONFJMP || op==JMP || op==IFFJMP) nop=FixJump(tf,p,p+i+n); + if (nop>0) + { + int j=i-nop; + if (n==2) + p[1]=j; + else +#if 0 + { + if (j<=255) /* does NOT work for nested loops */ + { + if (op==IFTUPJMP || op==IFFUPJMP) --j; + p[0]=OP.op-1; /* *JMP and *JMPW are consecutive */ + p[1]=j; + p[2]=NOP; + } + else +#endif + { + p[1]= 0x0000FF & (j>>8); + p[2]= 0x0000FF & j; + } +#if 0 + } +#endif + } + p+=n; + } +} + +static void PackCode(TProtoFunc* tf) +{ + Byte* code=tf->code; + Byte* p=code; + Byte* q=code; + while (1) + { + Opcode OP; + int n=INFO(tf,p,&OP); + int op=OP.class; + if (op!=NOP) { memcpy(q,p,n); q+=n; } + p+=n; + if (op==ENDCODE) break; + } +printf("\t\"%s\":%d reduced code from %d to %d\n", + tf->fileName->str,tf->lineDefined,(int)(p-code),(int)(q-code)); +} + +static void OptCode(TProtoFunc* tf) +{ + int nop=NoDebug(tf); + if (nop==0) return; /* cannot improve code */ + FixJumps(tf); + PackCode(tf); +} + +static void OptFunction(TProtoFunc* tf); + +static void OptFunctions(TProtoFunc* tf) +{ + int i,n=tf->nconsts; + for (i=0; iconsts+i; + if (ttype(o)==LUA_T_PROTO) OptFunction(tfvalue(o)); + } +} + +static void OptFunction(TProtoFunc* tf) +{ + tf->locvars=NULL; /* remove local variables table */ + OptConstants(tf); + OptCode(tf); + OptFunctions(tf); +} + +void OptChunk(TProtoFunc* Main) +{ + OptFunction(Main); +} diff --git a/src/luac/print.c b/src/luac/print.c dissimilarity index 90% index fb7bf8a..ce98539 100644 --- a/src/luac/print.c +++ b/src/luac/print.c @@ -1,383 +1,233 @@ -/* -** print.c -** print bytecodes -*/ - -char* rcs_print="$Id: print.c,v 1.17 1997/06/25 17:07:28 lhf Exp $"; - -#include -#include -#include -#include "luac.h" -#include "print.h" - -void LinkFunctions(TFunc* m) -{ - static TFunc* lastF; /* list of functions seen in code */ - Byte* code=m->code; - Byte* end=code+m->size; - Byte* p; - if (IsMain(m)) lastF=m; - for (p=code; p!=end;) - { - int op=*p; - int at=p-code+1; - switch (op) - { - case PUSHNIL: - case PUSH0: - case PUSH1: - case PUSH2: - case PUSHLOCAL0: - case PUSHLOCAL1: - case PUSHLOCAL2: - case PUSHLOCAL3: - case PUSHLOCAL4: - case PUSHLOCAL5: - case PUSHLOCAL6: - case PUSHLOCAL7: - case PUSHLOCAL8: - case PUSHLOCAL9: - case PUSHINDEXED: - case STORELOCAL0: - case STORELOCAL1: - case STORELOCAL2: - case STORELOCAL3: - case STORELOCAL4: - case STORELOCAL5: - case STORELOCAL6: - case STORELOCAL7: - case STORELOCAL8: - case STORELOCAL9: - case STOREINDEXED0: - case ADJUST0: - case EQOP: - case LTOP: - case LEOP: - case GTOP: - case GEOP: - case ADDOP: - case SUBOP: - case MULTOP: - case DIVOP: - case POWOP: - case CONCOP: - case MINUSOP: - case NOTOP: - case POP: - case RETCODE0: - p++; - break; - case PUSHBYTE: - case PUSHLOCAL: - case STORELOCAL: - case STOREINDEXED: - case STORELIST0: - case ADJUST: - case RETCODE: - case VARARGS: - case STOREMAP: - p+=2; - break; - case PUSHWORD: - case PUSHSTRING: - case PUSHGLOBAL: - case PUSHSELF: - case STOREGLOBAL: - case CREATEARRAY: - case ONTJMP: - case ONFJMP: - case JMP: - case UPJMP: - case IFFJMP: - case IFFUPJMP: - case CALLFUNC: - case SETLINE: - case STORELIST: - p+=3; - break; - case PUSHFLOAT: - p+=5; /* assumes sizeof(float)==4 */ - break; - case PUSHFUNCTION: - { - TFunc* tf; - p++; - get_code(tf,p); - tf->marked=at; - tf->next=NULL; /* TODO: remove? */ - lastF=lastF->next=tf; - break; - } - case STORERECORD: - { - int n=*++p; - p+=2*n+1; - break; - } - default: /* cannot happen */ - fprintf(stderr,"luac: bad opcode %d at %d\n",*p,(int)(p-code)); - exit(1); - break; - } - } -} - -#define LocStr(i) luaI_getlocalname(tf,i+1,line) - -static void PrintCode(TFunc* tf) -{ - Byte* code=tf->code; - Byte* end=code+tf->size; - Byte* p; - int line=0; - for (p=code; p!=end;) - { - int op=*p; - if (op>=NOPCODES) - { - fprintf(stderr,"luac: bad opcode %d at %d\n",op,(int)(p-code)); - exit(1); - } - printf("%6d\t%s",(int)(p-code),OpCodeName[op]); - switch (op) - { - case PUSHNIL: - case PUSH0: - case PUSH1: - case PUSH2: - case PUSHINDEXED: - case STOREINDEXED0: - case ADJUST0: - case EQOP: - case LTOP: - case LEOP: - case GTOP: - case GEOP: - case ADDOP: - case SUBOP: - case MULTOP: - case DIVOP: - case POWOP: - case CONCOP: - case MINUSOP: - case NOTOP: - case POP: - case RETCODE0: - p++; - break; - case PUSHLOCAL0: - case PUSHLOCAL1: - case PUSHLOCAL2: - case PUSHLOCAL3: - case PUSHLOCAL4: - case PUSHLOCAL5: - case PUSHLOCAL6: - case PUSHLOCAL7: - case PUSHLOCAL8: - case PUSHLOCAL9: - { - int i=op-PUSHLOCAL0; - if (tf->locvars) printf("\t\t; %s",LocStr(i)); - p++; - break; - } - case STORELOCAL0: - case STORELOCAL1: - case STORELOCAL2: - case STORELOCAL3: - case STORELOCAL4: - case STORELOCAL5: - case STORELOCAL6: - case STORELOCAL7: - case STORELOCAL8: - case STORELOCAL9: - { - int i=op-STORELOCAL0; - if (tf->locvars) printf("\t\t; %s",LocStr(i)); - p++; - break; - } - case PUSHLOCAL: - case STORELOCAL: - { - int i=*(p+1); - if (tf->locvars) printf("\t%d\t; %s",i,LocStr(i)); - p+=2; - break; - } - case PUSHBYTE: - case STOREINDEXED: - case STORELIST0: - case ADJUST: - case RETCODE: - case VARARGS: - case STOREMAP: - printf("\t%d",*(p+1)); - p+=2; - break; - case PUSHWORD: - case CREATEARRAY: - case SETLINE: - { - Word w; - p++; - get_word(w,p); - printf("\t%d",w); - if (op==SETLINE) line=w; - break; - } - case ONTJMP: - case ONFJMP: - case JMP: - case IFFJMP: - { /* suggested by Norman Ramsey */ - Word w; - p++; - get_word(w,p); - printf("\t%d\t\t; to %d",w,(int)(p-code)+w); - break; - } - case UPJMP: - case IFFUPJMP: - { /* suggested by Norman Ramsey */ - Word w; - p++; - get_word(w,p); - printf("\t%d\t\t; to %d",w,(int)(p-code)-w); - break; - } - case PUSHFLOAT: - { - float f; - p++; - get_float(f,p); - printf("\t%g",f); - break; - } - case PUSHSELF: - case PUSHSTRING: - { - Word w; - p++; - get_word(w,p); - printf("\t%d\t; \"%s\"",w,StrStr(w)); - break; - } - case PUSHFUNCTION: - { - TFunc* tf; - p++; - get_code(tf,p); - printf("\t%p\t; \"%s\":%d",tf,tf->fileName,tf->lineDefined); - break; - } - case PUSHGLOBAL: - case STOREGLOBAL: - { - Word w; - p++; - get_word(w,p); - printf("\t%d\t; %s",w,VarStr(w)); - break; - } - case STORELIST: - case CALLFUNC: - printf("\t%d %d",*(p+1),*(p+2)); - p+=3; - break; - case STORERECORD: - { - int n=*++p; - printf("\t%d",n); - p++; - while (n--) - { - Word w; - printf("\n%6d\t FIELD",(int)(p-code)); - get_word(w,p); - printf("\t%d\t; \"%s\"",w,StrStr(w)); - } - break; - } - default: - printf("\tcannot happen: opcode=%d\n",*p); - fprintf(stderr,"luac: bad opcode %d at %d\n",op,(int)(p-code)); - exit(1); - break; - } - printf("\n"); - } -} - -#undef LocStr - -static void PrintLocals(LocVar* v, int n) -{ - int i=0; - if (v==NULL || v->varname==NULL) return; - if (n>0) - { - printf("parameters:"); - for (i=0; ivarname->str,i,v->line); - printf("\n"); - } - if (v->varname!=NULL) - { - printf("locals:"); - for (; v->line>=0; v++) - { - if (v->varname==NULL) -#if 0 - printf(" %s[%d@%d]","*",--i,v->line); -#else - --i; -#endif - else - printf(" %s[%d@%d]",v->varname->str,i++,v->line); - } - printf("\n"); - } -} - -void PrintFunction(TFunc* tf, TFunc* Main) -{ - int n=0; - if (IsMain(tf)) - printf("\nmain of \"%s\" (%d bytes at %p)\n",tf->fileName,tf->size,tf); - else - { - Byte* p; - p=tf->code; /* get number of parameters */ - while (*p==SETLINE) p+=3; - if (*p==ADJUST) n=p[1]; - p=Main->code+tf->marked+sizeof(TFunc*); - printf("\nfunction "); - switch (*p) /* try to get name */ - { - case STOREGLOBAL: - { - Word w; - p++; get_word(w,p); printf("%s defined at ",VarStr(w)); - break; - } - case STOREINDEXED0: /* try method definition */ - { - if (p[-11]==PUSHGLOBAL && p[-8]==PUSHSTRING) - { - Word w; - Byte* op=p; - int c=(tf->locvars && n>0 && strcmp(tf->locvars->varname->str,"self")==0) - ? ':' : '.'; - p=op-11; p++; get_word(w,p); printf("%s%c",VarStr(w),c); - p=op-8; p++; get_word(w,p); printf("%s defined at ",StrStr(w)); - } - break; - } - } - printf("\"%s\":%d (%d bytes at %p); used at main+%d\n", - tf->fileName,tf->lineDefined,tf->size,tf,tf->marked); - } - PrintLocals(tf->locvars,n); - PrintCode(tf); -} +/* +** $Id: print.c,v 1.13 1998/07/12 00:17:37 lhf Exp $ +** print bytecodes +** See Copyright Notice in lua.h +*/ + +#include +#include +#include "luac.h" + +#ifdef DEBUG +void PrintConstant1(TProtoFunc* tf, int i) +{ + TObject* o=tf->consts+i; + printf("%6d ",i); + if (i<0 || i>=tf->nconsts) + printf("(bad constant #%d: max=%d)",i,tf->nconsts); + else + switch (ttype(o)) + { + case LUA_T_NUMBER: + printf("N " NUMBER_FMT "\n",nvalue(o)); /* LUA_NUMBER */ + break; + case LUA_T_STRING: + printf("S %p\t\"%s\"\n",(void*)tsvalue(o),svalue(o)); + break; + case LUA_T_PROTO: + printf("F %p\n",(void*)tfvalue(o)); + break; + default: /* cannot happen */ + printf("? %d\n",ttype(o)); + break; + } +} + +static void PrintConstants(TProtoFunc* tf) +{ + int i,n=tf->nconsts; + printf("constants (%d):\n",n); + for (i=0; i=tf->nconsts) + printf("(bad constant #%d: max=%d)",i,tf->nconsts); + else + { + TObject* o=tf->consts+i; + switch (ttype(o)) + { + case LUA_T_NUMBER: + printf(NUMBER_FMT,nvalue(o)); /* LUA_NUMBER */ + break; + case LUA_T_STRING: + printf("\"%s\"",svalue(o)); + break; + case LUA_T_PROTO: + printf("function at %p",(void*)tfvalue(o)); + break; + case LUA_T_NIL: + printf("(nil)"); + break; + default: /* cannot happen */ + printf("(bad constant #%d: type=%d [%s])\n",i,ttype(o),luaO_typename(o)); + break; + } + } +} + +#define VarStr(i) svalue(tf->consts+i) + +static void PrintCode(TProtoFunc* tf) +{ + Byte* code=tf->code; + Byte* p=code; + int line=0; + while (1) + { + Opcode OP; + int n=INFO(tf,p,&OP); + int op=OP.op; + int i=OP.arg; + printf("%6d ",(int)(p-code)); + { + Byte* q=p; + int j=n; + while (j--) printf("%02X",*q++); + } + printf("%*s%-13s",2*(5-n),"",OP.name); + + if (n!=1 || op<0) printf("\t%d",i); else if (i>=0) printf("\t"); + + switch (OP.class) + { + + case ENDCODE: + printf("\n"); + return; + + case CLOSURE: + printf(" %d",OP.arg2); + case PUSHCONSTANT: + case GETDOTTED: + case PUSHSELF: + printf("\t; "); + PrintConstant(tf,i); + break; + + case PUSHLOCAL: + case SETLOCAL: + { + char* s=luaF_getlocalname(tf,i+1,line); + if (s) printf("\t; %s",s); + break; + } + + case GETGLOBAL: + case SETGLOBAL: + printf("\t; %s",VarStr(i)); + break; + + case SETLIST: + case CALLFUNC: + if (n>=3) printf(" %d",OP.arg2); + break; + + case SETLINE: + printf("\t; \"%s\":%d",fileName(tf),line=i); + break; + +/* suggested by Norman Ramsey */ + case IFTUPJMP: + case IFFUPJMP: + i=-i; + case ONTJMP: + case ONFJMP: + case JMP: + case IFFJMP: + printf("\t; to %d",(int)(p-code)+i+n); + break; + + } + printf("\n"); + p+=n; + } +} + +static void PrintLocals(TProtoFunc* tf) +{ + LocVar* v=tf->locvars; + int n,i=0; + if (v==NULL || v->varname==NULL) return; + n=tf->code[1]; if (n>=ZEROVARARG) n-=ZEROVARARG; + + printf("locals:"); + if (n>0) + { + for (i=0; ivarname->str); + } + if (v->varname!=NULL) + { + for (; v->line>=0; v++) + { + if (v->varname==NULL) + { + printf(")"); --i; + } + else + { + printf(" (%s",v->varname->str); i++; + } + } + i-=n; + while (i--) printf(")"); + } + printf("\n"); +} + +static void PrintHeader(TProtoFunc* tf, TProtoFunc* Main, int at) +{ + int size=CodeSize(tf); + if (IsMain(tf)) + printf("\nmain of \"%s\" (%d bytes at %p)\n",fileName(tf),size,(void*)tf); + else if (Main) + { + printf("\nfunction defined at \"%s\":%d (%d bytes at %p); used at ", + fileName(tf),tf->lineDefined,size,(void*)tf); + if (IsMain(Main)) + printf("main"); + else + printf("%p",(void*)Main); + printf("+%d\n",at); + } +} + +static void PrintFunction(TProtoFunc* tf, TProtoFunc* Main, int at); + +static void PrintFunctions(TProtoFunc* Main) +{ + Byte* code=Main->code; + Byte* p=code; + while (1) + { + Opcode OP; + int n=INFO(Main,p,&OP); + if (OP.class==ENDCODE) break; + if (OP.class==PUSHCONSTANT || OP.class==CLOSURE) + { + int i=OP.arg; + TObject* o=Main->consts+i; + if (ttype(o)==LUA_T_PROTO) PrintFunction(tfvalue(o),Main,(int)(p-code)); + } + p+=n; + } +} + +static void PrintFunction(TProtoFunc* tf, TProtoFunc* Main, int at) +{ + PrintHeader(tf,Main,at); + PrintLocals(tf); + PrintCode(tf); +#ifdef DEBUG + PrintConstants(tf); +#endif + PrintFunctions(tf); +} + +void PrintChunk(TProtoFunc* Main) +{ + PrintFunction(Main,0,0); +} diff --git a/src/luac/print.h b/src/luac/print.h deleted file mode 100644 index 00e344c..0000000 --- a/src/luac/print.h +++ /dev/null @@ -1,79 +0,0 @@ -/* -** print.h -** opcode names -** $Id: print.h,v 1.3 1997/04/14 14:42:50 lhf Exp $ -*/ - -static char* OpCodeName[]={ /* ATTENTION: same order as enum in opcode.h */ - "PUSHNIL", - "PUSH0", - "PUSH1", - "PUSH2", - "PUSHBYTE", - "PUSHWORD", - "PUSHFLOAT", - "PUSHSTRING", - "PUSHFUNCTION", - "PUSHLOCAL0", - "PUSHLOCAL1", - "PUSHLOCAL2", - "PUSHLOCAL3", - "PUSHLOCAL4", - "PUSHLOCAL5", - "PUSHLOCAL6", - "PUSHLOCAL7", - "PUSHLOCAL8", - "PUSHLOCAL9", - "PUSHLOCAL", - "PUSHGLOBAL", - "PUSHINDEXED", - "PUSHSELF", - "STORELOCAL0", - "STORELOCAL1", - "STORELOCAL2", - "STORELOCAL3", - "STORELOCAL4", - "STORELOCAL5", - "STORELOCAL6", - "STORELOCAL7", - "STORELOCAL8", - "STORELOCAL9", - "STORELOCAL", - "STOREGLOBAL", - "STOREINDEXED0", - "STOREINDEXED", - "STORELIST0", - "STORELIST", - "STORERECORD", - "ADJUST0", - "ADJUST", - "CREATEARRAY", - "EQOP", - "LTOP", - "LEOP", - "GTOP", - "GEOP", - "ADDOP", - "SUBOP", - "MULTOP", - "DIVOP", - "POWOP", - "CONCOP", - "MINUSOP", - "NOTOP", - "ONTJMP", - "ONFJMP", - "JMP", - "UPJMP", - "IFFJMP", - "IFFUPJMP", - "POP", - "CALLFUNC", - "RETCODE0", - "RETCODE", - "SETLINE", - "VARARGS", - "STOREMAP" -}; - -#define NOPCODES (sizeof(OpCodeName)/sizeof(OpCodeName[0])) diff --git a/src/luac/stubs.c b/src/luac/stubs.c new file mode 100644 index 0000000..d42bec2 --- /dev/null +++ b/src/luac/stubs.c @@ -0,0 +1,68 @@ +/* +** $Id: stubs.c,v 1.8 1998/07/12 00:17:37 lhf Exp $ +** avoid runtime modules in luac +** See Copyright Notice in lua.h +*/ + +#include +#include +#include +#include "luac.h" + +/* +* avoid lapi lauxlib lbuiltin ldo lgc ltable ltm lvm +* use only lbuffer lfunc llex lmem lobject lparser lstate lstring lzio +*/ + +/* simplified from ldo.c */ +void lua_error(char* s) +{ + if (s) fprintf(stderr,"luac: %s\n",s); + exit(1); +} + +/* copied from lauxlib.c */ +void luaL_verror(char* fmt, ...) +{ + char buff[500]; + va_list argp; + va_start(argp,fmt); + vsprintf(buff,fmt,argp); + va_end(argp); + lua_error(buff); +} + +/* copied from lauxlib.c */ +int luaL_findstring (char* name, char* list[]) +{ + int i; + for (i=0; list[i]; i++) + if (strcmp(list[i], name) == 0) + return i; + return -1; +} + +/* avoid runtime modules in lstate.c */ +void luaB_predefine(void){} +void luaC_hashcallIM(Hash *l){} +void luaC_strcallIM(TaggedString *l){} +void luaD_gcIM(TObject *o){} +void luaD_init(void){} +void luaH_free(Hash *frees){} +void luaT_init(void){} + +/* +* the code below avoids the lexer and the parser (llex lparser). +* it is useful if you only want to load binary files. +* this works for interpreters like lua.c too. +*/ + +#ifdef NOPARSER + +int lua_debug=0; + +void luaX_init(void){} +void luaY_init(void){} +void luaY_parser(void) { lua_error("parser not loaded"); } + +#endif diff --git a/src/luamem.c b/src/luamem.c deleted file mode 100644 index e4cdd6d..0000000 --- a/src/luamem.c +++ /dev/null @@ -1,159 +0,0 @@ -/* -** mem.c -** TecCGraf - PUC-Rio -*/ - -char *rcs_luamem = "$Id: luamem.c,v 1.16 1997/04/01 21:23:20 roberto Exp $"; - -#include - -#include "luamem.h" -#include "lua.h" - - -#define DEBUG 0 - -#if !DEBUG - -void luaI_free (void *block) -{ - if (block) - { - *((char *)block) = -1; /* to catch errors */ - free(block); - } -} - - -void *luaI_realloc (void *oldblock, unsigned long size) -{ - void *block; - size_t s = (size_t)size; - if (s != size) - lua_error("Allocation Error: Block too big"); - block = oldblock ? realloc(oldblock, s) : malloc(s); - if (block == NULL) - lua_error(memEM); - return block; -} - - -int luaI_growvector (void **block, unsigned long nelems, int size, - char *errormsg, unsigned long limit) -{ - if (nelems >= limit) - lua_error(errormsg); - nelems = (nelems == 0) ? 20 : nelems*2; - if (nelems > limit) - nelems = limit; - *block = luaI_realloc(*block, nelems*size); - return (int)nelems; -} - - -void* luaI_buffer (unsigned long size) -{ - static unsigned long buffsize = 0; - static char* buffer = NULL; - if (size > buffsize) - buffer = luaI_realloc(buffer, buffsize=size); - return buffer; -} - -#else -/* DEBUG */ - -#include - -# define assert(ex) {if (!(ex)){(void)fprintf(stderr, \ - "Assertion failed: file \"%s\", line %d\n", __FILE__, __LINE__);exit(1);}} - -#define MARK 55 - -static unsigned long numblocks = 0; -static unsigned long totalmem = 0; - - -static void message (void) -{ -#define inrange(x,y) ((x) < (((y)*3)/2) && (x) > (((y)*2)/3)) - static int count = 0; - static unsigned long lastnumblocks = 0; - static unsigned long lasttotalmem = 0; - if (!inrange(numblocks, lastnumblocks) || !inrange(totalmem, lasttotalmem) - || count++ >= 5000) - { - fprintf(stderr,"blocks = %lu mem = %luK\n", numblocks, totalmem/1000); - count = 0; - lastnumblocks = numblocks; - lasttotalmem = totalmem; - } -} - - -void luaI_free (void *block) -{ - if (block) - { - unsigned long *b = (unsigned long *)block - 1; - unsigned long size = *b; - assert(*(((char *)b)+size+sizeof(unsigned long)) == MARK); - numblocks--; - totalmem -= size; - free(b); - message(); - } -} - - -void *luaI_realloc (void *oldblock, unsigned long size) -{ - unsigned long *block; - unsigned long realsize = sizeof(unsigned long)+size+sizeof(char); - if (realsize != (size_t)realsize) - lua_error("Allocation Error: Block too big"); - if (oldblock) - { - unsigned long *b = (unsigned long *)oldblock - 1; - unsigned long oldsize = *b; - assert(*(((char *)b)+oldsize+sizeof(unsigned long)) == MARK); - totalmem -= oldsize; - numblocks--; - block = (unsigned long *)realloc(b, realsize); - } - else - block = (unsigned long *)malloc(realsize); - if (block == NULL) - lua_error("not enough memory"); - totalmem += size; - numblocks++; - *block = size; - *(((char *)block)+size+sizeof(unsigned long)) = MARK; - message(); - return block+1; -} - - -int luaI_growvector (void **block, unsigned long nelems, int size, - char *errormsg, unsigned long limit) -{ - if (nelems >= limit) - lua_error(errormsg); - nelems = (nelems == 0) ? 20 : nelems*2; - if (nelems > limit) - nelems = limit; - *block = luaI_realloc(*block, nelems*size); - return (int)nelems; -} - - -void* luaI_buffer (unsigned long size) -{ - static unsigned long buffsize = 0; - static char* buffer = NULL; - if (size > buffsize) - buffer = luaI_realloc(buffer, buffsize=size); - return buffer; -} - -#endif diff --git a/src/luamem.h b/src/luamem.h deleted file mode 100644 index 86b7c8f..0000000 --- a/src/luamem.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -** mem.c -** memory manager for lua -** $Id: luamem.h,v 1.9 1997/03/31 14:10:11 roberto Exp $ -*/ - -#ifndef luamem_h -#define luamem_h - -#ifndef NULL -#define NULL 0 -#endif - - -/* memory error messages */ -#define codeEM "code size overflow" -#define symbolEM "symbol table overflow" -#define constantEM "constant table overflow" -#define stackEM "stack size overflow" -#define lexEM "lex buffer overflow" -#define refEM "reference table overflow" -#define tableEM "table overflow" -#define memEM "not enough memory" - - -void luaI_free (void *block); -void *luaI_realloc (void *oldblock, unsigned long size); -void *luaI_buffer (unsigned long size); -int luaI_growvector (void **block, unsigned long nelems, int size, - char *errormsg, unsigned long limit); - -#define luaI_malloc(s) luaI_realloc(NULL, (s)) -#define new(s) ((s *)luaI_malloc(sizeof(s))) -#define newvector(n,s) ((s *)luaI_malloc((n)*sizeof(s))) -#define growvector(old,n,s,e,l) \ - (luaI_growvector((void**)old,n,sizeof(s),e,l)) - -#endif - diff --git a/src/lundump.c b/src/lundump.c new file mode 100644 index 0000000..4fe2b0d --- /dev/null +++ b/src/lundump.c @@ -0,0 +1,228 @@ +/* +** $Id: lundump.c,v 1.12 1998/07/12 01:46:59 lhf Exp $ +** load bytecodes from files +** See Copyright Notice in lua.h +*/ + +#include +#include +#include "lauxlib.h" +#include "lfunc.h" +#include "lmem.h" +#include "lstring.h" +#include "lundump.h" + +#define LoadBlock(b,size,Z) ezread(Z,b,size) +#define LoadNative(t,Z) LoadBlock(&t,sizeof(t),Z) + +#if ID_NUMBER==ID_NATIVE + #define doLoadNumber(f,Z) LoadNative(f,Z) +#else + #define doLoadNumber(f,Z) f=LoadNumber(Z) +#endif + +static void unexpectedEOZ(ZIO* Z) +{ + luaL_verror("unexpected end of file in %s",zname(Z)); +} + +static int ezgetc(ZIO* Z) +{ + int c=zgetc(Z); + if (c==EOZ) unexpectedEOZ(Z); + return c; +} + +static void ezread(ZIO* Z, void* b, int n) +{ + int r=zread(Z,b,n); + if (r!=0) unexpectedEOZ(Z); +} + +static unsigned int LoadWord(ZIO* Z) +{ + unsigned int hi=ezgetc(Z); + unsigned int lo=ezgetc(Z); + return (hi<<8)|lo; +} + +static unsigned long LoadLong(ZIO* Z) +{ + unsigned long hi=LoadWord(Z); + unsigned long lo=LoadWord(Z); + return (hi<<16)|lo; +} + +#if ID_NUMBER==ID_REAL4 +/* LUA_NUMBER */ +/* assumes sizeof(long)==4 and sizeof(float)==4 (IEEE) */ +static float LoadFloat(ZIO* Z) +{ + unsigned long l=LoadLong(Z); + float f; + memcpy(&f,&l,sizeof(f)); + return f; +} +#endif + +#if ID_NUMBER==ID_REAL8 +/* LUA_NUMBER */ +/* assumes sizeof(long)==4 and sizeof(double)==8 (IEEE) */ +static double LoadDouble(ZIO* Z) +{ + unsigned long l[2]; + double f; + int x=1; + if (*(char*)&x==1) /* little-endian */ + { + l[1]=LoadLong(Z); + l[0]=LoadLong(Z); + } + else /* big-endian */ + { + l[0]=LoadLong(Z); + l[1]=LoadLong(Z); + } + memcpy(&f,l,sizeof(f)); + return f; +} +#endif + +static Byte* LoadCode(ZIO* Z) +{ + unsigned long size=LoadLong(Z); + unsigned int s=size; + void* b; + if (s!=size) luaL_verror("code too long (%ld bytes) in %s",size,zname(Z)); + b=luaM_malloc(size); + LoadBlock(b,size,Z); + return b; +} + +static TaggedString* LoadTString(ZIO* Z) +{ + int size=LoadWord(Z); + if (size==0) + return NULL; + else + { + char* s=luaL_openspace(size); + LoadBlock(s,size,Z); + return luaS_newlstr(s,size-1); + } +} + +static void LoadLocals(TProtoFunc* tf, ZIO* Z) +{ + int i,n=LoadWord(Z); + if (n==0) return; + tf->locvars=luaM_newvector(n+1,LocVar); + for (i=0; ilocvars[i].line=LoadWord(Z); + tf->locvars[i].varname=LoadTString(Z); + } + tf->locvars[i].line=-1; /* flag end of vector */ + tf->locvars[i].varname=NULL; +} + +static TProtoFunc* LoadFunction(ZIO* Z); + +static void LoadConstants(TProtoFunc* tf, ZIO* Z) +{ + int i,n=LoadWord(Z); + tf->nconsts=n; + if (n==0) return; + tf->consts=luaM_newvector(n,TObject); + for (i=0; iconsts+i; + ttype(o)=-ezgetc(Z); + switch (ttype(o)) + { + case LUA_T_NUMBER: + doLoadNumber(nvalue(o),Z); + break; + case LUA_T_STRING: + tsvalue(o)=LoadTString(Z); + break; + case LUA_T_PROTO: + tfvalue(o)=LoadFunction(Z); + break; + case LUA_T_NIL: + break; + default: + luaL_verror("bad constant #%d in %s: type=%d [%s]", + i,zname(Z),ttype(o),luaO_typename(o)); + break; + } + } +} + +static TProtoFunc* LoadFunction(ZIO* Z) +{ + TProtoFunc* tf=luaF_newproto(); + tf->lineDefined=LoadWord(Z); + tf->fileName=LoadTString(Z); + tf->code=LoadCode(Z); + LoadLocals(tf,Z); + LoadConstants(tf,Z); + return tf; +} + +static void LoadSignature(ZIO* Z) +{ + char* s=SIGNATURE; + while (*s!=0 && ezgetc(Z)==*s) + ++s; + if (*s!=0) luaL_verror("bad signature in %s",zname(Z)); +} + +static void LoadHeader(ZIO* Z) +{ + int version,id,sizeofR; + real f=-TEST_NUMBER,tf=TEST_NUMBER; + LoadSignature(Z); + version=ezgetc(Z); + if (version>VERSION) + luaL_verror( + "%s too new: version=0x%02x; expected at most 0x%02x", + zname(Z),version,VERSION); + if (versionlineDefined==0) +#define luaO_typename(o) luaO_typenames[-ttype(o)] + +/* number representation */ +#define ID_INT4 'l' /* 4-byte integers */ +#define ID_REAL4 'f' /* 4-byte reals */ +#define ID_REAL8 'd' /* 8-byte reals */ +#define ID_NATIVE '?' /* whatever your machine uses */ + +/* +* use a multiple of PI for testing number representation. +* multiplying by 1E8 gives notrivial integer values. +*/ +#define TEST_NUMBER 3.14159265358979323846E8 + +/* LUA_NUMBER +* choose one below for the number representation in precompiled chunks. +* the default is ID_REAL8 because the default for LUA_NUM_TYPE is double. +* if your machine does not use IEEE 754, use ID_NATIVE. +* the next version will support conversion to/from IEEE 754. +* +* if you change LUA_NUM_TYPE, make sure you set ID_NUMBER accordingly, +* specially if sizeof(long)!=4. +* for types other than the ones listed below, you'll have to write your own +* dump and undump routines. +*/ + +#ifndef ID_NUMBER +#define ID_NUMBER ID_REAL8 +#endif + +#if 0 +#define ID_NUMBER ID_INT4 +#define ID_NUMBER ID_REAL4 +#define ID_NUMBER ID_REAL8 +#define ID_NUMBER ID_NATIVE +#endif + +#endif + +#if ID_NUMBER==ID_REAL4 + #define DumpNumber DumpFloat + #define LoadNumber LoadFloat + #define SIZEOF_NUMBER 4 +#elif ID_NUMBER==ID_REAL8 + #define DumpNumber DumpDouble + #define LoadNumber LoadDouble + #define SIZEOF_NUMBER 8 +#elif ID_NUMBER==ID_INT4 + #define DumpNumber DumpLong + #define LoadNumber LoadLong + #define SIZEOF_NUMBER 4 +#elif ID_NUMBER==ID_NATIVE + #define DumpNumber DumpNative + #define LoadNumber LoadNative + #define SIZEOF_NUMBER sizeof(real) +#else + #error bad ID_NUMBER +#endif diff --git a/src/lvm.c b/src/lvm.c new file mode 100644 index 0000000..72c26c1 --- /dev/null +++ b/src/lvm.c @@ -0,0 +1,737 @@ +/* +** $Id: lvm.c,v 1.30 1998/06/11 18:21:37 roberto Exp $ +** Lua virtual machine +** See Copyright Notice in lua.h +*/ + + +#include +#include + +#include "lauxlib.h" +#include "ldo.h" +#include "lfunc.h" +#include "lgc.h" +#include "lmem.h" +#include "lopcodes.h" +#include "lstate.h" +#include "lstring.h" +#include "ltable.h" +#include "ltm.h" +#include "luadebug.h" +#include "lvm.h" + + +#ifdef OLD_ANSI +#define strcoll(a,b) strcmp(a,b) +#endif + + +#define skip_word(pc) (pc+=2) +#define get_word(pc) ((*(pc)<<8)+(*((pc)+1))) +#define next_word(pc) (pc+=2, get_word(pc-2)) + + +/* Extra stack size to run a function: LUA_T_LINE(1), TM calls(2), ... */ +#define EXTRA_STACK 5 + + + +static TaggedString *strconc (TaggedString *l, TaggedString *r) +{ + size_t nl = l->u.s.len; + size_t nr = r->u.s.len; + char *buffer = luaL_openspace(nl+nr+1); + memcpy(buffer, l->str, nl); + memcpy(buffer+nl, r->str, nr); + return luaS_newlstr(buffer, nl+nr); +} + + +int luaV_tonumber (TObject *obj) +{ /* LUA_NUMBER */ + double t; + char c; + if (ttype(obj) != LUA_T_STRING) + return 1; + else if (sscanf(svalue(obj), "%lf %c",&t, &c) == 1) { + nvalue(obj) = (real)t; + ttype(obj) = LUA_T_NUMBER; + return 0; + } + else + return 2; +} + + +int luaV_tostring (TObject *obj) +{ /* LUA_NUMBER */ + if (ttype(obj) != LUA_T_NUMBER) + return 1; + else { + char s[60]; + real f = nvalue(obj); + int i; + if ((real)(-MAX_INT) <= f && f <= (real)MAX_INT && (real)(i=(int)f) == f) + sprintf (s, "%d", i); + else + sprintf (s, NUMBER_FMT, nvalue(obj)); + tsvalue(obj) = luaS_new(s); + ttype(obj) = LUA_T_STRING; + return 0; + } +} + + +void luaV_closure (int nelems) +{ + if (nelems > 0) { + struct Stack *S = &L->stack; + Closure *c = luaF_newclosure(nelems); + c->consts[0] = *(S->top-1); + memcpy(&c->consts[1], S->top-(nelems+1), nelems*sizeof(TObject)); + S->top -= nelems; + ttype(S->top-1) = LUA_T_CLOSURE; + (S->top-1)->value.cl = c; + } +} + + +/* +** Function to index a table. +** Receives the table at top-2 and the index at top-1. +*/ +void luaV_gettable (void) +{ + struct Stack *S = &L->stack; + TObject *im; + if (ttype(S->top-2) != LUA_T_ARRAY) /* not a table, get "gettable" method */ + im = luaT_getimbyObj(S->top-2, IM_GETTABLE); + else { /* object is a table... */ + int tg = (S->top-2)->value.a->htag; + im = luaT_getim(tg, IM_GETTABLE); + if (ttype(im) == LUA_T_NIL) { /* and does not have a "gettable" method */ + TObject *h = luaH_get(avalue(S->top-2), S->top-1); + if (h != NULL && ttype(h) != LUA_T_NIL) { + --S->top; + *(S->top-1) = *h; + } + else if (ttype(im=luaT_getim(tg, IM_INDEX)) != LUA_T_NIL) + luaD_callTM(im, 2, 1); + else { + --S->top; + ttype(S->top-1) = LUA_T_NIL; + } + return; + } + /* else it has a "gettable" method, go through to next command */ + } + /* object is not a table, or it has a "gettable" method */ + if (ttype(im) != LUA_T_NIL) + luaD_callTM(im, 2, 1); + else + lua_error("indexed expression not a table"); +} + + +/* +** Function to store indexed based on values at the stack.top +** mode = 0: raw store (without tag methods) +** mode = 1: normal store (with tag methods) +** mode = 2: "deep L->stack.stack" store (with tag methods) +*/ +void luaV_settable (TObject *t, int mode) +{ + struct Stack *S = &L->stack; + TObject *im = (mode == 0) ? NULL : luaT_getimbyObj(t, IM_SETTABLE); + if (ttype(t) == LUA_T_ARRAY && (im == NULL || ttype(im) == LUA_T_NIL)) { + TObject *h = luaH_set(avalue(t), t+1); + *h = *(S->top-1); + S->top -= (mode == 2) ? 1 : 3; + } + else { /* object is not a table, and/or has a specific "settable" method */ + if (im && ttype(im) != LUA_T_NIL) { + if (mode == 2) { + *(S->top+1) = *(L->stack.top-1); + *(S->top) = *(t+1); + *(S->top-1) = *t; + S->top += 2; /* WARNING: caller must assure stack space */ + } + luaD_callTM(im, 3, 0); + } + else + lua_error("indexed expression not a table"); + } +} + + +void luaV_getglobal (TaggedString *ts) +{ + /* WARNING: caller must assure stack space */ + TObject *value = &ts->u.s.globalval; + TObject *im = luaT_getimbyObj(value, IM_GETGLOBAL); + if (ttype(im) == LUA_T_NIL) { /* default behavior */ + *L->stack.top++ = *value; + } + else { + struct Stack *S = &L->stack; + ttype(S->top) = LUA_T_STRING; + tsvalue(S->top) = ts; + S->top++; + *S->top++ = *value; + luaD_callTM(im, 2, 1); + } +} + + +void luaV_setglobal (TaggedString *ts) +{ + TObject *oldvalue = &ts->u.s.globalval; + TObject *im = luaT_getimbyObj(oldvalue, IM_SETGLOBAL); + if (ttype(im) == LUA_T_NIL) /* default behavior */ + luaS_rawsetglobal(ts, --L->stack.top); + else { + /* WARNING: caller must assure stack space */ + struct Stack *S = &L->stack; + TObject newvalue = *(S->top-1); + ttype(S->top-1) = LUA_T_STRING; + tsvalue(S->top-1) = ts; + *S->top++ = *oldvalue; + *S->top++ = newvalue; + luaD_callTM(im, 3, 0); + } +} + + +static void call_binTM (IMS event, char *msg) +{ + TObject *im = luaT_getimbyObj(L->stack.top-2, event);/* try first operand */ + if (ttype(im) == LUA_T_NIL) { + im = luaT_getimbyObj(L->stack.top-1, event); /* try second operand */ + if (ttype(im) == LUA_T_NIL) { + im = luaT_getim(0, event); /* try a 'global' i.m. */ + if (ttype(im) == LUA_T_NIL) + lua_error(msg); + } + } + lua_pushstring(luaT_eventname[event]); + luaD_callTM(im, 3, 1); +} + + +static void call_arith (IMS event) +{ + call_binTM(event, "unexpected type in arithmetic operation"); +} + + +static int strcomp (char *l, long ll, char *r, long lr) +{ + for (;;) { + long temp = strcoll(l, r); + if (temp != 0) return temp; + /* strings are equal up to a '\0' */ + temp = strlen(l); /* index of first '\0' in both strings */ + if (temp == ll) /* l is finished? */ + return (temp == lr) ? 0 : -1; /* l is equal or smaller than r */ + else if (temp == lr) /* r is finished? */ + return 1; /* l is greater than r (because l is not finished) */ + /* both strings longer than temp; go on comparing (after the '\0') */ + temp++; + l += temp; ll -= temp; r += temp; lr -= temp; + } +} + +static void comparison (lua_Type ttype_less, lua_Type ttype_equal, + lua_Type ttype_great, IMS op) +{ + struct Stack *S = &L->stack; + TObject *l = S->top-2; + TObject *r = S->top-1; + int result; + if (ttype(l) == LUA_T_NUMBER && ttype(r) == LUA_T_NUMBER) + result = (nvalue(l) < nvalue(r)) ? -1 : (nvalue(l) == nvalue(r)) ? 0 : 1; + else if (ttype(l) == LUA_T_STRING && ttype(r) == LUA_T_STRING) + result = strcomp(svalue(l), tsvalue(l)->u.s.len, + svalue(r), tsvalue(r)->u.s.len); + else { + call_binTM(op, "unexpected type in comparison"); + return; + } + S->top--; + nvalue(S->top-1) = 1; + ttype(S->top-1) = (result < 0) ? ttype_less : + (result == 0) ? ttype_equal : ttype_great; +} + + +void luaV_pack (StkId firstel, int nvararg, TObject *tab) +{ + TObject *firstelem = L->stack.stack+firstel; + int i; + if (nvararg < 0) nvararg = 0; + avalue(tab) = luaH_new(nvararg+1); /* +1 for field 'n' */ + ttype(tab) = LUA_T_ARRAY; + for (i=0; istack.top-L->stack.stack)-first_extra_arg, &arg); + luaD_adjusttop(first_extra_arg); + *L->stack.top++ = arg; +} + + + +/* +** Execute the given opcode, until a RET. Parameters are between +** [stack+base,top). Returns n such that the the results are between +** [stack+n,top). +*/ +StkId luaV_execute (Closure *cl, TProtoFunc *tf, StkId base) +{ + struct Stack *S = &L->stack; /* to optimize */ + Byte *pc = tf->code; + TObject *consts = tf->consts; + if (lua_callhook) + luaD_callHook(base, tf, 0); + luaD_checkstack((*pc++)+EXTRA_STACK); + if (*pc < ZEROVARARG) + luaD_adjusttop(base+*(pc++)); + else { /* varargs */ + luaC_checkGC(); + adjust_varargs(base+(*pc++)-ZEROVARARG); + } + while (1) { + int aux; + switch ((OpCode)(aux = *pc++)) { + + case PUSHNIL0: + ttype(S->top++) = LUA_T_NIL; + break; + + case PUSHNIL: + aux = *pc++; + do { + ttype(S->top++) = LUA_T_NIL; + } while (aux--); + break; + + case PUSHNUMBER: + aux = *pc++; goto pushnumber; + + case PUSHNUMBERW: + aux = next_word(pc); goto pushnumber; + + case PUSHNUMBER0: case PUSHNUMBER1: case PUSHNUMBER2: + aux -= PUSHNUMBER0; + pushnumber: + ttype(S->top) = LUA_T_NUMBER; + nvalue(S->top) = aux; + S->top++; + break; + + case PUSHLOCAL: + aux = *pc++; goto pushlocal; + + case PUSHLOCAL0: case PUSHLOCAL1: case PUSHLOCAL2: case PUSHLOCAL3: + case PUSHLOCAL4: case PUSHLOCAL5: case PUSHLOCAL6: case PUSHLOCAL7: + aux -= PUSHLOCAL0; + pushlocal: + *S->top++ = *((S->stack+base) + aux); + break; + + case GETGLOBALW: + aux = next_word(pc); goto getglobal; + + case GETGLOBAL: + aux = *pc++; goto getglobal; + + case GETGLOBAL0: case GETGLOBAL1: case GETGLOBAL2: case GETGLOBAL3: + case GETGLOBAL4: case GETGLOBAL5: case GETGLOBAL6: case GETGLOBAL7: + aux -= GETGLOBAL0; + getglobal: + luaV_getglobal(tsvalue(&consts[aux])); + break; + + case GETTABLE: + luaV_gettable(); + break; + + case GETDOTTEDW: + aux = next_word(pc); goto getdotted; + + case GETDOTTED: + aux = *pc++; goto getdotted; + + case GETDOTTED0: case GETDOTTED1: case GETDOTTED2: case GETDOTTED3: + case GETDOTTED4: case GETDOTTED5: case GETDOTTED6: case GETDOTTED7: + aux -= GETDOTTED0; + getdotted: + *S->top++ = consts[aux]; + luaV_gettable(); + break; + + case PUSHSELFW: + aux = next_word(pc); goto pushself; + + case PUSHSELF: + aux = *pc++; goto pushself; + + case PUSHSELF0: case PUSHSELF1: case PUSHSELF2: case PUSHSELF3: + case PUSHSELF4: case PUSHSELF5: case PUSHSELF6: case PUSHSELF7: + aux -= PUSHSELF0; + pushself: { + TObject receiver = *(S->top-1); + *S->top++ = consts[aux]; + luaV_gettable(); + *S->top++ = receiver; + break; + } + + case PUSHCONSTANTW: + aux = next_word(pc); goto pushconstant; + + case PUSHCONSTANT: + aux = *pc++; goto pushconstant; + + case PUSHCONSTANT0: case PUSHCONSTANT1: case PUSHCONSTANT2: + case PUSHCONSTANT3: case PUSHCONSTANT4: case PUSHCONSTANT5: + case PUSHCONSTANT6: case PUSHCONSTANT7: + aux -= PUSHCONSTANT0; + pushconstant: + *S->top++ = consts[aux]; + break; + + case PUSHUPVALUE: + aux = *pc++; goto pushupvalue; + + case PUSHUPVALUE0: case PUSHUPVALUE1: + aux -= PUSHUPVALUE0; + pushupvalue: + *S->top++ = cl->consts[aux+1]; + break; + + case SETLOCAL: + aux = *pc++; goto setlocal; + + case SETLOCAL0: case SETLOCAL1: case SETLOCAL2: case SETLOCAL3: + case SETLOCAL4: case SETLOCAL5: case SETLOCAL6: case SETLOCAL7: + aux -= SETLOCAL0; + setlocal: + *((S->stack+base) + aux) = *(--S->top); + break; + + case SETGLOBALW: + aux = next_word(pc); goto setglobal; + + case SETGLOBAL: + aux = *pc++; goto setglobal; + + case SETGLOBAL0: case SETGLOBAL1: case SETGLOBAL2: case SETGLOBAL3: + case SETGLOBAL4: case SETGLOBAL5: case SETGLOBAL6: case SETGLOBAL7: + aux -= SETGLOBAL0; + setglobal: + luaV_setglobal(tsvalue(&consts[aux])); + break; + + case SETTABLE0: + luaV_settable(S->top-3, 1); + break; + + case SETTABLE: + luaV_settable(S->top-3-(*pc++), 2); + break; + + case SETLISTW: + aux = next_word(pc); aux *= LFIELDS_PER_FLUSH; goto setlist; + + case SETLIST: + aux = *(pc++) * LFIELDS_PER_FLUSH; goto setlist; + + case SETLIST0: + aux = 0; + setlist: { + int n = *(pc++); + TObject *arr = S->top-n-1; + for (; n; n--) { + ttype(S->top) = LUA_T_NUMBER; + nvalue(S->top) = n+aux; + *(luaH_set(avalue(arr), S->top)) = *(S->top-1); + S->top--; + } + break; + } + + case SETMAP0: + aux = 0; goto setmap; + + case SETMAP: + aux = *pc++; + setmap: { + TObject *arr = S->top-(2*aux)-3; + do { + *(luaH_set(avalue(arr), S->top-2)) = *(S->top-1); + S->top-=2; + } while (aux--); + break; + } + + case POP: + aux = *pc++; goto pop; + + case POP0: case POP1: + aux -= POP0; + pop: + S->top -= (aux+1); + break; + + case CREATEARRAYW: + aux = next_word(pc); goto createarray; + + case CREATEARRAY0: case CREATEARRAY1: + aux -= CREATEARRAY0; goto createarray; + + case CREATEARRAY: + aux = *pc++; + createarray: + luaC_checkGC(); + avalue(S->top) = luaH_new(aux); + ttype(S->top) = LUA_T_ARRAY; + S->top++; + break; + + case EQOP: case NEQOP: { + int res = luaO_equalObj(S->top-2, S->top-1); + S->top--; + if (aux == NEQOP) res = !res; + ttype(S->top-1) = res ? LUA_T_NUMBER : LUA_T_NIL; + nvalue(S->top-1) = 1; + break; + } + + case LTOP: + comparison(LUA_T_NUMBER, LUA_T_NIL, LUA_T_NIL, IM_LT); + break; + + case LEOP: + comparison(LUA_T_NUMBER, LUA_T_NUMBER, LUA_T_NIL, IM_LE); + break; + + case GTOP: + comparison(LUA_T_NIL, LUA_T_NIL, LUA_T_NUMBER, IM_GT); + break; + + case GEOP: + comparison(LUA_T_NIL, LUA_T_NUMBER, LUA_T_NUMBER, IM_GE); + break; + + case ADDOP: { + TObject *l = S->top-2; + TObject *r = S->top-1; + if (tonumber(r) || tonumber(l)) + call_arith(IM_ADD); + else { + nvalue(l) += nvalue(r); + --S->top; + } + break; + } + + case SUBOP: { + TObject *l = S->top-2; + TObject *r = S->top-1; + if (tonumber(r) || tonumber(l)) + call_arith(IM_SUB); + else { + nvalue(l) -= nvalue(r); + --S->top; + } + break; + } + + case MULTOP: { + TObject *l = S->top-2; + TObject *r = S->top-1; + if (tonumber(r) || tonumber(l)) + call_arith(IM_MUL); + else { + nvalue(l) *= nvalue(r); + --S->top; + } + break; + } + + case DIVOP: { + TObject *l = S->top-2; + TObject *r = S->top-1; + if (tonumber(r) || tonumber(l)) + call_arith(IM_DIV); + else { + nvalue(l) /= nvalue(r); + --S->top; + } + break; + } + + case POWOP: + call_binTM(IM_POW, "undefined operation"); + break; + + case CONCOP: { + TObject *l = S->top-2; + TObject *r = S->top-1; + if (tostring(l) || tostring(r)) + call_binTM(IM_CONCAT, "unexpected type for concatenation"); + else { + tsvalue(l) = strconc(tsvalue(l), tsvalue(r)); + --S->top; + } + luaC_checkGC(); + break; + } + + case MINUSOP: + if (tonumber(S->top-1)) { + ttype(S->top) = LUA_T_NIL; + S->top++; + call_arith(IM_UNM); + } + else + nvalue(S->top-1) = - nvalue(S->top-1); + break; + + case NOTOP: + ttype(S->top-1) = + (ttype(S->top-1) == LUA_T_NIL) ? LUA_T_NUMBER : LUA_T_NIL; + nvalue(S->top-1) = 1; + break; + + case ONTJMPW: + aux = next_word(pc); goto ontjmp; + + case ONTJMP: + aux = *pc++; + ontjmp: + if (ttype(S->top-1) != LUA_T_NIL) pc += aux; + else S->top--; + break; + + case ONFJMPW: + aux = next_word(pc); goto onfjmp; + + case ONFJMP: + aux = *pc++; + onfjmp: + if (ttype(S->top-1) == LUA_T_NIL) pc += aux; + else S->top--; + break; + + case JMPW: + aux = next_word(pc); goto jmp; + + case JMP: + aux = *pc++; + jmp: + pc += aux; + break; + + case IFFJMPW: + aux = next_word(pc); goto iffjmp; + + case IFFJMP: + aux = *pc++; + iffjmp: + if (ttype(--S->top) == LUA_T_NIL) pc += aux; + break; + + case IFTUPJMPW: + aux = next_word(pc); goto iftupjmp; + + case IFTUPJMP: + aux = *pc++; + iftupjmp: + if (ttype(--S->top) != LUA_T_NIL) pc -= aux; + break; + + case IFFUPJMPW: + aux = next_word(pc); goto iffupjmp; + + case IFFUPJMP: + aux = *pc++; + iffupjmp: + if (ttype(--S->top) == LUA_T_NIL) pc -= aux; + break; + + case CLOSUREW: + aux = next_word(pc); goto closure; + + case CLOSURE: + aux = *pc++; + closure: + *S->top++ = consts[aux]; + luaV_closure(*pc++); + luaC_checkGC(); + break; + + case CALLFUNC: + aux = *pc++; goto callfunc; + + case CALLFUNC0: case CALLFUNC1: + aux -= CALLFUNC0; + callfunc: { + StkId newBase = (S->top-S->stack)-(*pc++); + luaD_call(newBase, aux); + break; + } + + case ENDCODE: + S->top = S->stack + base; + /* goes through */ + case RETCODE: + if (lua_callhook) + luaD_callHook(base, NULL, 1); + return (base + ((aux==RETCODE) ? *pc : 0)); + + case SETLINEW: + aux = next_word(pc); goto setline; + + case SETLINE: + aux = *pc++; + setline: + if ((S->stack+base-1)->ttype != LUA_T_LINE) { + /* open space for LINE value */ + luaD_openstack((S->top-S->stack)-base); + base++; + (S->stack+base-1)->ttype = LUA_T_LINE; + } + (S->stack+base-1)->value.i = aux; + if (lua_linehook) + luaD_lineHook(aux); + break; + +#ifdef DEBUG + default: + LUA_INTERNALERROR("opcode doesn't match"); +#endif + } + } +} + diff --git a/src/lvm.h b/src/lvm.h new file mode 100644 index 0000000..9b3f900 --- /dev/null +++ b/src/lvm.h @@ -0,0 +1,29 @@ +/* +** $Id: lvm.h,v 1.4 1997/12/15 16:17:20 roberto Exp $ +** Lua virtual machine +** See Copyright Notice in lua.h +*/ + +#ifndef lvm_h +#define lvm_h + + +#include "ldo.h" +#include "lobject.h" + + +#define tonumber(o) ((ttype(o) != LUA_T_NUMBER) && (luaV_tonumber(o) != 0)) +#define tostring(o) ((ttype(o) != LUA_T_STRING) && (luaV_tostring(o) != 0)) + + +void luaV_pack (StkId firstel, int nvararg, TObject *tab); +int luaV_tonumber (TObject *obj); +int luaV_tostring (TObject *obj); +void luaV_gettable (void); +void luaV_settable (TObject *t, int mode); +void luaV_getglobal (TaggedString *ts); +void luaV_setglobal (TaggedString *ts); +StkId luaV_execute (Closure *cl, TProtoFunc *tf, StkId base); +void luaV_closure (int nelems); + +#endif diff --git a/src/zio.c b/src/lzio.c similarity index 71% rename from src/zio.c rename to src/lzio.c index 2af49f4..0ab1adf 100644 --- a/src/zio.c +++ b/src/lzio.c @@ -1,43 +1,47 @@ /* -* zio.c -* a generic input stream interface -* $Id: zio.c,v 1.2 1997/06/20 19:25:54 roberto Exp $ +** $Id: lzio.c,v 1.3 1997/12/22 20:57:18 roberto Exp $ +** a generic input stream interface +** See Copyright Notice in lua.h */ + + #include -#include #include -#include "zio.h" + +#include "lzio.h" + /* ----------------------------------------------------- memory buffers --- */ -static int zmfilbuf(ZIO* z) +static int zmfilbuf (ZIO* z) { return EOZ; } -ZIO* zmopen(ZIO* z, char* b, int size) +ZIO* zmopen (ZIO* z, char* b, int size, char *name) { if (b==NULL) return NULL; z->n=size; z->p= (unsigned char *)b; z->filbuf=zmfilbuf; z->u=NULL; + z->name=name; return z; } /* ------------------------------------------------------------ strings --- */ -ZIO* zsopen(ZIO* z, char* s) +ZIO* zsopen (ZIO* z, char* s, char *name) { if (s==NULL) return NULL; - return zmopen(z,s,strlen(s)); + return zmopen(z,s,strlen(s),name); } /* -------------------------------------------------------------- FILEs --- */ -static int zffilbuf(ZIO* z) +static int zffilbuf (ZIO* z) { int n=fread(z->buffer,1,ZBSIZE,z->u); if (n==0) return EOZ; @@ -47,19 +51,20 @@ static int zffilbuf(ZIO* z) } -ZIO* zFopen(ZIO* z, FILE* f) +ZIO* zFopen (ZIO* z, FILE* f, char *name) { if (f==NULL) return NULL; z->n=0; z->p=z->buffer; z->filbuf=zffilbuf; z->u=f; + z->name=name; return z; } /* --------------------------------------------------------------- read --- */ -int zread(ZIO *z, void *b, int n) +int zread (ZIO *z, void *b, int n) { while (n) { int m; diff --git a/src/zio.h b/src/lzio.h similarity index 60% rename from src/zio.h rename to src/lzio.h index f0f3640..d7edd26 100644 --- a/src/zio.h +++ b/src/lzio.h @@ -1,11 +1,12 @@ /* -* zio.h -* a generic input stream interface -* $Id: zio.h,v 1.5 1997/06/20 19:25:54 roberto Exp $ +** $Id: lzio.h,v 1.4 1998/01/09 14:57:43 roberto Exp $ +** Buffered streams +** See Copyright Notice in lua.h */ -#ifndef zio_h -#define zio_h + +#ifndef lzio_h +#define lzio_h #include @@ -21,15 +22,15 @@ typedef struct zio ZIO; -ZIO* zFopen(ZIO* z, FILE* f); /* open FILEs */ -ZIO* zsopen(ZIO* z, char* s); /* string */ -ZIO* zmopen(ZIO* z, char* b, int size); /* memory */ +ZIO* zFopen (ZIO* z, FILE* f, char *name); /* open FILEs */ +ZIO* zsopen (ZIO* z, char* s, char *name); /* string */ +ZIO* zmopen (ZIO* z, char* b, int size, char *name); /* memory */ -int zread(ZIO* z, void* b, int n); /* read next n bytes */ +int zread (ZIO* z, void* b, int n); /* read next n bytes */ #define zgetc(z) (--(z)->n>=0 ? ((int)*(z)->p++): (z)->filbuf(z)) #define zungetc(z) (++(z)->n,--(z)->p) - +#define zname(z) ((z)->name) /* --------- Private Part ------------------ */ @@ -41,6 +42,7 @@ struct zio { unsigned char* p; /* current position in buffer */ int (*filbuf)(ZIO* z); void* u; /* additional data */ + char *name; unsigned char buffer[ZBSIZE]; /* buffer */ }; diff --git a/src/opcode.c b/src/opcode.c deleted file mode 100644 index ea18f9e..0000000 --- a/src/opcode.c +++ /dev/null @@ -1,1478 +0,0 @@ -/* -** opcode.c -** TecCGraf - PUC-Rio -*/ - -char *rcs_opcode="$Id: opcode.c,v 4.15 1997/06/26 21:40:57 roberto Exp $"; - -#include -#include -#include -#include - -#include "luadebug.h" -#include "luamem.h" -#include "opcode.h" -#include "hash.h" -#include "inout.h" -#include "table.h" -#include "lua.h" -#include "fallback.h" -#include "auxlib.h" -#include "lex.h" - -#define tonumber(o) ((ttype(o) != LUA_T_NUMBER) && (lua_tonumber(o) != 0)) -#define tostring(o) ((ttype(o) != LUA_T_STRING) && (lua_tostring(o) != 0)) - - -#define STACK_SIZE 128 - -#ifndef STACK_LIMIT -#define STACK_LIMIT 6000 -#endif - -typedef int StkId; /* index to stack elements */ - -static TObject initial_stack; - -static TObject *stackLimit = &initial_stack+1; -static TObject *stack = &initial_stack; -static TObject *top = &initial_stack; - - -/* macros to convert from lua_Object to (TObject *) and back */ - -#define Address(lo) ((lo)+stack-1) -#define Ref(st) ((st)-stack+1) - - -/* macro to increment stack top. There must be always an empty slot in -* the stack -*/ -#define incr_top if (++top >= stackLimit) growstack() - -struct C_Lua_Stack { - StkId base; /* when Lua calls C or C calls Lua, points to */ - /* the first slot after the last parameter. */ - StkId lua2C; /* points to first element of "array" lua2C */ - int num; /* size of "array" lua2C */ -}; - -static struct C_Lua_Stack CLS_current = {0, 0, 0}; - -static jmp_buf *errorJmp = NULL; /* current error recover point */ - - -/* Hooks */ -lua_LHFunction lua_linehook = NULL; -lua_CHFunction lua_callhook = NULL; - - -static StkId lua_execute (Byte *pc, StkId base); -static void do_call (StkId base, int nResults); - - - -TObject *luaI_Address (lua_Object o) -{ - return Address(o); -} - - -/* -** Init stack -*/ -static void lua_initstack (void) -{ - Long maxstack = STACK_SIZE; - stack = newvector(maxstack, TObject); - stackLimit = stack+maxstack; - top = stack; - *(top++) = initial_stack; -} - - -/* -** Check stack overflow and, if necessary, realloc vector -*/ -#define lua_checkstack(nt) if ((nt) >= stackLimit) growstack() - -static void growstack (void) -{ - if (stack == &initial_stack) - lua_initstack(); - else - { - static int limit = STACK_LIMIT; - StkId t = top-stack; - Long stacksize = stackLimit - stack; - stacksize = growvector(&stack, stacksize, TObject, stackEM, limit+100); - stackLimit = stack+stacksize; - top = stack + t; - if (stacksize >= limit) - { - limit = stacksize; - lua_error(stackEM); - } - } -} - - -/* -** Concatenate two given strings. Return the new string pointer. -*/ -static char *lua_strconc (char *l, char *r) -{ - size_t nl = strlen(l); - char *buffer = luaI_buffer(nl+strlen(r)+1); - strcpy(buffer, l); - strcpy(buffer+nl, r); - return buffer; -} - - -/* -** Convert, if possible, to a number object. -** Return 0 if success, not 0 if error. -*/ -static int lua_tonumber (TObject *obj) -{ - float t; - char c; - if (ttype(obj) != LUA_T_STRING) - return 1; - else if (sscanf(svalue(obj), "%f %c",&t, &c) == 1) - { - nvalue(obj) = t; - ttype(obj) = LUA_T_NUMBER; - return 0; - } - else - return 2; -} - - -/* -** Convert, if possible, to a string ttype -** Return 0 in success or not 0 on error. -*/ -static int lua_tostring (TObject *obj) -{ - if (ttype(obj) != LUA_T_NUMBER) - return 1; - else { - char s[60]; - real f = nvalue(obj); - int i; - if ((real)(-MAX_INT) <= f && f <= (real)MAX_INT && (real)(i=(int)f) == f) - sprintf (s, "%d", i); - else - sprintf (s, "%g", nvalue(obj)); - tsvalue(obj) = lua_createstring(s); - ttype(obj) = LUA_T_STRING; - return 0; - } -} - - -/* -** Adjust stack. Set top to the given value, pushing NILs if needed. -*/ -static void adjust_top_aux (StkId newtop) -{ - TObject *nt; - lua_checkstack(stack+newtop); - nt = stack+newtop; /* warning: previous call may change stack */ - while (top < nt) ttype(top++) = LUA_T_NIL; -} - - -#define adjust_top(newtop) { if (newtop <= top-stack) \ - top = stack+newtop; \ - else adjust_top_aux(newtop); } - -#define adjustC(nParams) adjust_top(CLS_current.base+nParams) - - -static void checkCparams (int nParams) -{ - if (top-stack < CLS_current.base+nParams) - lua_error("API error - wrong number of arguments in C2lua stack"); -} - - -/* -** Open a hole below "nelems" from the top. -*/ -static void open_stack (int nelems) -{ - int i; - for (i=0; ivalue.tf->fileName, f->value.tf->lineDefined); - else - (*lua_callhook)(Ref(f), "(C)", -1); - } - top = stack+old_top; - CLS_current = oldCLS; -} - - -/* -** Call a C function. CLS_current.base will point to the top of the stack, -** and CLS_current.num is the number of parameters. Returns an index -** to the first result from C. -*/ -static StkId callC (lua_CFunction func, StkId base) -{ - struct C_Lua_Stack oldCLS = CLS_current; - StkId firstResult; - CLS_current.num = (top-stack) - base; - /* incorporate parameters on the stack */ - CLS_current.lua2C = base; - CLS_current.base = base+CLS_current.num; /* == top-stack */ - if (lua_callhook) - callHook(base, LUA_T_CMARK, 0); - (*func)(); - if (lua_callhook) /* func may have changed lua_callhook */ - callHook(base, LUA_T_CMARK, 1); - firstResult = CLS_current.base; - CLS_current = oldCLS; - return firstResult; -} - -static void callIM (TObject *f, int nParams, int nResults) -{ - open_stack(nParams); - *(top-nParams-1) = *f; - do_call((top-stack)-nParams, nResults); -} - - -/* -** Call a function (C or Lua). The parameters must be on the stack, -** between [stack+base,top). The function to be called is at stack+base-1. -** When returns, the results are on the stack, between [stack+base-1,top). -** The number of results is nResults, unless nResults=MULT_RET. -*/ -static void do_call (StkId base, int nResults) -{ - StkId firstResult; - TObject *func = stack+base-1; - int i; - if (ttype(func) == LUA_T_CFUNCTION) { - ttype(func) = LUA_T_CMARK; - firstResult = callC(fvalue(func), base); - } - else if (ttype(func) == LUA_T_FUNCTION) { - ttype(func) = LUA_T_MARK; - firstResult = lua_execute(func->value.tf->code, base); - } - else { /* func is not a function */ - /* Check the tag method for invalid functions */ - TObject *im = luaI_getimbyObj(func, IM_FUNCTION); - if (ttype(im) == LUA_T_NIL) - lua_error("call expression not a function"); - open_stack((top-stack)-(base-1)); - stack[base-1] = *im; - do_call(base, nResults); - return; - } - /* adjust the number of results */ - if (nResults != MULT_RET) - adjust_top(firstResult+nResults); - /* move results to base-1 (to erase parameters and function) */ - base--; - nResults = top - (stack+firstResult); /* actual number of results */ - for (i=0; ivalue.a->htag; - im = luaI_getim(tg, IM_GETTABLE); - if (ttype(im) == LUA_T_NIL) { /* and does not have a "gettable" method */ - TObject *h = lua_hashget(avalue(top-2), top-1); - if (h != NULL && ttype(h) != LUA_T_NIL) { - --top; - *(top-1) = *h; - } - else if (ttype(im=luaI_getim(tg, IM_INDEX)) != LUA_T_NIL) - callIM(im, 2, 1); - else { - --top; - ttype(top-1) = LUA_T_NIL; - } - return; - } - /* else it has a "gettable" method, go through to next command */ - } - /* object is not a table, or it has a "gettable" method */ - if (ttype(im) != LUA_T_NIL) - callIM(im, 2, 1); - else - lua_error("indexed expression not a table"); -} - - -lua_Object lua_rawgettable (void) -{ - checkCparams(2); - if (ttype(top-2) != LUA_T_ARRAY) - lua_error("indexed expression not a table in raw gettable"); - else { - TObject *h = lua_hashget(avalue(top-2), top-1); - --top; - if (h != NULL) - *(top-1) = *h; - else - ttype(top-1) = LUA_T_NIL; - } - return put_luaObjectonTop(); -} - - -/* -** Function to store indexed based on values at the top -** mode = 0: raw store (without internal methods) -** mode = 1: normal store (with internal methods) -** mode = 2: "deep stack" store (with internal methods) -*/ -static void storesubscript (TObject *t, int mode) -{ - TObject *im = (mode == 0) ? NULL : luaI_getimbyObj(t, IM_SETTABLE); - if (ttype(t) == LUA_T_ARRAY && (im == NULL || ttype(im) == LUA_T_NIL)) { - TObject *h = lua_hashdefine(avalue(t), t+1); - *h = *(top-1); - top -= (mode == 2) ? 1 : 3; - } - else { /* object is not a table, and/or has a specific "settable" method */ - if (im && ttype(im) != LUA_T_NIL) { - if (mode == 2) { - lua_checkstack(top+2); - *(top+1) = *(top-1); - *(top) = *(t+1); - *(top-1) = *t; - top += 2; - } - callIM(im, 3, 0); - } - else - lua_error("indexed expression not a table"); - } -} - - -static void getglobal (Word n) -{ - TObject *value = &lua_table[n].object; - TObject *im = luaI_getimbyObj(value, IM_GETGLOBAL); - if (ttype(im) == LUA_T_NIL) { /* default behavior */ - *top = *value; - incr_top; - } - else { - ttype(top) = LUA_T_STRING; - tsvalue(top) = lua_table[n].varname; - incr_top; - *top = *value; - incr_top; - callIM(im, 2, 1); - } -} - -/* -** Traverse all objects on stack -*/ -void lua_travstack (int (*fn)(TObject *)) -{ - StkId i; - for (i = (top-1)-stack; i>=0; i--) - fn (stack+i); -} - - -/* -** Error messages and debug functions -*/ - -static void lua_message (char *s) -{ - TObject *im = luaI_geterrorim(); - if (ttype(im) != LUA_T_NIL) { - lua_pushstring(s); - callIM(im, 1, 0); - } -} - -/* -** Reports an error, and jumps up to the available recover label -*/ -void lua_error (char *s) -{ - if (s) lua_message(s); - if (errorJmp) - longjmp(*errorJmp, 1); - else - { - fprintf (stderr, "lua: exit(1). Unable to recover\n"); - exit(1); - } -} - - -lua_Function lua_stackedfunction (int level) -{ - StkId i; - for (i = (top-1)-stack; i>=0; i--) - if (stack[i].ttype == LUA_T_MARK || stack[i].ttype == LUA_T_CMARK) - if (level-- == 0) - return Ref(stack+i); - return LUA_NOOBJECT; -} - - -int lua_currentline (lua_Function func) -{ - TObject *f = Address(func); - return (f+1 < top && (f+1)->ttype == LUA_T_LINE) ? (f+1)->value.i : -1; -} - - -lua_Object lua_getlocal (lua_Function func, int local_number, char **name) -{ - TObject *f = luaI_Address(func); - *name = luaI_getlocalname(f->value.tf, local_number, lua_currentline(func)); - if (*name) - { - /* if "*name", there must be a LUA_T_LINE */ - /* therefore, f+2 points to function base */ - return Ref((f+2)+(local_number-1)); - } - else - return LUA_NOOBJECT; -} - -int lua_setlocal (lua_Function func, int local_number) -{ - TObject *f = Address(func); - char *name = luaI_getlocalname(f->value.tf, local_number, lua_currentline(func)); - checkCparams(1); - --top; - if (name) - { - /* if "name", there must be a LUA_T_LINE */ - /* therefore, f+2 points to function base */ - *((f+2)+(local_number-1)) = *top; - return 1; - } - else - return 0; -} - -/* -** Call the function at CLS_current.base, and incorporate results on -** the Lua2C structure. -*/ -static void do_callinc (int nResults) -{ - StkId base = CLS_current.base; - do_call(base+1, nResults); - CLS_current.lua2C = base; /* position of the new results */ - CLS_current.num = (top-stack) - base; /* number of results */ - CLS_current.base = base + CLS_current.num; /* incorporate results on stack */ -} - - -static void do_unprotectedrun (lua_CFunction f, int nParams, int nResults) -{ - StkId base = (top-stack)-nParams; - open_stack(nParams); - stack[base].ttype = LUA_T_CFUNCTION; - stack[base].value.f = f; - do_call(base+1, nResults); -} - - -/* -** Execute a protected call. Assumes that function is at CLS_current.base and -** parameters are on top of it. Leave nResults on the stack. -*/ -static int do_protectedrun (int nResults) -{ - jmp_buf myErrorJmp; - int status; - struct C_Lua_Stack oldCLS = CLS_current; - jmp_buf *oldErr = errorJmp; - errorJmp = &myErrorJmp; - if (setjmp(myErrorJmp) == 0) { - do_callinc(nResults); - status = 0; - } - else { /* an error occurred: restore CLS_current and top */ - CLS_current = oldCLS; - top = stack+CLS_current.base; - status = 1; - } - errorJmp = oldErr; - return status; -} - -int luaI_dorun (TFunc *tf) -{ - int status; - adjustC(1); /* one slot for the pseudo-function */ - stack[CLS_current.base].ttype = LUA_T_FUNCTION; - stack[CLS_current.base].value.tf = tf; - status = do_protectedrun(MULT_RET); - return status; -} - - -int lua_domain (void) -{ - TFunc tf; - int status; - jmp_buf myErrorJmp; - jmp_buf *oldErr = errorJmp; - errorJmp = &myErrorJmp; - luaI_initTFunc(&tf); - if (setjmp(myErrorJmp) == 0) { - lua_parse(&tf); - status = 0; - } - else { - adjustC(0); /* erase extra slot */ - status = 1; - } - if (status == 0) - status = luaI_dorun(&tf); - errorJmp = oldErr; - luaI_free(tf.code); - return status; -} - -/* -** Execute the given lua function. Return 0 on success or 1 on error. -*/ -int lua_callfunction (lua_Object function) -{ - if (function == LUA_NOOBJECT) - return 1; - else - { - open_stack((top-stack)-CLS_current.base); - stack[CLS_current.base] = *Address(function); - return do_protectedrun (MULT_RET); - } -} - - -lua_Object lua_gettagmethod (int tag, char *event) -{ - lua_pushnumber(tag); - lua_pushstring(event); - do_unprotectedrun(luaI_gettagmethod, 2, 1); - return put_luaObjectonTop(); -} - -lua_Object lua_settagmethod (int tag, char *event) -{ - TObject newmethod; - checkCparams(1); - newmethod = *(--top); - lua_pushnumber(tag); - lua_pushstring(event); - *top = newmethod; incr_top; - do_unprotectedrun(luaI_settagmethod, 3, 1); - return put_luaObjectonTop(); -} - -lua_Object lua_seterrormethod (void) -{ - checkCparams(1); - do_unprotectedrun(luaI_seterrormethod, 1, 1); - return put_luaObjectonTop(); -} - - -/* -** API: receives on the stack the table and the index. -** returns the value. -*/ -lua_Object lua_gettable (void) -{ - checkCparams(2); - pushsubscript(); - return put_luaObjectonTop(); -} - - -#define MAX_C_BLOCKS 10 - -static int numCblocks = 0; -static struct C_Lua_Stack Cblocks[MAX_C_BLOCKS]; - -/* -** API: starts a new block -*/ -void lua_beginblock (void) -{ - if (numCblocks >= MAX_C_BLOCKS) - lua_error("`lua_beginblock': too many nested blocks"); - Cblocks[numCblocks] = CLS_current; - numCblocks++; -} - -/* -** API: ends a block -*/ -void lua_endblock (void) -{ - --numCblocks; - CLS_current = Cblocks[numCblocks]; - adjustC(0); -} - -void lua_settag (int tag) -{ - checkCparams(1); - luaI_settag(tag, --top); -} - -/* -** API: receives on the stack the table, the index, and the new value. -*/ -void lua_settable (void) -{ - checkCparams(3); - storesubscript(top-3, 1); -} - -void lua_rawsettable (void) -{ - checkCparams(3); - storesubscript(top-3, 0); -} - -/* -** API: creates a new table -*/ -lua_Object lua_createtable (void) -{ - TObject o; - avalue(&o) = lua_createarray(0); - ttype(&o) = LUA_T_ARRAY; - return put_luaObject(&o); -} - -/* -** Get a parameter, returning the object handle or LUA_NOOBJECT on error. -** 'number' must be 1 to get the first parameter. -*/ -lua_Object lua_lua2C (int number) -{ - if (number <= 0 || number > CLS_current.num) return LUA_NOOBJECT; - /* Ref(stack+(CLS_current.lua2C+number-1)) == - stack+(CLS_current.lua2C+number-1)-stack+1 == */ - return CLS_current.lua2C+number; -} - -int lua_isnil (lua_Object o) -{ - return (o!= LUA_NOOBJECT) && (ttype(Address(o)) == LUA_T_NIL); -} - -int lua_istable (lua_Object o) -{ - return (o!= LUA_NOOBJECT) && (ttype(Address(o)) == LUA_T_ARRAY); -} - -int lua_isuserdata (lua_Object o) -{ - return (o!= LUA_NOOBJECT) && (ttype(Address(o)) == LUA_T_USERDATA); -} - -int lua_iscfunction (lua_Object o) -{ - int t = lua_tag(o); - return (t == LUA_T_CMARK) || (t == LUA_T_CFUNCTION); -} - -int lua_isnumber (lua_Object o) -{ - return (o!= LUA_NOOBJECT) && (tonumber(Address(o)) == 0); -} - -int lua_isstring (lua_Object o) -{ - int t = lua_tag(o); - return (t == LUA_T_STRING) || (t == LUA_T_NUMBER); -} - -int lua_isfunction (lua_Object o) -{ - int t = lua_tag(o); - return (t == LUA_T_FUNCTION) || (t == LUA_T_CFUNCTION) || - (t == LUA_T_MARK) || (t == LUA_T_CMARK); -} - -/* -** Given an object handle, return its number value. On error, return 0.0. -*/ -real lua_getnumber (lua_Object object) -{ - if (object == LUA_NOOBJECT) return 0.0; - if (tonumber (Address(object))) return 0.0; - else return (nvalue(Address(object))); -} - -/* -** Given an object handle, return its string pointer. On error, return NULL. -*/ -char *lua_getstring (lua_Object object) -{ - if (object == LUA_NOOBJECT || tostring (Address(object))) - return NULL; - else return (svalue(Address(object))); -} - - -void *lua_getuserdata (lua_Object object) -{ - if (object == LUA_NOOBJECT || ttype(Address(object)) != LUA_T_USERDATA) - return NULL; - else return tsvalue(Address(object))->u.v; -} - - -/* -** Given an object handle, return its cfuntion pointer. On error, return NULL. -*/ -lua_CFunction lua_getcfunction (lua_Object object) -{ - if (object == LUA_NOOBJECT || ((ttype(Address(object)) != LUA_T_CFUNCTION) && - (ttype(Address(object)) != LUA_T_CMARK))) - return NULL; - else return (fvalue(Address(object))); -} - - -lua_Object lua_getref (int ref) -{ - TObject *o = luaI_getref(ref); - if (o == NULL) - return LUA_NOOBJECT; - return put_luaObject(o); -} - - -int lua_ref (int lock) -{ - checkCparams(1); - return luaI_ref(--top, lock); -} - - - -/* -** Get a global object. -*/ -lua_Object lua_getglobal (char *name) -{ - getglobal(luaI_findsymbolbyname(name)); - return put_luaObjectonTop(); -} - - -lua_Object lua_rawgetglobal (char *name) -{ - return put_luaObject(&lua_table[luaI_findsymbolbyname(name)].object); -} - - -/* -** Store top of the stack at a global variable array field. -*/ -static void setglobal (Word n) -{ - TObject *oldvalue = &lua_table[n].object; - TObject *im = luaI_getimbyObj(oldvalue, IM_SETGLOBAL); - if (ttype(im) == LUA_T_NIL) /* default behavior */ - s_object(n) = *(--top); - else { - TObject newvalue = *(top-1); - ttype(top-1) = LUA_T_STRING; - tsvalue(top-1) = lua_table[n].varname; - *top = *oldvalue; - incr_top; - *top = newvalue; - incr_top; - callIM(im, 3, 0); - } -} - - -void lua_setglobal (char *name) -{ - checkCparams(1); - setglobal(luaI_findsymbolbyname(name)); -} - -void lua_rawsetglobal (char *name) -{ - Word n = luaI_findsymbolbyname(name); - checkCparams(1); - s_object(n) = *(--top); -} - -/* -** Push a nil object -*/ -void lua_pushnil (void) -{ - ttype(top) = LUA_T_NIL; - incr_top; -} - -/* -** Push an object (ttype=number) to stack. -*/ -void lua_pushnumber (real n) -{ - ttype(top) = LUA_T_NUMBER; nvalue(top) = n; - incr_top; -} - -/* -** Push an object (ttype=string) to stack. -*/ -void lua_pushstring (char *s) -{ - if (s == NULL) - ttype(top) = LUA_T_NIL; - else - { - tsvalue(top) = lua_createstring(s); - ttype(top) = LUA_T_STRING; - } - incr_top; -} - - -/* -** Push an object (ttype=cfunction) to stack. -*/ -void lua_pushcfunction (lua_CFunction fn) -{ - ttype(top) = LUA_T_CFUNCTION; fvalue(top) = fn; - incr_top; -} - - - -void lua_pushusertag (void *u, int tag) -{ - if (tag < 0 && tag != LUA_ANYTAG) - luaI_realtag(tag); /* error if tag is not valid */ - tsvalue(top) = luaI_createudata(u, tag); - ttype(top) = LUA_T_USERDATA; - incr_top; -} - -/* -** Push an object on the stack. -*/ -void luaI_pushobject (TObject *o) -{ - *top = *o; - incr_top; -} - -/* -** Push a lua_Object on stack. -*/ -void lua_pushobject (lua_Object o) -{ - if (o == LUA_NOOBJECT) - lua_error("API error - attempt to push a NOOBJECT"); - *top = *Address(o); - if (ttype(top) == LUA_T_MARK) ttype(top) = LUA_T_FUNCTION; - else if (ttype(top) == LUA_T_CMARK) ttype(top) = LUA_T_CFUNCTION; - incr_top; -} - -int lua_tag (lua_Object lo) -{ - if (lo == LUA_NOOBJECT) return LUA_T_NIL; - else { - TObject *o = Address(lo); - lua_Type t = ttype(o); - if (t == LUA_T_USERDATA) - return o->value.ts->tag; - else if (t == LUA_T_ARRAY) - return o->value.a->htag; - else return t; - } -} - - -void luaI_gcIM (TObject *o) -{ - TObject *im = luaI_getimbyObj(o, IM_GC); - if (ttype(im) != LUA_T_NIL) { - *top = *o; - incr_top; - callIM(im, 1, 0); - } -} - - -static void call_binTM (IMS event, char *msg) -{ - TObject *im = luaI_getimbyObj(top-2, event); /* try first operand */ - if (ttype(im) == LUA_T_NIL) { - im = luaI_getimbyObj(top-1, event); /* try second operand */ - if (ttype(im) == LUA_T_NIL) { - im = luaI_getim(0, event); /* try a 'global' i.m. */ - if (ttype(im) == LUA_T_NIL) - lua_error(msg); - } - } - lua_pushstring(luaI_eventname[event]); - callIM(im, 3, 1); -} - - -static void call_arith (IMS event) -{ - call_binTM(event, "unexpected type at arithmetic operation"); -} - - -static void comparison (lua_Type ttype_less, lua_Type ttype_equal, - lua_Type ttype_great, IMS op) -{ - TObject *l = top-2; - TObject *r = top-1; - int result; - if (ttype(l) == LUA_T_NUMBER && ttype(r) == LUA_T_NUMBER) - result = (nvalue(l) < nvalue(r)) ? -1 : (nvalue(l) == nvalue(r)) ? 0 : 1; - else if (ttype(l) == LUA_T_STRING && ttype(r) == LUA_T_STRING) - result = strcmp(svalue(l), svalue(r)); - else { - call_binTM(op, "unexpected type at comparison"); - return; - } - top--; - nvalue(top-1) = 1; - ttype(top-1) = (result < 0) ? ttype_less : - (result == 0) ? ttype_equal : ttype_great; -} - - -static void adjust_varargs (StkId first_extra_arg) -{ - TObject arg; - TObject *firstelem = stack+first_extra_arg; - int nvararg = top-firstelem; - int i; - if (nvararg < 0) nvararg = 0; - avalue(&arg) = lua_createarray(nvararg+1); /* +1 for field 'n' */ - ttype(&arg) = LUA_T_ARRAY; - for (i=0; ittype = LUA_T_FUNCTION; - top->value.tf = f; - incr_top; - } - break; - - case PUSHLOCAL0: case PUSHLOCAL1: case PUSHLOCAL2: - case PUSHLOCAL3: case PUSHLOCAL4: case PUSHLOCAL5: - case PUSHLOCAL6: case PUSHLOCAL7: case PUSHLOCAL8: - case PUSHLOCAL9: - *top = *((stack+base) + (int)(opcode-PUSHLOCAL0)); incr_top; break; - - case PUSHLOCAL: *top = *((stack+base) + (*pc++)); incr_top; break; - - case PUSHGLOBAL: - { - Word w; - get_word(w,pc); - getglobal(w); - } - break; - - case PUSHINDEXED: - pushsubscript(); - break; - - case PUSHSELF: - { - TObject receiver = *(top-1); - Word w; - get_word(w,pc); - ttype(top) = LUA_T_STRING; tsvalue(top) = lua_constant[w]; - incr_top; - pushsubscript(); - *top = receiver; - incr_top; - break; - } - - case STORELOCAL0: case STORELOCAL1: case STORELOCAL2: - case STORELOCAL3: case STORELOCAL4: case STORELOCAL5: - case STORELOCAL6: case STORELOCAL7: case STORELOCAL8: - case STORELOCAL9: - *((stack+base) + (int)(opcode-STORELOCAL0)) = *(--top); - break; - - case STORELOCAL: *((stack+base) + (*pc++)) = *(--top); break; - - case STOREGLOBAL: - { - Word w; - get_word(w,pc); - setglobal(w); - } - break; - - case STOREINDEXED0: - storesubscript(top-3, 1); - break; - - case STOREINDEXED: { - int n = *pc++; - storesubscript(top-3-n, 2); - break; - } - - case STORELIST0: - case STORELIST: - { - int m, n; - TObject *arr; - if (opcode == STORELIST0) m = 0; - else m = *(pc++) * FIELDS_PER_FLUSH; - n = *(pc++); - arr = top-n-1; - while (n) - { - ttype(top) = LUA_T_NUMBER; nvalue(top) = n+m; - *(lua_hashdefine (avalue(arr), top)) = *(top-1); - top--; - n--; - } - } - break; - - case STORERECORD: /* opcode obsolete: supersed by STOREMAP */ - { - int n = *(pc++); - TObject *arr = top-n-1; - while (n) - { - Word w; - get_word(w,pc); - ttype(top) = LUA_T_STRING; tsvalue(top) = lua_constant[w]; - *(lua_hashdefine (avalue(arr), top)) = *(top-1); - top--; - n--; - } - } - break; - - case STOREMAP: { - int n = *(pc++); - TObject *arr = top-(2*n)-1; - while (n--) { - *(lua_hashdefine (avalue(arr), top-2)) = *(top-1); - top-=2; - } - } - break; - - case ADJUST0: - adjust_top(base); - break; - - case ADJUST: { - StkId newtop = base + *(pc++); - adjust_top(newtop); - break; - } - - case VARARGS: - adjust_varargs(base + *(pc++)); - break; - - case CREATEARRAY: - { - Word size; - get_word(size,pc); - avalue(top) = lua_createarray(size); - ttype(top) = LUA_T_ARRAY; - incr_top; - } - break; - - case EQOP: - { - int res = lua_equalObj(top-2, top-1); - --top; - ttype(top-1) = res ? LUA_T_NUMBER : LUA_T_NIL; - nvalue(top-1) = 1; - } - break; - - case LTOP: - comparison(LUA_T_NUMBER, LUA_T_NIL, LUA_T_NIL, IM_LT); - break; - - case LEOP: - comparison(LUA_T_NUMBER, LUA_T_NUMBER, LUA_T_NIL, IM_LE); - break; - - case GTOP: - comparison(LUA_T_NIL, LUA_T_NIL, LUA_T_NUMBER, IM_GT); - break; - - case GEOP: - comparison(LUA_T_NIL, LUA_T_NUMBER, LUA_T_NUMBER, IM_GE); - break; - - case ADDOP: - { - TObject *l = top-2; - TObject *r = top-1; - if (tonumber(r) || tonumber(l)) - call_arith(IM_ADD); - else - { - nvalue(l) += nvalue(r); - --top; - } - } - break; - - case SUBOP: - { - TObject *l = top-2; - TObject *r = top-1; - if (tonumber(r) || tonumber(l)) - call_arith(IM_SUB); - else - { - nvalue(l) -= nvalue(r); - --top; - } - } - break; - - case MULTOP: - { - TObject *l = top-2; - TObject *r = top-1; - if (tonumber(r) || tonumber(l)) - call_arith(IM_MUL); - else - { - nvalue(l) *= nvalue(r); - --top; - } - } - break; - - case DIVOP: - { - TObject *l = top-2; - TObject *r = top-1; - if (tonumber(r) || tonumber(l)) - call_arith(IM_DIV); - else - { - nvalue(l) /= nvalue(r); - --top; - } - } - break; - - case POWOP: - call_arith(IM_POW); - break; - - case CONCOP: { - TObject *l = top-2; - TObject *r = top-1; - if (tostring(l) || tostring(r)) - call_binTM(IM_CONCAT, "unexpected type for concatenation"); - else { - tsvalue(l) = lua_createstring(lua_strconc(svalue(l),svalue(r))); - --top; - } - } - break; - - case MINUSOP: - if (tonumber(top-1)) - { - ttype(top) = LUA_T_NIL; - incr_top; - call_arith(IM_UNM); - } - else - nvalue(top-1) = - nvalue(top-1); - break; - - case NOTOP: - ttype(top-1) = (ttype(top-1) == LUA_T_NIL) ? LUA_T_NUMBER : LUA_T_NIL; - nvalue(top-1) = 1; - break; - - case ONTJMP: - { - Word w; - get_word(w,pc); - if (ttype(top-1) != LUA_T_NIL) pc += w; - } - break; - - case ONFJMP: - { - Word w; - get_word(w,pc); - if (ttype(top-1) == LUA_T_NIL) pc += w; - } - break; - - case JMP: - { - Word w; - get_word(w,pc); - pc += w; - } - break; - - case UPJMP: - { - Word w; - get_word(w,pc); - pc -= w; - } - break; - - case IFFJMP: - { - Word w; - get_word(w,pc); - top--; - if (ttype(top) == LUA_T_NIL) pc += w; - } - break; - - case IFFUPJMP: - { - Word w; - get_word(w,pc); - top--; - if (ttype(top) == LUA_T_NIL) pc -= w; - } - break; - - case POP: --top; break; - - case CALLFUNC: - { - int nParams = *(pc++); - int nResults = *(pc++); - StkId newBase = (top-stack)-nParams; - do_call(newBase, nResults); - } - break; - - case RETCODE0: - case RETCODE: - if (lua_callhook) - callHook (base, LUA_T_MARK, 1); - return (base + ((opcode==RETCODE0) ? 0 : *pc)); - - case SETLINE: - { - Word line; - get_word(line,pc); - if ((stack+base-1)->ttype != LUA_T_LINE) - { - /* open space for LINE value */ - open_stack((top-stack)-base); - base++; - (stack+base-1)->ttype = LUA_T_LINE; - } - (stack+base-1)->value.i = line; - if (lua_linehook) - lineHook (line); - break; - } - - default: - lua_error ("internal error - opcode doesn't match"); - } - } -} - - -#if COMPAT2_5 -/* -** API: set a function as a fallback -*/ -lua_Object lua_setfallback (char *name, lua_CFunction fallback) -{ - lua_pushstring(name); - lua_pushcfunction(fallback); - do_unprotectedrun(luaI_setfallback, 2, 1); - return put_luaObjectonTop(); -} -#endif diff --git a/src/opcode.h b/src/opcode.h deleted file mode 100644 index 0b63de9..0000000 --- a/src/opcode.h +++ /dev/null @@ -1,171 +0,0 @@ -/* -** TeCGraf - PUC-Rio -** $Id: opcode.h,v 3.34 1997/06/16 16:50:22 roberto Exp $ -*/ - -#ifndef opcode_h -#define opcode_h - -#include "lua.h" -#include "types.h" -#include "tree.h" -#include "func.h" - - -#define FIELDS_PER_FLUSH 40 - -/* -* WARNING: if you change the order of this enumeration, -* grep "ORDER LUA_T" -*/ -typedef enum -{ - LUA_T_NIL = -9, - LUA_T_NUMBER = -8, - LUA_T_STRING = -7, - LUA_T_ARRAY = -6, /* array==table */ - LUA_T_FUNCTION = -5, - LUA_T_CFUNCTION= -4, - LUA_T_MARK = -3, - LUA_T_CMARK = -2, - LUA_T_LINE = -1, - LUA_T_USERDATA = 0 -} lua_Type; - -#define NUM_TYPES 10 - - -extern char *luaI_typenames[]; - -typedef enum { -/* name parm before after side effect ------------------------------------------------------------------------------*/ - -PUSHNIL,/* - nil */ -PUSH0,/* - 0.0 */ -PUSH1,/* - 1.0 */ -PUSH2,/* - 2.0 */ -PUSHBYTE,/* b - (float)b */ -PUSHWORD,/* w - (float)w */ -PUSHFLOAT,/* f - f */ -PUSHSTRING,/* w - STR[w] */ -PUSHFUNCTION,/* p - FUN(p) */ -PUSHLOCAL0,/* - LOC[0] */ -PUSHLOCAL1,/* - LOC[1] */ -PUSHLOCAL2,/* - LOC[2] */ -PUSHLOCAL3,/* - LOC[3] */ -PUSHLOCAL4,/* - LOC[4] */ -PUSHLOCAL5,/* - LOC[5] */ -PUSHLOCAL6,/* - LOC[6] */ -PUSHLOCAL7,/* - LOC[7] */ -PUSHLOCAL8,/* - LOC[8] */ -PUSHLOCAL9,/* - LOC[9] */ -PUSHLOCAL,/* b - LOC[b] */ -PUSHGLOBAL,/* w - VAR[w] */ -PUSHINDEXED,/* i t t[i] */ -PUSHSELF,/* w t t t[STR[w]] */ -STORELOCAL0,/* x - LOC[0]=x */ -STORELOCAL1,/* x - LOC[1]=x */ -STORELOCAL2,/* x - LOC[2]=x */ -STORELOCAL3,/* x - LOC[3]=x */ -STORELOCAL4,/* x - LOC[4]=x */ -STORELOCAL5,/* x - LOC[5]=x */ -STORELOCAL6,/* x - LOC[6]=x */ -STORELOCAL7,/* x - LOC[7]=x */ -STORELOCAL8,/* x - LOC[8]=x */ -STORELOCAL9,/* x - LOC[9]=x */ -STORELOCAL,/* b x - LOC[b]=x */ -STOREGLOBAL,/* w x - VAR[w]=x */ -STOREINDEXED0,/* v i t - t[i]=v */ -STOREINDEXED,/* b v a_b...a_1 i t a_b...a_1 i t t[i]=v */ -STORELIST0,/* b v_b...v_1 t - t[i]=v_i */ -STORELIST,/* b c v_b...v_1 t - t[i+c*FPF]=v_i */ -STORERECORD,/* b - w_b...w_1 v_b...v_1 t - t[STR[w_i]]=v_i */ -ADJUST0,/* - - TOP=BASE */ -ADJUST,/* b - - TOP=BASE+b */ -CREATEARRAY,/* w - newarray(size = w) */ -EQOP,/* y x (x==y)? 1 : nil */ -LTOP,/* y x (xy)? 1 : nil */ -GEOP,/* y x (x>=y)? 1 : nil */ -ADDOP,/* y x x+y */ -SUBOP,/* y x x-y */ -MULTOP,/* y x x*y */ -DIVOP,/* y x x/y */ -POWOP,/* y x x^y */ -CONCOP,/* y x x..y */ -MINUSOP,/* x -x */ -NOTOP,/* x (x==nil)? 1 : nil */ -ONTJMP,/* w x - (x!=nil)? PC+=w */ -ONFJMP,/* w x - (x==nil)? PC+=w */ -JMP,/* w - - PC+=w */ -UPJMP,/* w - - PC-=w */ -IFFJMP,/* w x - (x==nil)? PC+=w */ -IFFUPJMP,/* w x - (x==nil)? PC-=w */ -POP,/* x - */ -CALLFUNC,/* b c v_b...v_1 f r_c...r_1 f(v1,...,v_b) */ -RETCODE0, -RETCODE,/* b - - */ -SETLINE,/* w - - LINE=w */ -VARARGS,/* b v_b...v_1 {v_1...v_b;n=b} */ -STOREMAP/* b v_b k_b ...v_1 k_1 t - t[k_i]=v_i */ -} OpCode; - - -#define MULT_RET 255 - - -typedef union -{ - lua_CFunction f; - real n; - TaggedString *ts; - TFunc *tf; - struct Hash *a; - int i; -} Value; - -typedef struct TObject -{ - lua_Type ttype; - Value value; -} TObject; - - -/* Macros to access structure members */ -#define ttype(o) ((o)->ttype) -#define nvalue(o) ((o)->value.n) -#define svalue(o) ((o)->value.ts->str) -#define tsvalue(o) ((o)->value.ts) -#define avalue(o) ((o)->value.a) -#define fvalue(o) ((o)->value.f) - -/* Macros to access symbol table */ -#define s_object(i) (lua_table[i].object) -#define s_ttype(i) (ttype(&s_object(i))) -#define s_nvalue(i) (nvalue(&s_object(i))) -#define s_svalue(i) (svalue(&s_object(i))) -#define s_tsvalue(i) (tsvalue(&s_object(i))) -#define s_avalue(i) (avalue(&s_object(i))) -#define s_fvalue(i) (fvalue(&s_object(i))) -#define s_uvalue(i) (uvalue(&s_object(i))) - -#define get_word(code,pc) {memcpy(&code, pc, sizeof(Word)); pc+=sizeof(Word);} -#define get_float(code,pc){memcpy(&code, pc, sizeof(real)); pc+=sizeof(real);} -#define get_code(code,pc) {memcpy(&code, pc, sizeof(TFunc *)); \ - pc+=sizeof(TFunc *);} - - -/* Exported functions */ -void lua_parse (TFunc *tf); /* from "lua.stx" module */ -void luaI_codedebugline (int line); /* from "lua.stx" module */ -void lua_travstack (int (*fn)(TObject *)); -TObject *luaI_Address (lua_Object o); -void luaI_pushobject (TObject *o); -void luaI_gcIM (TObject *o); -int luaI_dorun (TFunc *tf); -int lua_domain (void); - -#endif diff --git a/src/parser.c b/src/parser.c deleted file mode 100644 index ad5f8d6..0000000 --- a/src/parser.c +++ /dev/null @@ -1,1696 +0,0 @@ -#ifndef lint -static char luaY_sccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93"; -#endif -#define YYBYACC 1 -#define YYMAJOR 1 -#define YYMINOR 9 -#define luaY_clearin (luaY_char=(-1)) -#define luaY_errok (luaY_errflag=0) -#define YYRECOVERING (luaY_errflag!=0) -#define YYPREFIX "luaY_" -#line 2 "lua.stx" - -char *rcs_luastx = "$Id: parser.c,v 1.1 1997/06/30 18:59:03 lhf Exp $"; - -#include -#include -#include - -#include "luadebug.h" -#include "luamem.h" -#include "lex.h" -#include "opcode.h" -#include "hash.h" -#include "inout.h" -#include "tree.h" -#include "table.h" -#include "lua.h" -#include "func.h" - -/* to avoid warnings generated by yacc */ -int luaY_parse (void); -#define malloc luaI_malloc -#define realloc luaI_realloc -#define free luaI_free - -#ifndef LISTING -#define LISTING 0 -#endif - -#ifndef CODE_BLOCK -#define CODE_BLOCK 256 -#endif -static int maxcode; -static int maxmain; -static int maxcurr; -static Byte *funcCode = NULL; -static Byte **initcode; -static Byte *basepc; -static int maincode; -static int pc; - - -#define MAXVAR 32 -static Long varbuffer[MAXVAR]; /* variables in an assignment list; - it's long to store negative Word values */ -static int nvarbuffer=0; /* number of variables at a list */ - -#define MAXLOCALS 32 -static TaggedString *localvar[MAXLOCALS]; /* store local variable names */ -static int nlocalvar=0; /* number of local variables */ - -#define MAXFIELDS FIELDS_PER_FLUSH*2 - -int lua_debug = 0; - -/* Internal functions */ - -static void luaY_error (char *s) -{ - luaI_syntaxerror(s); -} - -static void check_space (int i) -{ - if (pc+i>maxcurr-1) /* 1 byte free to code HALT of main code */ - maxcurr = growvector(&basepc, maxcurr, Byte, codeEM, MAX_INT); -} - -static void code_byte (Byte c) -{ - check_space(1); - basepc[pc++] = c; -} - -static void code_word (Word n) -{ - check_space(sizeof(Word)); - memcpy(basepc+pc, &n, sizeof(Word)); - pc += sizeof(Word); -} - -static void code_float (real n) -{ - check_space(sizeof(real)); - memcpy(basepc+pc, &n, sizeof(real)); - pc += sizeof(real); -} - -static void code_code (TFunc *tf) -{ - check_space(sizeof(TFunc *)); - memcpy(basepc+pc, &tf, sizeof(TFunc *)); - pc += sizeof(TFunc *); -} - -static void code_word_at (Byte *p, int n) -{ - Word w = n; - if (w != n) - luaY_error("block too big"); - memcpy(p, &w, sizeof(Word)); -} - -static void flush_record (int n) -{ - if (n == 0) return; - code_byte(STOREMAP); - code_byte(n); -} - -static void flush_list (int m, int n) -{ - if (n == 0) return; - if (m == 0) - code_byte(STORELIST0); - else - if (m < 255) - { - code_byte(STORELIST); - code_byte(m); - } - else - luaY_error ("list constructor too long"); - code_byte(n); -} - -static void store_localvar (TaggedString *name, int n) -{ - if (nlocalvar+n < MAXLOCALS) - localvar[nlocalvar+n] = name; - else - luaY_error ("too many local variables"); - if (lua_debug) - luaI_registerlocalvar(name, lua_linenumber); -} - -static void add_localvar (TaggedString *name) -{ - store_localvar(name, 0); - nlocalvar++; -} - -static void add_varbuffer (Long var) -{ - if (nvarbuffer < MAXVAR) - varbuffer[nvarbuffer++] = var; - else - luaY_error ("variable buffer overflow"); -} - -static void code_string (Word w) -{ - code_byte(PUSHSTRING); - code_word(w); -} - -static void code_constant (TaggedString *s) -{ - code_string(luaI_findconstant(s)); -} - -static void code_number (float f) -{ - Word i; - if (f >= 0 && f <= (float)MAX_WORD && (float)(i=(Word)f) == f) { - /* f has an (short) integer value */ - if (i <= 2) code_byte(PUSH0 + i); - else if (i <= 255) - { - code_byte(PUSHBYTE); - code_byte(i); - } - else - { - code_byte(PUSHWORD); - code_word(i); - } - } - else - { - code_byte(PUSHFLOAT); - code_float(f); - } -} - -/* -** Search a local name and if find return its index. If do not find return -1 -*/ -static int lua_localname (TaggedString *n) -{ - int i; - for (i=nlocalvar-1; i >= 0; i--) - if (n == localvar[i]) return i; /* local var */ - return -1; /* global var */ -} - -/* -** Push a variable given a number. If number is positive, push global variable -** indexed by (number -1). If negative, push local indexed by ABS(number)-1. -** Otherwise, if zero, push indexed variable (record). -*/ -static void lua_pushvar (Long number) -{ - if (number > 0) /* global var */ - { - code_byte(PUSHGLOBAL); - code_word(number-1); - } - else if (number < 0) /* local var */ - { - number = (-number) - 1; - if (number < 10) code_byte(PUSHLOCAL0 + number); - else - { - code_byte(PUSHLOCAL); - code_byte(number); - } - } - else - { - code_byte(PUSHINDEXED); - } -} - -static void lua_codeadjust (int n) -{ - if (n+nlocalvar == 0) - code_byte(ADJUST0); - else - { - code_byte(ADJUST); - code_byte(n+nlocalvar); - } -} - -static void change2main (void) -{ - /* (re)store main values */ - pc=maincode; basepc=*initcode; maxcurr=maxmain; - nlocalvar=0; -} - -static void savemain (void) -{ - /* save main values */ - maincode=pc; *initcode=basepc; maxmain=maxcurr; -} - -static void init_func (void) -{ - if (funcCode == NULL) /* first function */ - { - funcCode = newvector(CODE_BLOCK, Byte); - maxcode = CODE_BLOCK; - } - savemain(); /* save main values */ - /* set func values */ - pc=0; basepc=funcCode; maxcurr=maxcode; - nlocalvar = 0; - luaI_codedebugline(lua_linenumber); -} - -static void codereturn (void) -{ - if (nlocalvar == 0) - code_byte(RETCODE0); - else - { - code_byte(RETCODE); - code_byte(nlocalvar); - } -} - -void luaI_codedebugline (int line) -{ - static int lastline = 0; - if (lua_debug && line != lastline) - { - code_byte(SETLINE); - code_word(line); - lastline = line; - } -} - -static int adjust_functioncall (Long exp, int i) -{ - if (exp <= 0) - return -exp; /* exp is -list length */ - else - { - int temp = basepc[exp]; - basepc[exp] = i; - return temp+i; - } -} - -static void adjust_mult_assign (int vars, Long exps, int temps) -{ - if (exps > 0) - { /* must correct function call */ - int diff = vars - basepc[exps]; - if (diff >= 0) - adjust_functioncall(exps, diff); - else - { - adjust_functioncall(exps, 0); - lua_codeadjust(temps); - } - } - else if (vars != -exps) - lua_codeadjust(temps); -} - -static int close_parlist (int dots) -{ - if (!dots) - lua_codeadjust(0); - else - { - code_byte(VARARGS); - code_byte(nlocalvar); - add_localvar(luaI_createfixedstring("arg")); - } - return lua_linenumber; -} - -static void storesinglevar (Long v) -{ - if (v > 0) /* global var */ - { - code_byte(STOREGLOBAL); - code_word(v-1); - } - else if (v < 0) /* local var */ - { - int number = (-v) - 1; - if (number < 10) code_byte(STORELOCAL0 + number); - else - { - code_byte(STORELOCAL); - code_byte(number); - } - } - else - code_byte(STOREINDEXED0); -} - -static void lua_codestore (int i) -{ - if (varbuffer[i] != 0) /* global or local var */ - storesinglevar(varbuffer[i]); - else /* indexed var */ - { - int j; - int upper=0; /* number of indexed variables upper */ - int param; /* number of itens until indexed expression */ - for (j=i+1; j code); - *initcode = newvector(CODE_BLOCK, Byte); - maincode = 0; - maxmain = CODE_BLOCK; - change2main(); - if (luaY_parse ()) lua_error("parse error"); - savemain(); - (*initcode)[maincode++] = RETCODE0; - tf->size = maincode; -#if LISTING -{ static void PrintCode (Byte *c, Byte *end); - PrintCode(*initcode,*initcode+maincode); } -#endif -} - - -#line 412 "lua.stx" -typedef union -{ - int vInt; - float vFloat; - char *pChar; - Word vWord; - Long vLong; - TFunc *pFunc; - TaggedString *pTStr; -} YYSTYPE; -#line 431 "y.tab.c" -#define WRONGTOKEN 257 -#define NIL 258 -#define IF 259 -#define THEN 260 -#define ELSE 261 -#define ELSEIF 262 -#define WHILE 263 -#define DO 264 -#define REPEAT 265 -#define UNTIL 266 -#define END 267 -#define RETURN 268 -#define LOCAL 269 -#define FUNCTION 270 -#define DOTS 271 -#define NUMBER 272 -#define STRING 273 -#define NAME 274 -#define AND 275 -#define OR 276 -#define EQ 277 -#define NE 278 -#define LE 279 -#define GE 280 -#define CONC 281 -#define UNARY 282 -#define NOT 283 -#define YYERRCODE 256 -short luaY_lhs[] = { -1, - 0, 24, 24, 24, 28, 22, 22, 23, 31, 31, - 27, 27, 26, 34, 26, 35, 26, 26, 26, 26, - 33, 33, 33, 36, 30, 25, 25, 1, 32, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 38, 5, 39, 5, 40, 37, 4, 8, 8, 7, - 7, 2, 2, 3, 41, 3, 17, 17, 18, 18, - 19, 19, 42, 9, 9, 14, 14, 43, 43, 12, - 12, 13, 13, 44, 45, 45, 15, 15, 16, 16, - 6, 6, 20, 20, 20, 21, 29, 10, 10, 11, - 11, -}; -short luaY_len[] = { 2, - 2, 0, 3, 2, 3, 1, 3, 5, 0, 3, - 0, 1, 8, 0, 8, 0, 6, 3, 1, 3, - 0, 2, 7, 0, 3, 0, 3, 0, 1, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 2, 1, 1, 1, 1, 1, 1, 2, - 0, 5, 0, 5, 0, 4, 2, 1, 3, 3, - 1, 0, 1, 1, 0, 4, 0, 1, 1, 3, - 1, 1, 0, 3, 2, 0, 2, 0, 1, 0, - 2, 1, 3, 3, 3, 1, 0, 2, 1, 3, - 1, 3, 1, 4, 3, 1, 1, 1, 3, 0, - 2, -}; -short luaY_defred[] = { 2, - 0, 0, 0, 14, 16, 0, 0, 0, 96, 19, - 0, 0, 0, 93, 1, 0, 4, 0, 48, 46, - 47, 0, 0, 0, 49, 29, 97, 0, 0, 44, - 0, 0, 24, 0, 0, 0, 0, 98, 0, 0, - 0, 0, 0, 0, 0, 57, 61, 12, 3, 0, - 0, 0, 0, 0, 0, 28, 28, 28, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 9, 27, 65, 0, 0, 20, 0, - 5, 0, 0, 0, 0, 0, 59, 0, 95, 30, - 24, 51, 53, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 73, - 0, 0, 82, 0, 28, 0, 0, 0, 0, 99, - 72, 71, 0, 0, 69, 7, 60, 94, 28, 0, - 0, 0, 56, 0, 75, 0, 0, 88, 0, 24, - 0, 25, 0, 0, 24, 0, 0, 0, 0, 85, - 86, 83, 0, 74, 0, 0, 28, 17, 10, 0, - 70, 24, 0, 0, 77, 0, 0, 8, 22, 0, - 13, 81, 15, 28, 24, 28, 0, 23, -}; -short luaY_dgoto[] = { 1, - 91, 34, 35, 25, 26, 11, 46, 12, 108, 39, - 79, 165, 109, 154, 110, 111, 123, 124, 125, 27, - 14, 41, 81, 2, 15, 16, 49, 17, 28, 73, - 117, 37, 164, 32, 33, 74, 30, 130, 131, 31, - 118, 136, 135, 113, 114, -}; -short luaY_sindex[] = { 0, - 0, 288, -34, 0, 0, -34, -238, -223, 0, 0, - -6, 22, 0, 0, 0, 14, 0, 150, 0, 0, - 0, -34, -34, -34, 0, 0, 0, 150, 547, 0, - -46, -34, 0, 14, 34, 0, 212, 0, -5, 0, - 39, 156, -34, -223, -34, 0, 0, 0, 0, -194, - -34, -193, -4, -4, 48, 0, 0, 0, -34, -34, - -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, - -38, 481, -173, 0, 0, 0, -34, -146, 0, -234, - 0, -138, 34, 0, -15, 96, 0, 753, 0, 0, - 0, 0, 0, -30, -30, -30, -30, -30, -30, -20, - -12, -12, -4, -4, -4, 0, -34, 16, 95, 0, - 98, 212, 0, 82, 0, -34, 328, -34, 34, 0, - 0, 0, 103, 101, 0, 0, 0, 0, 0, -34, - -34, 1181, 0, -91, 0, 92, -34, 0, -34, 0, - 212, 0, 14, 0, 0, -234, -233, 118, 118, 0, - 0, 0, -91, 0, 212, 212, 0, 0, 0, -105, - 0, 0, -34, -103, 0, 95, -101, 0, 0, 1105, - 0, 0, 0, 0, 0, 0, -233, 0, -}; -short luaY_rindex[] = { 0, - 0, 169, 52, 0, 0, 173, 0, 0, 0, 0, - 0, 52, 508, 0, 0, 146, 0, -36, 0, 0, - 0, 52, 52, 52, 0, 0, 0, 1, 0, 0, - 0, 52, 0, 47, 461, 436, 0, 0, 197, 76, - 0, 0, 52, 0, -32, 0, 0, 0, 0, 0, - 52, 0, 24, 59, 1195, 0, 0, 0, 52, 52, - 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - -27, 0, 0, 0, 0, 0, 52, 0, 0, 129, - 0, 0, 311, 142, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 746, 776, 799, 821, 844, 866, 505, - 383, 410, 88, 112, 359, 1174, 52, 0, 51, 0, - -40, -10, 0, 0, 0, 52, -153, 52, 921, 0, - 0, 0, 0, 144, 0, 0, 0, 0, 0, 52, - 52, 0, 0, 62, 0, 64, -26, 0, 52, 0, - 939, 0, 682, 474, 0, 0, -77, 894, 1137, 0, - 0, 0, 66, 0, 13, -18, 0, 0, 0, 0, - 0, 0, 52, 0, 0, 51, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, -77, 0, -}; -short luaY_gindex[] = { 0, - 53, 147, -23, 3, 134, 0, 0, 0, 0, 0, - 0, 0, 40, 0, 0, 0, 0, 0, 49, 6, - 0, 0, 0, 0, 81, 83, -16, 0, 8, -70, - 0, 1445, 27, 0, 0, 0, 187, 0, 0, 0, - 0, 0, -108, 67, 0, -}; -#define YYTABLESIZE 1608 -short luaY_table[] = { 107, - 45, 24, 138, 58, 10, 24, 22, 13, 62, 18, - 22, 68, 66, 40, 67, 42, 69, 75, 78, 83, - 129, 68, 66, 43, 67, 84, 69, 162, 163, 68, - 52, 87, 79, 89, 69, 38, 121, 44, 78, 122, - 58, 45, 45, 45, 45, 45, 11, 45, 89, 84, - 9, 85, 107, 119, 43, 77, 90, 172, 50, 45, - 45, 45, 45, 70, 43, 43, 43, 43, 43, 157, - 43, 90, 48, 70, 160, 51, 71, 76, 80, 87, - 89, 70, 43, 43, 78, 43, 58, 39, 90, 70, - 55, 169, 116, 45, 45, 55, 55, 87, 79, 50, - 50, 50, 50, 50, 176, 50, 84, 26, 26, 92, - 93, 40, 26, 26, 89, 6, 43, 50, 50, 10, - 50, 97, 13, 58, 18, 45, 159, 120, 39, 39, - 39, 39, 39, 97, 39, 126, 127, 90, 134, 36, - 133, 137, 139, 145, 146, 11, 39, 39, 43, 39, - 153, 50, 40, 40, 40, 40, 40, 55, 40, 68, - 66, 168, 67, 171, 69, 173, 97, 140, 26, 67, - 40, 40, 62, 40, 55, 78, 36, 62, 36, 61, - 39, 147, 151, 50, 68, 92, 79, 97, 76, 21, - 80, 86, 166, 158, 161, 52, 100, 142, 47, 143, - 152, 52, 92, 178, 40, 0, 0, 50, 0, 167, - 36, 70, 39, 82, 0, 0, 0, 0, 0, 19, - 0, 0, 0, 19, 0, 0, 175, 0, 177, 0, - 0, 62, 97, 20, 21, 106, 40, 20, 21, 9, - 51, 0, 0, 0, 23, 0, 51, 0, 23, 0, - 65, 144, 0, 68, 66, 100, 67, 0, 69, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 62, 0, 61, 45, 45, 45, 45, 45, 45, - 45, 45, 43, 43, 43, 43, 43, 43, 43, 43, - 43, 43, 43, 43, 0, 55, 0, 43, 43, 43, - 43, 43, 43, 43, 43, 70, 0, 11, 11, 0, - 18, 0, 11, 11, 0, 0, 0, 50, 50, 50, - 50, 50, 50, 50, 50, 50, 50, 50, 50, 0, - 0, 0, 50, 50, 50, 50, 50, 50, 50, 50, - 0, 0, 0, 0, 0, 0, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 41, 0, - 0, 39, 39, 39, 39, 39, 39, 39, 39, 18, - 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, - 40, 40, 37, 0, 0, 40, 40, 40, 40, 40, - 40, 40, 40, 0, 59, 60, 63, 64, 65, 41, - 41, 41, 41, 41, 11, 41, 0, 0, 11, 38, - 11, 0, 0, 11, 11, 11, 0, 41, 41, 11, - 41, 0, 0, 37, 0, 37, 37, 37, 0, 0, - 0, 0, 0, 62, 62, 64, 0, 0, 62, 62, - 0, 37, 37, 0, 37, 0, 0, 0, 0, 0, - 38, 41, 38, 38, 38, 100, 0, 100, 100, 100, - 63, 100, 100, 100, 100, 100, 100, 0, 38, 38, - 100, 38, 0, 66, 0, 37, 64, 29, 29, 64, - 29, 0, 29, 41, 0, 0, 57, 58, 59, 60, - 63, 64, 65, 0, 64, 29, 0, 29, 0, 0, - 0, 63, 38, 0, 42, 0, 0, 37, 0, 0, - 0, 0, 0, 0, 66, 29, 29, 66, 29, 63, - 29, 0, 68, 66, 0, 67, 0, 69, 0, 29, - 0, 0, 66, 29, 38, 29, 0, 0, 0, 0, - 62, 0, 61, 0, 0, 42, 3, 97, 42, 0, - 4, 91, 5, 97, 0, 6, 7, 8, 0, 0, - 0, 9, 0, 42, 42, 97, 42, 29, 91, 18, - 0, 18, 18, 18, 70, 18, 18, 18, 18, 18, - 18, 0, 0, 0, 18, 0, 3, 0, 68, 66, - 4, 67, 5, 69, 0, 6, 7, 42, 97, 0, - 0, 9, 0, 0, 0, 0, 62, 0, 61, 0, - 0, 0, 0, 0, 0, 0, 0, 41, 41, 41, - 41, 41, 41, 41, 41, 41, 41, 41, 41, 42, - 97, 0, 41, 41, 41, 41, 41, 41, 41, 41, - 70, 37, 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 0, 0, 0, 37, 37, 37, 37, - 37, 37, 37, 37, 0, 0, 0, 0, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 0, 0, 0, 38, 38, 38, 38, 38, 38, 38, - 38, 0, 0, 0, 64, 0, 64, 64, 64, 0, - 64, 64, 64, 64, 64, 64, 0, 0, 0, 64, - 29, 29, 29, 29, 29, 29, 29, 0, 0, 0, - 0, 63, 63, 0, 0, 0, 63, 63, 0, 0, - 0, 0, 66, 0, 66, 66, 66, 0, 66, 66, - 66, 66, 66, 66, 115, 31, 0, 66, 29, 29, - 29, 29, 29, 29, 29, 57, 58, 59, 60, 63, - 64, 65, 0, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 34, 0, 0, 42, 42, - 42, 42, 42, 42, 42, 42, 31, 0, 0, 31, - 0, 0, 0, 0, 68, 66, 0, 67, 33, 69, - 0, 0, 0, 0, 31, 31, 56, 31, 0, 0, - 0, 0, 62, 0, 61, 0, 34, 0, 0, 34, - 32, 57, 58, 59, 60, 63, 64, 65, 0, 0, - 0, 0, 0, 0, 34, 34, 0, 34, 31, 33, - 0, 0, 33, 35, 0, 128, 70, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 33, 33, 0, - 33, 32, 0, 0, 32, 36, 0, 0, 34, 0, - 31, 0, 0, 0, 0, 0, 0, 0, 0, 32, - 32, 0, 32, 0, 35, 0, 0, 35, 0, 0, - 0, 33, 0, 52, 0, 0, 0, 0, 0, 0, - 34, 0, 35, 35, 0, 35, 36, 0, 0, 36, - 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, - 101, 0, 0, 33, 36, 36, 0, 36, 0, 0, - 0, 0, 0, 0, 52, 0, 35, 52, 28, 0, - 11, 0, 11, 11, 11, 32, 11, 11, 11, 11, - 11, 0, 52, 0, 0, 11, 0, 0, 36, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, - 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, - 36, 0, 0, 0, 0, 0, 0, 28, 0, 0, - 0, 0, 0, 0, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 0, 0, 52, 31, - 31, 31, 31, 31, 31, 31, 0, 57, 58, 59, - 60, 63, 64, 65, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 0, 0, 0, 34, - 34, 34, 34, 34, 34, 34, 0, 33, 33, 33, - 33, 33, 33, 33, 33, 33, 33, 33, 33, 0, - 0, 0, 33, 33, 33, 33, 33, 33, 33, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 0, 0, 0, 32, 32, 32, 32, 32, 32, - 32, 0, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 0, 0, 0, 35, 35, 35, - 35, 35, 35, 35, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 54, 0, 0, 36, - 36, 36, 36, 36, 36, 36, 68, 66, 0, 67, - 0, 69, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 62, 0, 61, 52, 52, 52, - 0, 0, 0, 0, 0, 0, 0, 54, 0, 101, - 54, 101, 101, 101, 0, 101, 101, 101, 101, 101, - 101, 0, 0, 0, 101, 54, 0, 28, 70, 28, - 28, 28, 0, 28, 28, 28, 28, 28, 28, 0, - 0, 0, 28, 96, 0, 96, 96, 96, 96, 96, - 96, 0, 68, 66, 0, 67, 0, 69, 0, 54, - 0, 96, 96, 96, 86, 96, 29, 29, 0, 29, - 62, 29, 61, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 29, 0, 29, 0, 0, 0, - 0, 54, 0, 0, 96, 0, 0, 96, 0, 0, - 0, 0, 0, 150, 70, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, - 0, 0, 0, 0, 0, 0, 96, 0, 96, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 174, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 57, - 58, 59, 60, 63, 64, 65, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 54, 54, 54, 54, 54, - 54, 54, 54, 54, 54, 54, 54, 0, 0, 0, - 54, 54, 54, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 29, 96, 96, - 96, 96, 96, 96, 96, 57, 58, 59, 60, 63, - 64, 65, 0, 0, 0, 0, 53, 54, 0, 29, - 29, 29, 29, 29, 29, 29, 72, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 88, 0, 0, 0, 0, - 0, 0, 0, 94, 95, 96, 97, 98, 99, 100, - 101, 102, 103, 104, 105, 112, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 132, 0, 0, 0, 0, 0, 0, 0, 0, - 141, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 148, 149, 0, 0, 0, 0, - 0, 155, 0, 156, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 170, -}; -short luaY_check[] = { 91, - 0, 40, 111, 40, 2, 40, 45, 2, 41, 2, - 45, 42, 43, 8, 45, 8, 47, 34, 59, 43, - 91, 42, 43, 0, 45, 44, 47, 261, 262, 42, - 46, 59, 59, 44, 47, 274, 271, 44, 44, 274, - 40, 41, 42, 43, 44, 45, 0, 47, 59, 44, - 274, 44, 91, 77, 61, 61, 44, 166, 0, 59, - 60, 40, 62, 94, 41, 42, 43, 44, 45, 140, - 47, 59, 59, 94, 145, 91, 123, 44, 40, 274, - 274, 94, 59, 60, 125, 62, 123, 0, 41, 94, - 123, 162, 266, 93, 94, 123, 123, 125, 125, 41, - 42, 43, 44, 45, 175, 47, 125, 261, 262, 57, - 58, 0, 266, 267, 125, 40, 93, 59, 60, 117, - 62, 46, 117, 123, 117, 125, 143, 274, 41, 42, - 43, 44, 45, 58, 47, 274, 41, 125, 44, 6, - 125, 44, 61, 41, 44, 0, 59, 60, 125, 62, - 59, 93, 41, 42, 43, 44, 45, 24, 47, 42, - 43, 267, 45, 267, 47, 267, 91, 115, 0, 41, - 59, 60, 0, 62, 123, 125, 43, 60, 45, 62, - 93, 129, 274, 125, 41, 44, 125, 46, 125, 267, - 125, 45, 153, 141, 146, 46, 0, 117, 12, 117, - 134, 46, 61, 177, 93, -1, -1, 58, -1, 157, - 77, 94, 125, 58, -1, -1, -1, -1, -1, 258, - -1, -1, -1, 258, -1, -1, 174, -1, 176, -1, - -1, 59, 91, 272, 273, 274, 125, 272, 273, 274, - 91, -1, -1, -1, 283, -1, 91, -1, 283, -1, - 281, 118, -1, 42, 43, 59, 45, -1, 47, 259, - 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, - 270, 60, -1, 62, 274, 275, 276, 277, 278, 279, - 280, 281, 259, 260, 261, 262, 263, 264, 265, 266, - 267, 268, 269, 270, -1, 123, -1, 274, 275, 276, - 277, 278, 279, 280, 281, 94, -1, 261, 262, -1, - 0, -1, 266, 267, -1, -1, -1, 259, 260, 261, - 262, 263, 264, 265, 266, 267, 268, 269, 270, -1, - -1, -1, 274, 275, 276, 277, 278, 279, 280, 281, - -1, -1, -1, -1, -1, -1, 259, 260, 261, 262, - 263, 264, 265, 266, 267, 268, 269, 270, 0, -1, - -1, 274, 275, 276, 277, 278, 279, 280, 281, 59, - 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, - 269, 270, 0, -1, -1, 274, 275, 276, 277, 278, - 279, 280, 281, -1, 277, 278, 279, 280, 281, 41, - 42, 43, 44, 45, 259, 47, -1, -1, 263, 0, - 265, -1, -1, 268, 269, 270, -1, 59, 60, 274, - 62, -1, -1, 41, -1, 43, 44, 45, -1, -1, - -1, -1, -1, 261, 262, 0, -1, -1, 266, 267, - -1, 59, 60, -1, 62, -1, -1, -1, -1, -1, - 41, 93, 43, 44, 45, 259, -1, 261, 262, 263, - 0, 265, 266, 267, 268, 269, 270, -1, 59, 60, - 274, 62, -1, 0, -1, 93, 41, 42, 43, 44, - 45, -1, 47, 125, -1, -1, 275, 276, 277, 278, - 279, 280, 281, -1, 59, 60, -1, 62, -1, -1, - -1, 41, 93, -1, 0, -1, -1, 125, -1, -1, - -1, -1, -1, -1, 41, 42, 43, 44, 45, 59, - 47, -1, 42, 43, -1, 45, -1, 47, -1, 94, - -1, -1, 59, 60, 125, 62, -1, -1, -1, -1, - 60, -1, 62, -1, -1, 41, 259, 40, 44, -1, - 263, 44, 265, 46, -1, 268, 269, 270, -1, -1, - -1, 274, -1, 59, 60, 58, 62, 94, 61, 259, - -1, 261, 262, 263, 94, 265, 266, 267, 268, 269, - 270, -1, -1, -1, 274, -1, 259, -1, 42, 43, - 263, 45, 265, 47, -1, 268, 269, 93, 91, -1, - -1, 274, -1, -1, -1, -1, 60, -1, 62, -1, - -1, -1, -1, -1, -1, -1, -1, 259, 260, 261, - 262, 263, 264, 265, 266, 267, 268, 269, 270, 125, - 123, -1, 274, 275, 276, 277, 278, 279, 280, 281, - 94, 259, 260, 261, 262, 263, 264, 265, 266, 267, - 268, 269, 270, -1, -1, -1, 274, 275, 276, 277, - 278, 279, 280, 281, -1, -1, -1, -1, 259, 260, - 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, - -1, -1, -1, 274, 275, 276, 277, 278, 279, 280, - 281, -1, -1, -1, 259, -1, 261, 262, 263, -1, - 265, 266, 267, 268, 269, 270, -1, -1, -1, 274, - 275, 276, 277, 278, 279, 280, 281, -1, -1, -1, - -1, 261, 262, -1, -1, -1, 266, 267, -1, -1, - -1, -1, 259, -1, 261, 262, 263, -1, 265, 266, - 267, 268, 269, 270, 264, 0, -1, 274, 275, 276, - 277, 278, 279, 280, 281, 275, 276, 277, 278, 279, - 280, 281, -1, 259, 260, 261, 262, 263, 264, 265, - 266, 267, 268, 269, 270, 0, -1, -1, 274, 275, - 276, 277, 278, 279, 280, 281, 41, -1, -1, 44, - -1, -1, -1, -1, 42, 43, -1, 45, 0, 47, - -1, -1, -1, -1, 59, 60, 260, 62, -1, -1, - -1, -1, 60, -1, 62, -1, 41, -1, -1, 44, - 0, 275, 276, 277, 278, 279, 280, 281, -1, -1, - -1, -1, -1, -1, 59, 60, -1, 62, 93, 41, - -1, -1, 44, 0, -1, 93, 94, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 59, 60, -1, - 62, 41, -1, -1, 44, 0, -1, -1, 93, -1, - 125, -1, -1, -1, -1, -1, -1, -1, -1, 59, - 60, -1, 62, -1, 41, -1, -1, 44, -1, -1, - -1, 93, -1, 0, -1, -1, -1, -1, -1, -1, - 125, -1, 59, 60, -1, 62, 41, -1, -1, 44, - -1, -1, -1, 93, -1, -1, -1, -1, -1, -1, - 0, -1, -1, 125, 59, 60, -1, 62, -1, -1, - -1, -1, -1, -1, 41, -1, 93, 44, 0, -1, - 259, -1, 261, 262, 263, 125, 265, 266, 267, 268, - 269, -1, 59, -1, -1, 274, -1, -1, 93, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 125, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 59, - -1, -1, -1, -1, -1, -1, 93, -1, -1, -1, - 125, -1, -1, -1, -1, -1, -1, 59, -1, -1, - -1, -1, -1, -1, 259, 260, 261, 262, 263, 264, - 265, 266, 267, 268, 269, 270, -1, -1, 125, 274, - 275, 276, 277, 278, 279, 280, -1, 275, 276, 277, - 278, 279, 280, 281, 259, 260, 261, 262, 263, 264, - 265, 266, 267, 268, 269, 270, -1, -1, -1, 274, - 275, 276, 277, 278, 279, 280, -1, 259, 260, 261, - 262, 263, 264, 265, 266, 267, 268, 269, 270, -1, - -1, -1, 274, 275, 276, 277, 278, 279, 280, 259, - 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, - 270, -1, -1, -1, 274, 275, 276, 277, 278, 279, - 280, -1, 259, 260, 261, 262, 263, 264, 265, 266, - 267, 268, 269, 270, -1, -1, -1, 274, 275, 276, - 277, 278, 279, 280, 259, 260, 261, 262, 263, 264, - 265, 266, 267, 268, 269, 270, 0, -1, -1, 274, - 275, 276, 277, 278, 279, 280, 42, 43, -1, 45, - -1, 47, 259, 260, 261, 262, 263, 264, 265, 266, - 267, 268, 269, 270, 60, -1, 62, 274, 275, 276, - -1, -1, -1, -1, -1, -1, -1, 41, -1, 259, - 44, 261, 262, 263, -1, 265, 266, 267, 268, 269, - 270, -1, -1, -1, 274, 59, -1, 259, 94, 261, - 262, 263, -1, 265, 266, 267, 268, 269, 270, -1, - -1, -1, 274, 40, -1, 42, 43, 44, 45, 46, - 47, -1, 42, 43, -1, 45, -1, 47, -1, 93, - -1, 58, 59, 60, 61, 62, 42, 43, -1, 45, - 60, 47, 62, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 60, -1, 62, -1, -1, -1, - -1, 125, -1, -1, 91, -1, -1, 94, -1, -1, - -1, -1, -1, 93, 94, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 94, -1, - -1, -1, -1, -1, -1, -1, 123, -1, 125, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 260, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 275, - 276, 277, 278, 279, 280, 281, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 259, 260, 261, 262, 263, - 264, 265, 266, 267, 268, 269, 270, -1, -1, -1, - 274, 275, 276, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 3, 275, 276, - 277, 278, 279, 280, 281, 275, 276, 277, 278, 279, - 280, 281, -1, -1, -1, -1, 22, 23, -1, 275, - 276, 277, 278, 279, 280, 281, 32, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 51, -1, -1, -1, -1, - -1, -1, -1, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 107, -1, -1, -1, -1, -1, -1, -1, -1, - 116, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 130, 131, -1, -1, -1, -1, - -1, 137, -1, 139, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 163, -}; -#define YYFINAL 1 -#ifndef YYDEBUG -#define YYDEBUG 0 -#endif -#define YYMAXTOKEN 283 -#if YYDEBUG -char *luaY_name[] = { -"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,"'('","')'","'*'","'+'","','","'-'","'.'","'/'",0,0,0,0,0,0,0,0,0,0, -"':'","';'","'<'","'='","'>'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,"'['",0,"']'","'^'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,"'{'",0,"'}'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"WRONGTOKEN","NIL","IF","THEN","ELSE", -"ELSEIF","WHILE","DO","REPEAT","UNTIL","END","RETURN","LOCAL","FUNCTION","DOTS", -"NUMBER","STRING","NAME","AND","OR","EQ","NE","LE","GE","CONC","UNARY","NOT", -}; -char *luaY_rule[] = { -"$accept : chunk", -"chunk : chunklist ret", -"chunklist :", -"chunklist : chunklist stat sc", -"chunklist : chunklist function", -"function : FUNCTION funcname body", -"funcname : var", -"funcname : varexp ':' NAME", -"body : '(' parlist ')' block END", -"statlist :", -"statlist : statlist stat sc", -"sc :", -"sc : ';'", -"stat : IF expr1 THEN PrepJump block PrepJump elsepart END", -"$$1 :", -"stat : WHILE $$1 expr1 DO PrepJump block PrepJump END", -"$$2 :", -"stat : REPEAT $$2 block UNTIL expr1 PrepJump", -"stat : varlist1 '=' exprlist1", -"stat : functioncall", -"stat : LOCAL localdeclist decinit", -"elsepart :", -"elsepart : ELSE block", -"elsepart : ELSEIF expr1 THEN PrepJump block PrepJump elsepart", -"$$3 :", -"block : $$3 statlist ret", -"ret :", -"ret : RETURN exprlist sc", -"PrepJump :", -"expr1 : expr", -"expr : '(' expr ')'", -"expr : expr1 EQ expr1", -"expr : expr1 '<' expr1", -"expr : expr1 '>' expr1", -"expr : expr1 NE expr1", -"expr : expr1 LE expr1", -"expr : expr1 GE expr1", -"expr : expr1 '+' expr1", -"expr : expr1 '-' expr1", -"expr : expr1 '*' expr1", -"expr : expr1 '/' expr1", -"expr : expr1 '^' expr1", -"expr : expr1 CONC expr1", -"expr : '-' expr1", -"expr : table", -"expr : varexp", -"expr : NUMBER", -"expr : STRING", -"expr : NIL", -"expr : functioncall", -"expr : NOT expr1", -"$$4 :", -"expr : expr1 AND PrepJump $$4 expr1", -"$$5 :", -"expr : expr1 OR PrepJump $$5 expr1", -"$$6 :", -"table : $$6 '{' fieldlist '}'", -"functioncall : funcvalue funcParams", -"funcvalue : varexp", -"funcvalue : varexp ':' NAME", -"funcParams : '(' exprlist ')'", -"funcParams : table", -"exprlist :", -"exprlist : exprlist1", -"exprlist1 : expr", -"$$7 :", -"exprlist1 : exprlist1 ',' $$7 expr", -"parlist :", -"parlist : parlist1", -"parlist1 : par", -"parlist1 : parlist1 ',' par", -"par : NAME", -"par : DOTS", -"$$8 :", -"fieldlist : lfieldlist $$8 semicolonpart", -"fieldlist : ffieldlist1 lastcomma", -"semicolonpart :", -"semicolonpart : ';' ffieldlist", -"lastcomma :", -"lastcomma : ','", -"ffieldlist :", -"ffieldlist : ffieldlist1 lastcomma", -"ffieldlist1 : ffield", -"ffieldlist1 : ffieldlist1 ',' ffield", -"ffield : ffieldkey '=' expr1", -"ffieldkey : '[' expr1 ']'", -"ffieldkey : NAME", -"lfieldlist :", -"lfieldlist : lfieldlist1 lastcomma", -"lfieldlist1 : expr1", -"lfieldlist1 : lfieldlist1 ',' expr1", -"varlist1 : var", -"varlist1 : varlist1 ',' var", -"var : singlevar", -"var : varexp '[' expr1 ']'", -"var : varexp '.' NAME", -"singlevar : NAME", -"varexp : var", -"localdeclist : NAME", -"localdeclist : localdeclist ',' NAME", -"decinit :", -"decinit : '=' exprlist1", -}; -#endif -#ifdef YYSTACKSIZE -#undef YYMAXDEPTH -#define YYMAXDEPTH YYSTACKSIZE -#else -#ifdef YYMAXDEPTH -#define YYSTACKSIZE YYMAXDEPTH -#else -#define YYSTACKSIZE 500 -#define YYMAXDEPTH 500 -#endif -#endif -int luaY_debug; -int luaY_nerrs; -int luaY_errflag; -int luaY_char; -short *luaY_ssp; -YYSTYPE *luaY_vsp; -YYSTYPE luaY_val; -YYSTYPE luaY_lval; -short luaY_ss[YYSTACKSIZE]; -YYSTYPE luaY_vs[YYSTACKSIZE]; -#define luaY_stacksize YYSTACKSIZE -#define YYABORT goto luaY_abort -#define YYREJECT goto luaY_abort -#define YYACCEPT goto luaY_accept -#define YYERROR goto luaY_errlab -int -luaY_parse() -{ - register int luaY_m, luaY_n, luaY_state; -#if YYDEBUG - register char *luaY_s; - extern char *getenv(); - - if (luaY_s = getenv("YYDEBUG")) - { - luaY_n = *luaY_s; - if (luaY_n >= '0' && luaY_n <= '9') - luaY_debug = luaY_n - '0'; - } -#endif - - luaY_nerrs = 0; - luaY_errflag = 0; - luaY_char = (-1); - - luaY_ssp = luaY_ss; - luaY_vsp = luaY_vs; - *luaY_ssp = luaY_state = 0; - -luaY_loop: - if (luaY_n = luaY_defred[luaY_state]) goto luaY_reduce; - if (luaY_char < 0) - { - if ((luaY_char = luaY_lex()) < 0) luaY_char = 0; -#if YYDEBUG - if (luaY_debug) - { - luaY_s = 0; - if (luaY_char <= YYMAXTOKEN) luaY_s = luaY_name[luaY_char]; - if (!luaY_s) luaY_s = "illegal-symbol"; - printf("%sdebug: state %d, reading %d (%s)\n", - YYPREFIX, luaY_state, luaY_char, luaY_s); - } -#endif - } - if ((luaY_n = luaY_sindex[luaY_state]) && (luaY_n += luaY_char) >= 0 && - luaY_n <= YYTABLESIZE && luaY_check[luaY_n] == luaY_char) - { -#if YYDEBUG - if (luaY_debug) - printf("%sdebug: state %d, shifting to state %d\n", - YYPREFIX, luaY_state, luaY_table[luaY_n]); -#endif - if (luaY_ssp >= luaY_ss + luaY_stacksize - 1) - { - goto luaY_overflow; - } - *++luaY_ssp = luaY_state = luaY_table[luaY_n]; - *++luaY_vsp = luaY_lval; - luaY_char = (-1); - if (luaY_errflag > 0) --luaY_errflag; - goto luaY_loop; - } - if ((luaY_n = luaY_rindex[luaY_state]) && (luaY_n += luaY_char) >= 0 && - luaY_n <= YYTABLESIZE && luaY_check[luaY_n] == luaY_char) - { - luaY_n = luaY_table[luaY_n]; - goto luaY_reduce; - } - if (luaY_errflag) goto luaY_inrecovery; -#ifdef lint - goto luaY_newerror; -#endif -luaY_newerror: - luaY_error("syntax error"); -#ifdef lint - goto luaY_errlab; -#endif -luaY_errlab: - ++luaY_nerrs; -luaY_inrecovery: - if (luaY_errflag < 3) - { - luaY_errflag = 3; - for (;;) - { - if ((luaY_n = luaY_sindex[*luaY_ssp]) && (luaY_n += YYERRCODE) >= 0 && - luaY_n <= YYTABLESIZE && luaY_check[luaY_n] == YYERRCODE) - { -#if YYDEBUG - if (luaY_debug) - printf("%sdebug: state %d, error recovery shifting\ - to state %d\n", YYPREFIX, *luaY_ssp, luaY_table[luaY_n]); -#endif - if (luaY_ssp >= luaY_ss + luaY_stacksize - 1) - { - goto luaY_overflow; - } - *++luaY_ssp = luaY_state = luaY_table[luaY_n]; - *++luaY_vsp = luaY_lval; - goto luaY_loop; - } - else - { -#if YYDEBUG - if (luaY_debug) - printf("%sdebug: error recovery discarding state %d\n", - YYPREFIX, *luaY_ssp); -#endif - if (luaY_ssp <= luaY_ss) goto luaY_abort; - --luaY_ssp; - --luaY_vsp; - } - } - } - else - { - if (luaY_char == 0) goto luaY_abort; -#if YYDEBUG - if (luaY_debug) - { - luaY_s = 0; - if (luaY_char <= YYMAXTOKEN) luaY_s = luaY_name[luaY_char]; - if (!luaY_s) luaY_s = "illegal-symbol"; - printf("%sdebug: state %d, error recovery discards token %d (%s)\n", - YYPREFIX, luaY_state, luaY_char, luaY_s); - } -#endif - luaY_char = (-1); - goto luaY_loop; - } -luaY_reduce: -#if YYDEBUG - if (luaY_debug) - printf("%sdebug: state %d, reducing by rule %d (%s)\n", - YYPREFIX, luaY_state, luaY_n, luaY_rule[luaY_n]); -#endif - luaY_m = luaY_len[luaY_n]; - luaY_val = luaY_vsp[1-luaY_m]; - switch (luaY_n) - { -case 5: -#line 468 "lua.stx" -{ - code_byte(PUSHFUNCTION); - code_code(luaY_vsp[0].pFunc); - storesinglevar(luaY_vsp[-1].vLong); - } -break; -case 6: -#line 475 "lua.stx" -{ luaY_val.vLong =luaY_vsp[0].vLong; init_func(); } -break; -case 7: -#line 477 "lua.stx" -{ - code_constant(luaY_vsp[0].pTStr); - luaY_val.vLong = 0; /* indexed variable */ - init_func(); - add_localvar(luaI_createfixedstring("self")); - } -break; -case 8: -#line 486 "lua.stx" -{ - codereturn(); - luaY_val.pFunc = new(TFunc); - luaI_initTFunc(luaY_val.pFunc); - luaY_val.pFunc->size = pc; - luaY_val.pFunc->code = newvector(pc, Byte); - luaY_val.pFunc->lineDefined = luaY_vsp[-3].vInt; - memcpy(luaY_val.pFunc->code, basepc, pc*sizeof(Byte)); - if (lua_debug) - luaI_closelocalvars(luaY_val.pFunc); - /* save func values */ - funcCode = basepc; maxcode=maxcurr; -#if LISTING - PrintCode(funcCode,funcCode+pc); -#endif - change2main(); /* change back to main code */ - } -break; -case 13: -#line 512 "lua.stx" -{ codeIf(luaY_vsp[-4].vLong, luaY_vsp[-2].vLong); } -break; -case 14: -#line 514 "lua.stx" -{luaY_val.vLong=pc;} -break; -case 15: -#line 515 "lua.stx" -{ - basepc[luaY_vsp[-3].vLong] = IFFJMP; - code_word_at(basepc+luaY_vsp[-3].vLong+1, pc - (luaY_vsp[-3].vLong + sizeof(Word)+1)); - basepc[luaY_vsp[-1].vLong] = UPJMP; - code_word_at(basepc+luaY_vsp[-1].vLong+1, pc - (luaY_vsp[-6].vLong)); - } -break; -case 16: -#line 522 "lua.stx" -{luaY_val.vLong=pc;} -break; -case 17: -#line 523 "lua.stx" -{ - basepc[luaY_vsp[0].vLong] = IFFUPJMP; - code_word_at(basepc+luaY_vsp[0].vLong+1, pc - (luaY_vsp[-4].vLong)); - } -break; -case 18: -#line 529 "lua.stx" -{ - { - int i; - adjust_mult_assign(nvarbuffer, luaY_vsp[0].vLong, luaY_vsp[-2].vInt * 2 + nvarbuffer); - for (i=nvarbuffer-1; i>=0; i--) - lua_codestore (i); - if (luaY_vsp[-2].vInt > 1 || (luaY_vsp[-2].vInt == 1 && varbuffer[0] != 0)) - lua_codeadjust (0); - } - } -break; -case 19: -#line 539 "lua.stx" -{;} -break; -case 20: -#line 541 "lua.stx" -{ nlocalvar += luaY_vsp[-1].vInt; - adjust_mult_assign(luaY_vsp[-1].vInt, luaY_vsp[0].vInt, 0); - } -break; -case 23: -#line 549 "lua.stx" -{ codeIf(luaY_vsp[-3].vLong, luaY_vsp[-1].vLong); } -break; -case 24: -#line 552 "lua.stx" -{luaY_val.vInt = nlocalvar;} -break; -case 25: -#line 553 "lua.stx" -{ - if (nlocalvar != luaY_vsp[-2].vInt) - { - if (lua_debug) - for (; nlocalvar > luaY_vsp[-2].vInt; nlocalvar--) - luaI_unregisterlocalvar(lua_linenumber); - else - nlocalvar = luaY_vsp[-2].vInt; - lua_codeadjust (0); - } - } -break; -case 27: -#line 568 "lua.stx" -{ - adjust_functioncall(luaY_vsp[-1].vLong, MULT_RET); - codereturn(); - } -break; -case 28: -#line 575 "lua.stx" -{ - luaY_val.vLong = pc; - code_byte(0); /* open space */ - code_word (0); - } -break; -case 29: -#line 582 "lua.stx" -{ adjust_functioncall(luaY_vsp[0].vLong, 1); } -break; -case 30: -#line 585 "lua.stx" -{ luaY_val.vLong = luaY_vsp[-1].vLong; } -break; -case 31: -#line 586 "lua.stx" -{ code_byte(EQOP); luaY_val.vLong = 0; } -break; -case 32: -#line 587 "lua.stx" -{ code_byte(LTOP); luaY_val.vLong = 0; } -break; -case 33: -#line 588 "lua.stx" -{ code_byte(GTOP); luaY_val.vLong = 0; } -break; -case 34: -#line 589 "lua.stx" -{ code_byte(EQOP); code_byte(NOTOP); luaY_val.vLong = 0; } -break; -case 35: -#line 590 "lua.stx" -{ code_byte(LEOP); luaY_val.vLong = 0; } -break; -case 36: -#line 591 "lua.stx" -{ code_byte(GEOP); luaY_val.vLong = 0; } -break; -case 37: -#line 592 "lua.stx" -{ code_byte(ADDOP); luaY_val.vLong = 0; } -break; -case 38: -#line 593 "lua.stx" -{ code_byte(SUBOP); luaY_val.vLong = 0; } -break; -case 39: -#line 594 "lua.stx" -{ code_byte(MULTOP); luaY_val.vLong = 0; } -break; -case 40: -#line 595 "lua.stx" -{ code_byte(DIVOP); luaY_val.vLong = 0; } -break; -case 41: -#line 596 "lua.stx" -{ code_byte(POWOP); luaY_val.vLong = 0; } -break; -case 42: -#line 597 "lua.stx" -{ code_byte(CONCOP); luaY_val.vLong = 0; } -break; -case 43: -#line 598 "lua.stx" -{ code_byte(MINUSOP); luaY_val.vLong = 0;} -break; -case 44: -#line 599 "lua.stx" -{ luaY_val.vLong = 0; } -break; -case 45: -#line 600 "lua.stx" -{ luaY_val.vLong = 0;} -break; -case 46: -#line 601 "lua.stx" -{ code_number(luaY_vsp[0].vFloat); luaY_val.vLong = 0; } -break; -case 47: -#line 603 "lua.stx" -{ - code_string(luaY_vsp[0].vWord); - luaY_val.vLong = 0; - } -break; -case 48: -#line 607 "lua.stx" -{code_byte(PUSHNIL); luaY_val.vLong = 0; } -break; -case 49: -#line 608 "lua.stx" -{ luaY_val.vLong = luaY_vsp[0].vLong; } -break; -case 50: -#line 609 "lua.stx" -{ code_byte(NOTOP); luaY_val.vLong = 0;} -break; -case 51: -#line 610 "lua.stx" -{code_byte(POP); } -break; -case 52: -#line 611 "lua.stx" -{ - basepc[luaY_vsp[-2].vLong] = ONFJMP; - code_word_at(basepc+luaY_vsp[-2].vLong+1, pc - (luaY_vsp[-2].vLong + sizeof(Word)+1)); - luaY_val.vLong = 0; - } -break; -case 53: -#line 616 "lua.stx" -{code_byte(POP); } -break; -case 54: -#line 617 "lua.stx" -{ - basepc[luaY_vsp[-2].vLong] = ONTJMP; - code_word_at(basepc+luaY_vsp[-2].vLong+1, pc - (luaY_vsp[-2].vLong + sizeof(Word)+1)); - luaY_val.vLong = 0; - } -break; -case 55: -#line 625 "lua.stx" -{ - code_byte(CREATEARRAY); - luaY_val.vLong = pc; code_word(0); - } -break; -case 56: -#line 630 "lua.stx" -{ - code_word_at(basepc+luaY_vsp[-3].vLong, luaY_vsp[-1].vInt); - } -break; -case 57: -#line 636 "lua.stx" -{ - code_byte(CALLFUNC); - code_byte(luaY_vsp[-1].vInt+luaY_vsp[0].vInt); - luaY_val.vLong = pc; - code_byte(0); /* may be modified by other rules */ - } -break; -case 58: -#line 644 "lua.stx" -{ luaY_val.vInt = 0; } -break; -case 59: -#line 646 "lua.stx" -{ - code_byte(PUSHSELF); - code_word(luaI_findconstant(luaY_vsp[0].pTStr)); - luaY_val.vInt = 1; - } -break; -case 60: -#line 654 "lua.stx" -{ luaY_val.vInt = adjust_functioncall(luaY_vsp[-1].vLong, 1); } -break; -case 61: -#line 655 "lua.stx" -{ luaY_val.vInt = 1; } -break; -case 62: -#line 658 "lua.stx" -{ luaY_val.vLong = 0; } -break; -case 63: -#line 659 "lua.stx" -{ luaY_val.vLong = luaY_vsp[0].vLong; } -break; -case 64: -#line 662 "lua.stx" -{ if (luaY_vsp[0].vLong != 0) luaY_val.vLong = luaY_vsp[0].vLong; else luaY_val.vLong = -1; } -break; -case 65: -#line 663 "lua.stx" -{ luaY_val.vLong = adjust_functioncall(luaY_vsp[-1].vLong, 1); } -break; -case 66: -#line 664 "lua.stx" -{ - if (luaY_vsp[0].vLong == 0) luaY_val.vLong = -(luaY_vsp[-1].vLong + 1); /* -length */ - else - { - adjust_functioncall(luaY_vsp[0].vLong, luaY_vsp[-1].vLong); - luaY_val.vLong = luaY_vsp[0].vLong; - } - } -break; -case 67: -#line 674 "lua.stx" -{ luaY_val.vInt = close_parlist(0); } -break; -case 68: -#line 675 "lua.stx" -{ luaY_val.vInt = close_parlist(luaY_vsp[0].vInt); } -break; -case 69: -#line 678 "lua.stx" -{ luaY_val.vInt = luaY_vsp[0].vInt; } -break; -case 70: -#line 680 "lua.stx" -{ - if (luaY_vsp[-2].vInt) - lua_error("invalid parameter list"); - luaY_val.vInt = luaY_vsp[0].vInt; - } -break; -case 71: -#line 687 "lua.stx" -{ add_localvar(luaY_vsp[0].pTStr); luaY_val.vInt = 0; } -break; -case 72: -#line 688 "lua.stx" -{ luaY_val.vInt = 1; } -break; -case 73: -#line 692 "lua.stx" -{ flush_list(luaY_vsp[0].vInt/FIELDS_PER_FLUSH, luaY_vsp[0].vInt%FIELDS_PER_FLUSH); } -break; -case 74: -#line 694 "lua.stx" -{ luaY_val.vInt = luaY_vsp[-2].vInt+luaY_vsp[0].vInt; } -break; -case 75: -#line 696 "lua.stx" -{ luaY_val.vInt = luaY_vsp[-1].vInt; flush_record(luaY_vsp[-1].vInt%FIELDS_PER_FLUSH); } -break; -case 76: -#line 700 "lua.stx" -{ luaY_val.vInt = 0; } -break; -case 77: -#line 702 "lua.stx" -{ luaY_val.vInt = luaY_vsp[0].vInt; flush_record(luaY_vsp[0].vInt%FIELDS_PER_FLUSH); } -break; -case 80: -#line 709 "lua.stx" -{ luaY_val.vInt = 0; } -break; -case 81: -#line 710 "lua.stx" -{ luaY_val.vInt = luaY_vsp[-1].vInt; } -break; -case 82: -#line 713 "lua.stx" -{luaY_val.vInt=1;} -break; -case 83: -#line 715 "lua.stx" -{ - luaY_val.vInt=luaY_vsp[-2].vInt+1; - if (luaY_val.vInt%FIELDS_PER_FLUSH == 0) flush_record(FIELDS_PER_FLUSH); - } -break; -case 86: -#line 725 "lua.stx" -{ code_constant(luaY_vsp[0].pTStr); } -break; -case 87: -#line 728 "lua.stx" -{ luaY_val.vInt = 0; } -break; -case 88: -#line 729 "lua.stx" -{ luaY_val.vInt = luaY_vsp[-1].vInt; } -break; -case 89: -#line 732 "lua.stx" -{luaY_val.vInt=1;} -break; -case 90: -#line 734 "lua.stx" -{ - luaY_val.vInt=luaY_vsp[-2].vInt+1; - if (luaY_val.vInt%FIELDS_PER_FLUSH == 0) - flush_list(luaY_val.vInt/FIELDS_PER_FLUSH - 1, FIELDS_PER_FLUSH); - } -break; -case 91: -#line 742 "lua.stx" -{ - nvarbuffer = 0; - add_varbuffer(luaY_vsp[0].vLong); - luaY_val.vInt = (luaY_vsp[0].vLong == 0) ? 1 : 0; - } -break; -case 92: -#line 748 "lua.stx" -{ - add_varbuffer(luaY_vsp[0].vLong); - luaY_val.vInt = (luaY_vsp[0].vLong == 0) ? luaY_vsp[-2].vInt + 1 : luaY_vsp[-2].vInt; - } -break; -case 93: -#line 754 "lua.stx" -{ luaY_val.vLong = luaY_vsp[0].vLong; } -break; -case 94: -#line 756 "lua.stx" -{ - luaY_val.vLong = 0; /* indexed variable */ - } -break; -case 95: -#line 760 "lua.stx" -{ - code_constant(luaY_vsp[0].pTStr); - luaY_val.vLong = 0; /* indexed variable */ - } -break; -case 96: -#line 767 "lua.stx" -{ - int local = lua_localname(luaY_vsp[0].pTStr); - if (local == -1) /* global var */ - luaY_val.vLong = luaI_findsymbol(luaY_vsp[0].pTStr)+1; /* return positive value */ - else - luaY_val.vLong = -(local+1); /* return negative value */ - } -break; -case 97: -#line 776 "lua.stx" -{ lua_pushvar(luaY_vsp[0].vLong); } -break; -case 98: -#line 779 "lua.stx" -{store_localvar(luaY_vsp[0].pTStr, 0); luaY_val.vInt = 1;} -break; -case 99: -#line 781 "lua.stx" -{ - store_localvar(luaY_vsp[0].pTStr, luaY_vsp[-2].vInt); - luaY_val.vInt = luaY_vsp[-2].vInt+1; - } -break; -case 100: -#line 787 "lua.stx" -{ luaY_val.vInt = 0; } -break; -case 101: -#line 788 "lua.stx" -{ luaY_val.vInt = luaY_vsp[0].vLong; } -break; -#line 1641 "y.tab.c" - } - luaY_ssp -= luaY_m; - luaY_state = *luaY_ssp; - luaY_vsp -= luaY_m; - luaY_m = luaY_lhs[luaY_n]; - if (luaY_state == 0 && luaY_m == 0) - { -#if YYDEBUG - if (luaY_debug) - printf("%sdebug: after reduction, shifting from state 0 to\ - state %d\n", YYPREFIX, YYFINAL); -#endif - luaY_state = YYFINAL; - *++luaY_ssp = YYFINAL; - *++luaY_vsp = luaY_val; - if (luaY_char < 0) - { - if ((luaY_char = luaY_lex()) < 0) luaY_char = 0; -#if YYDEBUG - if (luaY_debug) - { - luaY_s = 0; - if (luaY_char <= YYMAXTOKEN) luaY_s = luaY_name[luaY_char]; - if (!luaY_s) luaY_s = "illegal-symbol"; - printf("%sdebug: state %d, reading %d (%s)\n", - YYPREFIX, YYFINAL, luaY_char, luaY_s); - } -#endif - } - if (luaY_char == 0) goto luaY_accept; - goto luaY_loop; - } - if ((luaY_n = luaY_gindex[luaY_m]) && (luaY_n += luaY_state) >= 0 && - luaY_n <= YYTABLESIZE && luaY_check[luaY_n] == luaY_state) - luaY_state = luaY_table[luaY_n]; - else - luaY_state = luaY_dgoto[luaY_m]; -#if YYDEBUG - if (luaY_debug) - printf("%sdebug: after reduction, shifting from state %d \ -to state %d\n", YYPREFIX, *luaY_ssp, luaY_state); -#endif - if (luaY_ssp >= luaY_ss + luaY_stacksize - 1) - { - goto luaY_overflow; - } - *++luaY_ssp = luaY_state; - *++luaY_vsp = luaY_val; - goto luaY_loop; -luaY_overflow: - luaY_error("yacc stack overflow"); -luaY_abort: - return (1); -luaY_accept: - return (0); -} diff --git a/src/parser.h b/src/parser.h deleted file mode 100644 index 7087ef9..0000000 --- a/src/parser.h +++ /dev/null @@ -1,38 +0,0 @@ -#define WRONGTOKEN 257 -#define NIL 258 -#define IF 259 -#define THEN 260 -#define ELSE 261 -#define ELSEIF 262 -#define WHILE 263 -#define DO 264 -#define REPEAT 265 -#define UNTIL 266 -#define END 267 -#define RETURN 268 -#define LOCAL 269 -#define FUNCTION 270 -#define DOTS 271 -#define NUMBER 272 -#define STRING 273 -#define NAME 274 -#define AND 275 -#define OR 276 -#define EQ 277 -#define NE 278 -#define LE 279 -#define GE 280 -#define CONC 281 -#define UNARY 282 -#define NOT 283 -typedef union -{ - int vInt; - float vFloat; - char *pChar; - Word vWord; - Long vLong; - TFunc *pFunc; - TaggedString *pTStr; -} YYSTYPE; -extern YYSTYPE luaY_lval; diff --git a/src/table.c b/src/table.c deleted file mode 100644 index 6f24ca9..0000000 --- a/src/table.c +++ /dev/null @@ -1,266 +0,0 @@ -/* -** table.c -** Module to control static tables -*/ - -char *rcs_table="$Id: table.c,v 2.72 1997/06/17 18:09:31 roberto Exp $"; - -#include "luamem.h" -#include "auxlib.h" -#include "func.h" -#include "opcode.h" -#include "tree.h" -#include "hash.h" -#include "table.h" -#include "inout.h" -#include "lua.h" -#include "fallback.h" -#include "luadebug.h" - - -#define BUFFER_BLOCK 256 - -Symbol *lua_table = NULL; -Word lua_ntable = 0; -static Long lua_maxsymbol = 0; - -TaggedString **lua_constant = NULL; -Word lua_nconstant = 0; -static Long lua_maxconstant = 0; - - -#define GARBAGE_BLOCK 100 - - -void luaI_initsymbol (void) -{ - lua_maxsymbol = BUFFER_BLOCK; - lua_table = newvector(lua_maxsymbol, Symbol); - luaI_predefine(); -} - - -/* -** Initialise constant table with pre-defined constants -*/ -void luaI_initconstant (void) -{ - lua_maxconstant = BUFFER_BLOCK; - lua_constant = newvector(lua_maxconstant, TaggedString *); - /* pre-register mem error messages, to avoid loop when error arises */ - luaI_findconstantbyname(tableEM); - luaI_findconstantbyname(memEM); -} - - -/* -** Given a name, search it at symbol table and return its index. If not -** found, allocate it. -*/ -Word luaI_findsymbol (TaggedString *t) -{ - if (t->u.s.varindex == NOT_USED) - { - if (lua_ntable == lua_maxsymbol) - lua_maxsymbol = growvector(&lua_table, lua_maxsymbol, Symbol, - symbolEM, MAX_WORD); - t->u.s.varindex = lua_ntable; - lua_table[lua_ntable].varname = t; - s_ttype(lua_ntable) = LUA_T_NIL; - lua_ntable++; - } - return t->u.s.varindex; -} - - -Word luaI_findsymbolbyname (char *name) -{ - return luaI_findsymbol(luaI_createfixedstring(name)); -} - - -/* -** Given a tree node, check it is has a correspondent constant index. If not, -** allocate it. -*/ -Word luaI_findconstant (TaggedString *t) -{ - if (t->u.s.constindex == NOT_USED) - { - if (lua_nconstant == lua_maxconstant) - lua_maxconstant = growvector(&lua_constant, lua_maxconstant, TaggedString *, - constantEM, MAX_WORD); - t->u.s.constindex = lua_nconstant; - lua_constant[lua_nconstant] = t; - lua_nconstant++; - } - return t->u.s.constindex; -} - - -Word luaI_findconstantbyname (char *name) -{ - return luaI_findconstant(luaI_createfixedstring(name)); -} - -TaggedString *luaI_createfixedstring (char *name) -{ - TaggedString *ts = lua_createstring(name); - if (!ts->marked) - ts->marked = 2; /* avoid GC */ - return ts; -} - - -int luaI_globaldefined (char *name) -{ - return ttype(&lua_table[luaI_findsymbolbyname(name)].object) != LUA_T_NIL; -} - - -/* -** Traverse symbol table objects -*/ -static char *lua_travsymbol (int (*fn)(TObject *)) -{ - Word i; - for (i=0; istr; - return NULL; -} - - -/* -** Mark an object if it is a string or a unmarked array. -*/ -int lua_markobject (TObject *o) -{/* if already marked, does not change mark value */ - if (ttype(o) == LUA_T_USERDATA || - (ttype(o) == LUA_T_STRING && !tsvalue(o)->marked)) - tsvalue(o)->marked = 1; - else if (ttype(o) == LUA_T_ARRAY) - lua_hashmark (avalue(o)); - else if ((o->ttype == LUA_T_FUNCTION || o->ttype == LUA_T_MARK) - && !o->value.tf->marked) - o->value.tf->marked = 1; - return 0; -} - -/* -* returns 0 if the object is going to be (garbage) collected -*/ -int luaI_ismarked (TObject *o) -{ - switch (o->ttype) - { - case LUA_T_STRING: case LUA_T_USERDATA: - return o->value.ts->marked; - case LUA_T_FUNCTION: - return o->value.tf->marked; - case LUA_T_ARRAY: - return o->value.a->mark; - default: /* nil, number, cfunction, or user data */ - return 1; - } -} - - -static void call_nilIM (void) -{ /* signals end of garbage collection */ - TObject t; - ttype(&t) = LUA_T_NIL; - luaI_gcIM(&t); /* end of list */ -} - -/* -** Garbage collection. -** Delete all unused strings and arrays. -*/ -static long gc_block = GARBAGE_BLOCK; -static long gc_nentity = 0; /* total of strings, arrays, etc */ - -static void markall (void) -{ - lua_travstack(lua_markobject); /* mark stack objects */ - lua_travsymbol(lua_markobject); /* mark symbol table objects */ - luaI_travlock(lua_markobject); /* mark locked objects */ - luaI_travfallbacks(lua_markobject); /* mark fallbacks */ -} - - -long lua_collectgarbage (long limit) -{ - long recovered = 0; - Hash *freetable; - TaggedString *freestr; - TFunc *freefunc; - markall(); - luaI_invalidaterefs(); - freetable = luaI_hashcollector(&recovered); - freestr = luaI_strcollector(&recovered); - freefunc = luaI_funccollector(&recovered); - gc_nentity -= recovered; - gc_block = (limit == 0) ? 2*(gc_block-recovered) : gc_nentity+limit; - luaI_hashcallIM(freetable); - luaI_strcallIM(freestr); - call_nilIM(); - luaI_hashfree(freetable); - luaI_strfree(freestr); - luaI_funcfree(freefunc); - return recovered; -} - - -void lua_pack (void) -{ - if (++gc_nentity >= gc_block) - lua_collectgarbage(0); -} - - -/* -** Internal function: return next global variable -*/ -void luaI_nextvar (void) -{ - Word next; - if (lua_isnil(lua_getparam(1))) - next = 0; - else - next = luaI_findsymbolbyname(luaL_check_string(1)) + 1; - while (next < lua_ntable && s_ttype(next) == LUA_T_NIL) - next++; - if (next < lua_ntable) { - lua_pushstring(lua_table[next].varname->str); - luaI_pushobject(&s_object(next)); - } -} - - -static TObject *functofind; -static int checkfunc (TObject *o) -{ - if (o->ttype == LUA_T_FUNCTION) - return - ((functofind->ttype == LUA_T_FUNCTION || functofind->ttype == LUA_T_MARK) - && (functofind->value.tf == o->value.tf)); - if (o->ttype == LUA_T_CFUNCTION) - return - ((functofind->ttype == LUA_T_CFUNCTION || - functofind->ttype == LUA_T_CMARK) && - (functofind->value.f == o->value.f)); - return 0; -} - - -char *lua_getobjname (lua_Object o, char **name) -{ /* try to find a name for given function */ - functofind = luaI_Address(o); - if ((*name = luaI_travfallbacks(checkfunc)) != NULL) - return "tag-method"; - else if ((*name = lua_travsymbol(checkfunc)) != NULL) - return "global"; - else return ""; -} - diff --git a/src/table.h b/src/table.h deleted file mode 100644 index 5a62852..0000000 --- a/src/table.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -** Module to control static tables -** TeCGraf - PUC-Rio -** $Id: table.h,v 2.25 1997/05/26 14:42:36 roberto Exp $ -*/ - -#ifndef table_h -#define table_h - -#include "tree.h" -#include "opcode.h" - -typedef struct -{ - TObject object; - TaggedString *varname; -} Symbol; - - -extern Symbol *lua_table; -extern Word lua_ntable; -extern TaggedString **lua_constant; -extern Word lua_nconstant; - -void luaI_initsymbol (void); -void luaI_initconstant (void); -Word luaI_findsymbolbyname (char *name); -Word luaI_findsymbol (TaggedString *t); -Word luaI_findconstant (TaggedString *t); -Word luaI_findconstantbyname (char *name); -int luaI_globaldefined (char *name); -void luaI_nextvar (void); -TaggedString *luaI_createfixedstring (char *str); -int lua_markobject (TObject *o); -int luaI_ismarked (TObject *o); -void lua_pack (void); - - -#endif diff --git a/src/tree.c b/src/tree.c deleted file mode 100644 index 6f3f2d4..0000000 --- a/src/tree.c +++ /dev/null @@ -1,211 +0,0 @@ -/* -** tree.c -** TecCGraf - PUC-Rio -*/ - -char *rcs_tree="$Id: tree.c,v 1.28 1997/06/11 14:24:40 roberto Exp $"; - - -#include - -#include "luamem.h" -#include "lua.h" -#include "tree.h" -#include "lex.h" -#include "hash.h" -#include "table.h" -#include "fallback.h" - - -#define NUM_HASHS 64 - -typedef struct { - int size; - int nuse; /* number of elements (including EMPTYs) */ - TaggedString **hash; -} stringtable; - -static int initialized = 0; - -static stringtable string_root[NUM_HASHS]; - -static TaggedString EMPTY = {LUA_T_STRING, NULL, {{NOT_USED, NOT_USED}}, - 0, 2, {0}}; - - -static unsigned long hash (char *s, int tag) -{ - unsigned long h; - if (tag != LUA_T_STRING) - h = (unsigned long)s; - else { - h = 0; - while (*s) - h = ((h<<5)-h)^(unsigned char)*(s++); - } - return h; -} - - -static void luaI_inittree (void) -{ - int i; - for (i=0; isize); - TaggedString **newhash = newvector(newsize, TaggedString *); - int i; - for (i=0; inuse = 0; - for (i=0; isize; i++) - if (tb->hash[i] != NULL && tb->hash[i] != &EMPTY) { - int h = tb->hash[i]->hash%newsize; - while (newhash[h]) - h = (h+1)%newsize; - newhash[h] = tb->hash[i]; - tb->nuse++; - } - luaI_free(tb->hash); - tb->size = newsize; - tb->hash = newhash; -} - - -static TaggedString *newone(char *buff, int tag, unsigned long h) -{ - TaggedString *ts; - if (tag == LUA_T_STRING) { - ts = (TaggedString *)luaI_malloc(sizeof(TaggedString)+strlen(buff)); - strcpy(ts->str, buff); - ts->u.s.varindex = ts->u.s.constindex = NOT_USED; - ts->tag = LUA_T_STRING; - } - else { - ts = (TaggedString *)luaI_malloc(sizeof(TaggedString)); - ts->u.v = buff; - ts->tag = tag == LUA_ANYTAG ? 0 : tag; - } - ts->marked = 0; - ts->hash = h; - return ts; -} - -static TaggedString *insert (char *buff, int tag, stringtable *tb) -{ - TaggedString *ts; - unsigned long h = hash(buff, tag); - int i; - int j = -1; - if ((Long)tb->nuse*3 >= (Long)tb->size*2) - { - if (!initialized) - initialize(); - grow(tb); - } - i = h%tb->size; - while ((ts = tb->hash[i]) != NULL) - { - if (ts == &EMPTY) - j = i; - else if ((ts->tag == LUA_T_STRING) ? - (tag == LUA_T_STRING && (strcmp(buff, ts->str) == 0)) : - ((tag == ts->tag || tag == LUA_ANYTAG) && buff == ts->u.v)) - return ts; - i = (i+1)%tb->size; - } - /* not found */ - lua_pack(); - if (j != -1) /* is there an EMPTY space? */ - i = j; - else - tb->nuse++; - ts = tb->hash[i] = newone(buff, tag, h); - return ts; -} - -TaggedString *luaI_createudata (void *udata, int tag) -{ - return insert(udata, tag, &string_root[(unsigned)udata%NUM_HASHS]); -} - -TaggedString *lua_createstring (char *str) -{ - return insert(str, LUA_T_STRING, &string_root[(unsigned)str[0]%NUM_HASHS]); -} - - -void luaI_strcallIM (TaggedString *l) -{ - TObject o; - ttype(&o) = LUA_T_USERDATA; - for (; l; l=l->next) { - tsvalue(&o) = l; - luaI_gcIM(&o); - } -} - - -void luaI_strfree (TaggedString *l) -{ - while (l) { - TaggedString *next = l->next; - luaI_free(l); - l = next; - } -} - - -/* -** Garbage collection function. -*/ -TaggedString *luaI_strcollector (long *acum) -{ - Long counter = 0; - TaggedString *frees = NULL; - int i; - for (i=0; isize; j++) - { - TaggedString *t = tb->hash[j]; - if (t != NULL && t->marked <= 1) - { - if (t->marked) - t->marked = 0; - else - { - t->next = frees; - frees = t; - tb->hash[j] = &EMPTY; - counter++; - } - } - } - } - *acum += counter; - return frees; -} - diff --git a/src/tree.h b/src/tree.h deleted file mode 100644 index 22b81ae..0000000 --- a/src/tree.h +++ /dev/null @@ -1,38 +0,0 @@ -/* -** tree.h -** TecCGraf - PUC-Rio -** $Id: tree.h,v 1.18 1997/06/09 17:28:14 roberto Exp $ -*/ - -#ifndef tree_h -#define tree_h - -#include "types.h" - -#define NOT_USED 0xFFFE - - -typedef struct TaggedString -{ - int tag; /* if != LUA_T_STRING, this is a userdata */ - struct TaggedString *next; - union { - struct { - Word varindex; /* != NOT_USED if this is a symbol */ - Word constindex; /* != NOT_USED if this is a constant */ - } s; - void *v; /* if this is a userdata, here is its value */ - } u; - unsigned long hash; /* 0 if not initialized */ - int marked; /* for garbage collection; never collect (nor change) if > 1 */ - char str[1]; /* \0 byte already reserved */ -} TaggedString; - - -TaggedString *lua_createstring (char *str); -TaggedString *luaI_createudata (void *udata, int tag); -TaggedString *luaI_strcollector (long *cont); -void luaI_strfree (TaggedString *l); -void luaI_strcallIM (TaggedString *l); - -#endif diff --git a/src/types.h b/src/types.h deleted file mode 100644 index 748ed83..0000000 --- a/src/types.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -** TeCGraf - PUC-Rio -** $Id: types.h,v 1.4 1996/02/07 14:13:17 roberto Exp $ -*/ - -#ifndef types_h -#define types_h - -#include - -#ifndef real -#define real float -#endif - -#define Byte lua_Byte /* some systems have Byte as a predefined type */ -typedef unsigned char Byte; /* unsigned 8 bits */ - -#define Word lua_Word /* some systems have Word as a predefined type */ -typedef unsigned short Word; /* unsigned 16 bits */ - -#define MAX_WORD (USHRT_MAX-2) /* maximum value of a word (-2 for safety) */ -#define MAX_INT (INT_MAX-2) /* maximum value of a int (-2 for safety) */ - -#define Long lua_Long /* some systems have Long as a predefined type */ -typedef signed long Long; /* 32 bits */ - -typedef unsigned int IntPoint; /* unsigned with same size as a pointer (for hashing) */ - -#endif diff --git a/src/undump.c b/src/undump.c deleted file mode 100644 index 1a00ef7..0000000 --- a/src/undump.c +++ /dev/null @@ -1,330 +0,0 @@ -/* -** undump.c -** load bytecodes from files -*/ - -char* rcs_undump="$Id: undump.c,v 1.24 1997/06/17 18:19:17 roberto Exp $"; - -#include -#include -#include "auxlib.h" -#include "opcode.h" -#include "luamem.h" -#include "table.h" -#include "undump.h" -#include "zio.h" - -static int swapword=0; -static int swapfloat=0; -static TFunc* Main=NULL; /* functions in a chunk */ -static TFunc* lastF=NULL; - -static void FixCode(Byte* code, Byte* end) /* swap words */ -{ - Byte* p; - for (p=code; p!=end;) - { - int op=*p; - switch (op) - { - case PUSHNIL: - case PUSH0: - case PUSH1: - case PUSH2: - case PUSHLOCAL0: - case PUSHLOCAL1: - case PUSHLOCAL2: - case PUSHLOCAL3: - case PUSHLOCAL4: - case PUSHLOCAL5: - case PUSHLOCAL6: - case PUSHLOCAL7: - case PUSHLOCAL8: - case PUSHLOCAL9: - case PUSHINDEXED: - case STORELOCAL0: - case STORELOCAL1: - case STORELOCAL2: - case STORELOCAL3: - case STORELOCAL4: - case STORELOCAL5: - case STORELOCAL6: - case STORELOCAL7: - case STORELOCAL8: - case STORELOCAL9: - case STOREINDEXED0: - case ADJUST0: - case EQOP: - case LTOP: - case LEOP: - case GTOP: - case GEOP: - case ADDOP: - case SUBOP: - case MULTOP: - case DIVOP: - case POWOP: - case CONCOP: - case MINUSOP: - case NOTOP: - case POP: - case RETCODE0: - p++; - break; - case PUSHBYTE: - case PUSHLOCAL: - case STORELOCAL: - case STOREINDEXED: - case STORELIST0: - case ADJUST: - case RETCODE: - case VARARGS: - case STOREMAP: - p+=2; - break; - case STORELIST: - case CALLFUNC: - p+=3; - break; - case PUSHFUNCTION: - p+=5; /* TODO: use sizeof(TFunc*) or old? */ - break; - case PUSHWORD: - case PUSHSELF: - case CREATEARRAY: - case ONTJMP: - case ONFJMP: - case JMP: - case UPJMP: - case IFFJMP: - case IFFUPJMP: - case SETLINE: - case PUSHSTRING: - case PUSHGLOBAL: - case STOREGLOBAL: - { - Byte t; - t=p[1]; p[1]=p[2]; p[2]=t; - p+=3; - break; - } - case PUSHFLOAT: /* assumes sizeof(float)==4 */ - { - Byte t; - t=p[1]; p[1]=p[4]; p[4]=t; - t=p[2]; p[2]=p[3]; p[3]=t; - p+=5; - break; - } - case STORERECORD: - { - int n=*++p; - p++; - while (n--) - { - Byte t; - t=p[0]; p[0]=p[1]; p[1]=t; - p+=2; - } - break; - } - default: - luaL_verror("corrupt binary file: bad opcode %d at %d\n", - op,(int)(p-code)); - break; - } - } -} - -static void Unthread(Byte* code, int i, int v) -{ - while (i!=0) - { - Word w; - Byte* p=code+i; - memcpy(&w,p,sizeof(w)); - i=w; w=v; - memcpy(p,&w,sizeof(w)); - } -} - -static int LoadWord(ZIO* Z) -{ - Word w; - zread(Z,&w,sizeof(w)); - if (swapword) - { - Byte* p=(Byte*)&w; - Byte t; - t=p[0]; p[0]=p[1]; p[1]=t; - } - return w; -} - -static int LoadSize(ZIO* Z) -{ - Word hi=LoadWord(Z); - Word lo=LoadWord(Z); - int s=(hi<<16)|lo; - if ((Word)s != s) lua_error("code too long"); - return s; -} - -static void* LoadBlock(int size, ZIO* Z) -{ - void* b=luaI_malloc(size); - zread(Z,b,size); - return b; -} - -static char* LoadString(ZIO* Z) -{ - int size=LoadWord(Z); - char *b=luaI_buffer(size); - zread(Z,b,size); - return b; -} - -static char* LoadNewString(ZIO* Z) -{ - return LoadBlock(LoadWord(Z),Z); -} - -static void LoadFunction(ZIO* Z) -{ - TFunc* tf=new(TFunc); - tf->next=NULL; - tf->locvars=NULL; - tf->size=LoadSize(Z); - tf->lineDefined=LoadWord(Z); - if (IsMain(tf)) /* new main */ - { - tf->fileName=LoadNewString(Z); - Main=lastF=tf; - } - else /* fix PUSHFUNCTION */ - { - tf->marked=LoadWord(Z); - tf->fileName=Main->fileName; - memcpy(Main->code+tf->marked,&tf,sizeof(tf)); - lastF=lastF->next=tf; - } - tf->code=LoadBlock(tf->size,Z); - if (swapword || swapfloat) FixCode(tf->code,tf->code+tf->size); - while (1) /* unthread */ - { - int c=zgetc(Z); - if (c==ID_VAR) /* global var */ - { - int i=LoadWord(Z); - char* s=LoadString(Z); - int v=luaI_findsymbolbyname(s); - Unthread(tf->code,i,v); - } - else if (c==ID_STR) /* constant string */ - { - int i=LoadWord(Z); - char* s=LoadString(Z); - int v=luaI_findconstantbyname(s); - Unthread(tf->code,i,v); - } - else - { - zungetc(Z); - break; - } - } -} - -static void LoadSignature(ZIO* Z) -{ - char* s=SIGNATURE; - while (*s!=0 && zgetc(Z)==*s) - ++s; - if (*s!=0) lua_error("cannot load binary file: bad signature"); -} - -static void LoadHeader(ZIO* Z) -{ - Word w,tw=TEST_WORD; - float f,tf=TEST_FLOAT; - int version; - LoadSignature(Z); - version=zgetc(Z); - if (version>0x23) /* after 2.5 */ - { - int oldsizeofW=zgetc(Z); - int oldsizeofF=zgetc(Z); - int oldsizeofP=zgetc(Z); - if (oldsizeofW!=2) - luaL_verror( - "cannot load binary file created on machine with sizeof(Word)=%d; " - "expected 2",oldsizeofW); - if (oldsizeofF!=4) - luaL_verror( - "cannot load binary file created on machine with sizeof(float)=%d; " - "expected 4\nnot an IEEE machine?",oldsizeofF); - if (oldsizeofP!=sizeof(TFunc*)) /* TODO: pack? */ - luaL_verror( - "cannot load binary file created on machine with sizeof(TFunc*)=%d; " - "expected %d",oldsizeofP,(int)sizeof(TFunc*)); - } - zread(Z,&w,sizeof(w)); /* test word */ - if (w!=tw) - { - swapword=1; - } - zread(Z,&f,sizeof(f)); /* test float */ - if (f!=tf) - { - Byte* p=(Byte*)&f; - Byte t; - swapfloat=1; - t=p[0]; p[0]=p[3]; p[3]=t; - t=p[1]; p[1]=p[2]; p[2]=t; - if (f!=tf) /* TODO: try another perm? */ - lua_error("cannot load binary file: unknown float representation"); - } -} - -static void LoadChunk(ZIO* Z) -{ - LoadHeader(Z); - while (1) - { - int c=zgetc(Z); - if (c==ID_FUN) LoadFunction(Z); else { zungetc(Z); break; } - } -} - -/* -** load one chunk from a file. -** return list of functions found, headed by main, or NULL at EOF. -*/ -TFunc* luaI_undump1(ZIO* Z) -{ - int c=zgetc(Z); - if (c==ID_CHUNK) - { - LoadChunk(Z); - return Main; - } - else if (c!=EOZ) - lua_error("not a lua binary file"); - return NULL; -} - -/* -** load and run all chunks in a file -*/ -int luaI_undump(ZIO* Z) -{ - TFunc* m; - while ((m=luaI_undump1(Z))) - { - int status=luaI_dorun(m); - luaI_freefunc(m); - if (status!=0) return status; - } - return 0; -} diff --git a/src/undump.h b/src/undump.h deleted file mode 100644 index 3937358..0000000 --- a/src/undump.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -** undump.h -** definitions for lua decompiler -** $Id: undump.h,v 1.6 1997/06/17 18:19:17 roberto Exp $ -*/ - -#ifndef undump_h -#define undump_h - -#include "func.h" -#include "zio.h" - -#define IsMain(f) (f->lineDefined==0) - -/* definitions for chunk headers */ - -#define ID_CHUNK 27 /* ESC */ -#define ID_FUN 'F' -#define ID_VAR 'V' -#define ID_STR 'S' -#define SIGNATURE "Lua" -#define VERSION 0x25 /* last format change was in 2.5 */ -#define TEST_WORD 0x1234 /* a word for testing byte ordering */ -#define TEST_FLOAT 0.123456789e-23 /* a float for testing representation */ - - -TFunc* luaI_undump1(ZIO* Z); -int luaI_undump(ZIO* Z); /* load all chunks */ - -#endif diff --git a/test/array.lua b/test/array.lua index 48c2857..728a0b2 100644 --- a/test/array.lua +++ b/test/array.lua @@ -1,5 +1,3 @@ -$debug - a = {} local i=0 diff --git a/test/bisect.lua b/test/bisect.lua index 8b72065..4de9e99 100644 --- a/test/bisect.lua +++ b/test/bisect.lua @@ -1,9 +1,9 @@ -$debug -- bisection method for solving non-linear equations function bisect(f,a,b,fa,fb) write(n," a=",a," fa=",fa," b=",b," fb=",fb,"\n") local c=(a+b)/2 + if c==a or c==b then return c end if abs(a-b)v do j=j-1 end - a[i],a[j]=a[j],a[i] - until j<=i - a[i],a[j]=a[j],a[i] -- undo last swap - a[j],a[r]=a[r],a[j] - quicksort(a,r,j-1) - quicksort(a,j+1,s) -end - -function selectionsort(a,n) - local i=1 - while i<=n do - local m, j = i, i+1 - while j<=n do - if a[j]>a[m] then m=j end -- reverse sort - j=j+1 - end - a[i],a[m]=a[m],a[i] -- swap a[i] and a[m] - i=i+1 - end -end - -function show(m,x) - write(m,"\n\t") - local i=0 - while x[i] do - write(x[i]) - i=i+1 - if x[i] then write(",") end - end - write("\n") -end - -x={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"} - -n=1 while x[n] do n=n+1 end -- count elements -x[0]="A" x[n]="Z" -- quicksort need sentinels - -show("original",x) - -quicksort(x,1,n-1) -show("after quicksort",x) - -selectionsort(x, n-1) -show("after reverse selection sort",x) +-- extracted from Programming Pearls, page 110 +function qsort(x,l,u,f) + if ly end) + show("after reverse selection sort",x) + qsort(x,1,n,function (x,y) return x