lua c++中没有括号的函数

我正在创建一个名为musica的应用程序,它根据在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"
}
/*
信息代码

M8I5H: 信息
MSKIE:语法错误
M3UET:未知错误

*/
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)
{
// 尚未添加
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));
}

}

如何使play函数没有括号?

预先感谢您

点赞
用户7509065
用户7509065

标准 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;
+
+  /* 将函数准备好,可以像 suffixedexp 一样对其进行调用 */
+  singlevar(ls, f);
+  luaK_exp2nextreg(fs, f);
+
+  /* 这一部分来自于 funcargs 的 '(' 分支中的 else 块*/
+  explist(ls, &args);
+  if (hasmultret(args.k))
+    luaK_setmultret(fs, &args);
+
+  /* 这一部分来自于 funcargs 开关语句后的部分 */
+  lua_assert(f->k == VNONRELOC);
+  base = f->u.info;  /* 调用时的基础寄存器 */
+  if (hasmultret(args.k))
+    nparams = LUA_MULTRET;  /* 开放调用 */
+  else {
+    luaK_exp2nextreg(fs, &args);  /* 关闭最后一个参数 */
+    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;  /* 调用会删除函数和参数并留下一个结果(除非修改)*/
+
+  /* 这一部分来自于 exprstat 的 else 块 */
+  inst = &getinstruction(fs, &v.v);
+  SETARG_C(*inst, 1);  /* 调用语句不使用结果 */
+}
+
+
 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;
+      }
+    }
+    /* 下面就是 stat -> func | assignment */
+    default: {
       exprstat(ls);
       break;

这使得 play 在语句开头时像关键字一样进行操作。它捕获类似于 local foo, bar, baz = 之后的表达式。我必须强调这确实是一个相当蹩脚的方法。你的另一个选择是使用 Metalua 进行同样的操作,但这将限制你使用已经过时 8 年且存在已知安全问题的 Lua 5.1 版本。

2020-11-13 02:34:19