1

我正在创建一个基于 Lua 脚本中调用的函数播放音乐的应用程序。我称之为音乐。问题是我需要一个不需要括号的函数。像这样:

play note("A")

这是我的完整代码:

#include <iostream>
#include <string>

extern "C"
{
#include "../lua/include/lua.h"
#include "../lua/include/lauxlib.h"
#include "../lua/include/lualib.h"
}
/*
Message codes

M8I5H: Information
MSKIE: Syntax error
M3UET: Unknown error

*/
enum class MUSICA_NOTE_ENUM
{
A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z
};

int musica_play(lua_State *L)
{
// Not added yet
return 1;
}

int musica_note(lua_State *L)
{
  std::string note = lua_tostring(L, 1);

  lua_pushnumber(L, (lua_Number)((MUSICA_NOTE_ENUM)(note.at(0) & 31)));
  return 1;
}

int main(){
std::string music = R"(a = 75
play note("A")
play note("B")
play note("C")
-- play melody(melody_piono_tune)
)";
std::string m = "play note(\"A\")";

lua_State *L = luaL_newstate();

lua_register(L, "note", musica_note);
lua_register(L, "play", musica_play);

int r = luaL_dostring(L, m.c_str());


if(r == LUA_OK)
{

}else{
printf("[Line: %d, File: %s, MessageCode: MSKIE] MUSICA: There was a problem interperting the file:\n%s\n\n", __LINE__, __FILE__, lua_tostring(L, -1));
}

}

如何使播放功能无括号?

先感谢您

4

1 回答 1

1

标准 Lua 仅支持在使用表构造函数或字符串文字作为其唯一参数调用函数时调用不带括号的函数。由于您希望能够使用其他值调用它,因此您唯一的选择是修补 Lua 解析器。以下是你可以通过修改 Lua 的源代码来做到这一点的方法(这个补丁是针对 Lua 5.4.1 版本准备的):

diff --git a/src/lparser.c b/src/lparser.c
index bc7d9a4..d917687 100644
--- a/src/lparser.c
+++ b/src/lparser.c
@@ -1795,6 +1795,44 @@ static void localstat (LexState *ls) {
 }


+static void playstat (LexState *ls) {
+  FuncState *fs = ls->fs;
+  struct LHS_assign v;
+  expdesc *f = &v.v;
+  int line = ls->linenumber;
+  expdesc args;
+  int base, nparams;
+  Instruction *inst;
+
+  /* get the function ready to call like suffixedexp does */
+  singlevar(ls, f);
+  luaK_exp2nextreg(fs, f);
+
+  /* this section taken from the else inside case '(' in funcargs */
+  explist(ls, &args);
+  if (hasmultret(args.k))
+    luaK_setmultret(fs, &args);
+
+  /* this section taken from after the switch statement in funcargs */
+  lua_assert(f->k == VNONRELOC);
+  base = f->u.info;  /* base register for call */
+  if (hasmultret(args.k))
+    nparams = LUA_MULTRET;  /* open call */
+  else {
+    luaK_exp2nextreg(fs, &args);  /* close last argument */
+    nparams = fs->freereg - (base+1);
+  }
+  init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2));
+  luaK_fixline(fs, line);
+  fs->freereg = base+1;  /* call remove function and arguments and leaves
+                            (unless changed) one result */
+
+  /* this section taken from the else block in exprstat */
+  inst = &getinstruction(fs, &v.v);
+  SETARG_C(*inst, 1);  /* call statement uses no results */
+}
+
+
 static int funcname (LexState *ls, expdesc *v) {
   /* funcname -> NAME {fieldsel} [':' NAME] */
   int ismethod = 0;
@@ -1932,6 +1970,13 @@ static void statement (LexState *ls) {
       gotostat(ls);
       break;
     }
+    case TK_NAME: {
+      if (!strcmp(getstr(ls->t.seminfo.ts), "play")) {
+        playstat(ls);
+        break;
+      }
+    }
+    /* FALLTHROUGH */
     default: {  /* stat -> func | assignment */
       exprstat(ls);
       break;

这使得play在语句开头时的行为就像关键字一样。它捕获它之后的表达式,类似于 how local foo, bar, baz =does。我必须强调,这确实是一个 hack。您的另一个选择是对Metalua做同样的事情,但这将您限制在 Lua 5.1,它已经停产 8 年并且存在已知的安全问题。

于 2020-11-13T02:34:19.830 回答