diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..96cff23d61 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.16) +project(lua LANGUAGES C) +set(CMAKE_C_STANDARD 11) + +file(GLOB LUA_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.c" "${CMAKE_CURRENT_SOURCE_DIR}/*.h") +add_library(${PROJECT_NAME} STATIC ${LUA_SOURCES}) + +target_include_directories(${PROJECT_NAME} + PUBLIC + "${CMAKE_CURRENT_SOURCE_DIR}") + +add_library(lua::lua ALIAS lua) diff --git a/llex.c b/llex.c index 1c4227ca4c..4ad7bb6d48 100644 --- a/llex.c +++ b/llex.c @@ -47,8 +47,9 @@ static const char *const luaX_tokens [] = { "end", "false", "for", "function", "goto", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while", - "//", "..", "...", "==", ">=", "<=", "~=", - "<<", ">>", "::", "", + "//", "..", "..=", "...", "==", ">=", "<=", "~=", "!=", + "<<", ">>", "+=", "-=", "*=", "/=", "%=", "^=", + "::", "", "", "", "", "" }; @@ -468,9 +469,13 @@ static int llex (LexState *ls, SemInfo *seminfo) { next(ls); break; } - case '-': { /* '-' or '--' (comment) */ + case '-': { /* '-' or '-=' or '--' (comment) */ next(ls); - if (ls->current != '-') return '-'; + if (ls->current == '=') { + next(ls); + return TK_SUBA; + } + else if (ls->current != '-') return '-'; /* else is a comment */ next(ls); if (ls->current == '[') { /* long comment? */ @@ -516,13 +521,36 @@ static int llex (LexState *ls, SemInfo *seminfo) { } case '/': { next(ls); - if (check_next1(ls, '/')) return TK_IDIV; /* '//' */ + if (ls->current == '=') { + next(ls); + return TK_DIVA; + } + else if (check_next1(ls, '/')) return TK_IDIV; /* '//' */ else return '/'; } - case '~': { + case '+': + case '*': + case '%': + case '^': { + int c = ls->current; + next(ls); + if (ls->current != '=') return c; /* '+', '*', '%', '^' */ + else { + next(ls); + switch (c) { + case '+': return TK_ADDA; /* '+=' */ + case '*': return TK_MULA; /* '*=' */ + case '%': return TK_MODA; /* '%=' */ + case '^': return TK_POWA; /* '^=' */ + } + } + } + case '~': + case '!': { + int c = ls->current; next(ls); - if (check_next1(ls, '=')) return TK_NE; /* '~=' */ - else return '~'; + if (check_next1(ls, '=')) return c == '~' ? TK_NE /* '~=' */ : TK_NE2 /* '!=' */; + else return c; } case ':': { next(ls); @@ -533,11 +561,13 @@ static int llex (LexState *ls, SemInfo *seminfo) { read_string(ls, ls->current, seminfo); return TK_STRING; } - case '.': { /* '.', '..', '...', or number */ + case '.': { /* '.', '..', '..=', '...', or number */ save_and_next(ls); if (check_next1(ls, '.')) { if (check_next1(ls, '.')) return TK_DOTS; /* '...' */ + else if (check_next1(ls, '=')) + return TK_CONCATA; /* '..=' */ else return TK_CONCAT; /* '..' */ } else if (!lisdigit(ls->current)) return '.'; diff --git a/llex.h b/llex.h index 389d2f8635..0443811a17 100644 --- a/llex.h +++ b/llex.h @@ -36,8 +36,9 @@ enum RESERVED { TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, /* other terminal symbols */ - TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, + TK_IDIV, TK_CONCAT, TK_CONCATA, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_NE2, TK_SHL, TK_SHR, + TK_ADDA, TK_SUBA, TK_MULA, TK_DIVA, TK_MODA, TK_POWA, TK_DBCOLON, TK_EOS, TK_FLT, TK_INT, TK_NAME, TK_STRING }; diff --git a/lparser.c b/lparser.c index 380e45f58c..967719bc32 100644 --- a/lparser.c +++ b/lparser.c @@ -1255,7 +1255,7 @@ static BinOpr getbinopr (int op) { case TK_SHL: return OPR_SHL; case TK_SHR: return OPR_SHR; case TK_CONCAT: return OPR_CONCAT; - case TK_NE: return OPR_NE; + case TK_NE: case TK_NE2: return OPR_NE; case TK_EQ: return OPR_EQ; case '<': return OPR_LT; case TK_LE: return OPR_LE; @@ -1440,6 +1440,44 @@ static void restassign (LexState *ls, struct LHS_assign *lh, int nvars) { } +/* +** Parse and compile a compound assignment. +** Made by https://github.com/samhocevar +** +** compoundassign -> ( '+=' | '-=' | '*=' | '/=' | '%=' | '..=' | '^=' ) expression +*/ +static void compoundassign (LexState *ls, expdesc *v) { + int i, line, extra; + FuncState *fs = ls->fs; + expdesc e1 = *v, e2; + BinOpr op = ls->t.token == TK_ADDA ? OPR_ADD : + ls->t.token == TK_SUBA ? OPR_SUB : + ls->t.token == TK_MULA ? OPR_MUL : + ls->t.token == TK_DIVA ? OPR_DIV : + ls->t.token == TK_MODA ? OPR_MOD : + ls->t.token == TK_CONCATA ? OPR_CONCAT : + ls->t.token == TK_POWA ? OPR_POW : + OPR_NOBINOPR; + extra = fs->freereg - fs->nactvar; + for (i = 0; i < extra; ++i) + new_localvarliteral(ls, "(for compound)"); + adjustlocalvars(ls, extra); + + luaX_next(ls); + line = ls->linenumber; + + enterlevel(ls); + luaK_infix(fs, op, &e1); + expr(ls, &e2); + luaK_posfix(fs, op, &e1, &e2, line); + leavelevel(ls); + + luaK_exp2nextreg(fs, &e1); + luaK_setoneret(ls->fs, &e1); + luaK_storevar(ls->fs, v, &e1); +} + + static int cond (LexState *ls) { /* cond -> exp */ expdesc v; @@ -1807,7 +1845,17 @@ static void exprstat (LexState *ls) { FuncState *fs = ls->fs; struct LHS_assign v; suffixedexp(ls, &v.v); - if (ls->t.token == '=' || ls->t.token == ',') { /* stat -> assignment ? */ + if (ls->t.token == TK_ADDA || + ls->t.token == TK_SUBA || + ls->t.token == TK_MULA || + ls->t.token == TK_DIVA || + ls->t.token == TK_MODA || + ls->t.token == TK_CONCATA || + ls->t.token == TK_POWA) { + v.prev = NULL; + compoundassign(ls, &v.v); + } + else if (ls->t.token == '=' || ls->t.token == ',') { /* stat -> assignment ? */ v.prev = NULL; restassign(ls, &v, 1); } diff --git a/onelua.c b/onelua.c deleted file mode 100644 index 2a43496124..0000000000 --- a/onelua.c +++ /dev/null @@ -1,121 +0,0 @@ -/* -** Lua core, libraries, and interpreter in a single file. -** Compiling just this file generates a complete Lua stand-alone -** program: -** -** $ gcc -O2 -std=c99 -o lua onelua.c -lm -** -** or -** -** $ gcc -O2 -std=c89 -DLUA_USE_C89 -o lua onelua.c -lm -** -*/ - -/* default is to build the full interpreter */ -#ifndef MAKE_LIB -#ifndef MAKE_LUAC -#ifndef MAKE_LUA -#define MAKE_LUA -#endif -#endif -#endif - - -/* -** Choose suitable platform-specific features. Default is no -** platform-specific features. Some of these options may need extra -** libraries such as -ldl -lreadline -lncurses -*/ -#if 0 -#define LUA_USE_LINUX -#define LUA_USE_MACOSX -#define LUA_USE_POSIX -#define LUA_ANSI -#endif - - -/* no need to change anything below this line ----------------------------- */ - -#include "lprefix.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* setup for luaconf.h */ -#define LUA_CORE -#define LUA_LIB -#define ltable_c -#define lvm_c -#include "luaconf.h" - -/* do not export internal symbols */ -#undef LUAI_FUNC -#undef LUAI_DDEC -#undef LUAI_DDEF -#define LUAI_FUNC static -#define LUAI_DDEC(def) /* empty */ -#define LUAI_DDEF static - -/* core -- used by all */ -#include "lzio.c" -#include "lctype.c" -#include "lopcodes.c" -#include "lmem.c" -#include "lundump.c" -#include "ldump.c" -#include "lstate.c" -#include "lgc.c" -#include "llex.c" -#include "lcode.c" -#include "lparser.c" -#include "ldebug.c" -#include "lfunc.c" -#include "lobject.c" -#include "ltm.c" -#include "lstring.c" -#include "ltable.c" -#include "ldo.c" -#include "lvm.c" -#include "lapi.c" - -/* auxiliary library -- used by all */ -#include "lauxlib.c" - -/* standard library -- not used by luac */ -#ifndef MAKE_LUAC -#include "lbaselib.c" -#include "lcorolib.c" -#include "ldblib.c" -#include "liolib.c" -#include "lmathlib.c" -#include "loadlib.c" -#include "loslib.c" -#include "lstrlib.c" -#include "ltablib.c" -#include "lutf8lib.c" -#include "linit.c" -#endif - -/* lua */ -#ifdef MAKE_LUA -#include "lua.c" -#endif - -/* luac */ -#ifdef MAKE_LUAC -#include "luac.c" -#endif