我正在尝试实现一个简单的C ++函数,它检查Lua脚本的语法。为此,我正在使用Lua的编译器函数luaL_loadbufferx()
并在之后检查其返回值。
最近,我遇到了一个问题,因为我认为我认为应该标记为无效的代码未被检测到,而是脚本在运行时稍后失败(例如{{1} }})。
示例Lua代码(可在official Lua demo上测试):
lua_pcall()
目标显然是在编译时捕获所有语法错误。所以我的问题是:
function myfunc()
return "everyone"
end
-- Examples of unexpected behaviour:
-- The following lines pass the compile time check without errors.
print("Hello " .. myfunc() "!") -- Runtime error: attempt to call a string value
print("Hello " .. myfunc() {1,2,3}) -- Runtime error: attempt to call a string value
-- Other examples:
-- The following lines contain examples of invalid syntax, which IS detected by compiler.
print("Hello " myfunc() .. "!") -- Compile error: ')' expected near 'myfunc'
print("Hello " .. myfunc() 5) -- Compile error: ')' expected near '5'
print("Hello " .. myfunc() .. ) -- Compile error: unexpected symbol near ')'
在这个特定的例子中是否有问题?luaL_loadbufferx()
运行代码。注意:我使用的是Lua版本5.3.4(manual here)。
非常感谢你的帮助。
答案 0 :(得分:5)
myfunc() "!"
和myfunc(){1,2,3}
都是有效的Lua表达式。
Lua允许调用 exp string 形式。请参阅Syntax of Lua中的functioncall
和prefixexp
。
因此myfunc() "!"
是一个有效的函数调用,它调用myfunc
返回的任何内容并使用字符串"!"
调用它。
调用 exp table-literal 形式的事情也是如此。
答案 1 :(得分:2)
我正在回答我自己的问题,以防万一其他人在将来偶然发现类似的问题并寻找解决方案。
Lua manual (in its section 3.4.10 – Function Calls)基本上说,有三种不同的方式为Lua函数提供参数。
参数具有以下语法:
在调用之前计算所有参数表达式。 f {fields}形式的调用是f({fields})的语法糖;也就是说,参数列表是一个新表。形式为f'字符串'(或f“字符串”或f [[string]])的调用是f('string')的语法糖;也就是说,参数列表是单个文字字符串。args ::= ‘(’ [explist] ‘)’ args ::= tableconstructor args ::= LiteralString
在lhf中指出his answer,myfunc()"!"
和myfunc(){1,2,3}
都是有效的Lua表达式。这意味着Lua编译器没有做错任何事情,因为它在编译时知道函数返回值。
问题中给出的原始示例代码:
print("Hello " .. myfunc() "!")
然后可以改写为:
print("Hello " .. (myfunc()) ("!"))
哪个(执行时)转换为:
print("Hello " .. ("everyone") ("!"))
因而导致运行时错误消息attempt to call a string value
(可以重写为:字符串everyone
不是函数,因此您无法调用它。)
据我了解,这两种提供参数的替代方法与标准func(arg)
语法相比没有任何实际好处。这就是我最终修改Lua解析器文件的原因。保持这种替代语法的不足之处太大了。这就是我所做的(与v5.3.4相关):
lparser.c
中,我搜索了函数:
static void suffixedexp (LexState *ls, expdesc *v)
case '(': case TK_STRING: case '{':
至case '(':
警告!通过这样做,我修改了Lua语言,正如他在评论中所述,它不再被称为 pure Lua。如果您不确定它是否正是您想要的,我不推荐这种方法。
使用此轻微修改编译器将上述两种替代语法检测为错误。当然,我不能再在Lua脚本中使用它们,但对于我的特定应用程序,它就没问题了。
我需要做的就是在某处注意此更改,以便在将Lua升级到更高版本时找到它。
答案 2 :(得分:2)
另一种方法是更改字符串的元表,使对字符串的调用有效。
local mt = getmetatable ""
mt.__call = function (self, args) return self .. args end
print(("x") "y") -- outputs `xy`
现在,对字符串的有效语法调用将导致字符串连接而不是运行时错误。