用户操作
[即时聊天] [发私信] [加为好友]
邓际锋ID:soloist
84661次访问,排名1139好友1人,关注者2
soloist的文章
原创 39 篇
翻译 0 篇
转载 0 篇
评论 189 篇
soloist的公告
欢迎吹毛求疵,感谢您对任何错误的指正,包括技术的、语法的、用词的、标点的、典故的、引用资料的……
最近评论
qingbai:lua绝对是个好东西。但国内除了java就是.net,其他东西没法活。因为程序员得工作,得吃饭。国内有哪家公司用lua?唉没办法呀。国外是一片繁荣,“百家争鸣”,国内是“青一色”的java和.net!无奈!
zhangyilan:尽管没有在实际代码的编写中碰到这个问题,不过也先学习一下,免得出现问题了搞出清楚情况。
ddrmsdos:这篇文章写的太好了,分析的非常仔细,以前常常碰到这类问题,终于解了我多年的心头之患......
ollydbg23:楼主的这篇文章写的非常好啊!
我看了以后,还是挺有收获感的,多谢多谢!
我也是对汇编,c++的比较感兴趣,有空可以交流一下!
w2001:写得很好
文章分类
收藏
    相册
    好博链接
    C++罗浮宫
    cpper
    fixopen
    fmddlmyy
    neoragex2002
    whinah
    云风
    梦想风暴
    沉思者
    许式伟
    负暄琐话
    辣子鸡丁
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 Lua的语法是无歧义的吗?收藏

    新一篇: 为什么会出现LNK2005"符号已定义"的链接错误? | 旧一篇: C++的缺省参数与函数重载是正交特性吗?

        Lua5.0的语法非常简洁,这从参考手册中的语法定义的规模(转换成标准BNF形式大概有100个左右的产生式)可以看出。不过简洁归简洁,它却不完全是无二义性的。下面将用具体例子揭示什么样的代码会引起歧义(执行环境是www.lua.org发布的Lua5.04)。

        首先定义如下几个函数:

    function foo(a)
       print("foo print",a)
       return a
    end

    function goo(a)
       print("goo print",a)
       return a
    end

    function hoo(a)
       print("hoo print",a)
       return a
    end

    试看这一段代码:

    foo(goo)
    (hoo)(1979)

    如果试图编译执行上面这段程序,那么解释器就会报告 "ambiguous syntax (function call x new statement) near '(' " 这样的错误。为什么呢?或许写程序的人原本的意思就是第一行foo(goo)为一个单独的函数调用语句(statement),而第二行(hoo)(1979)又为另一个单独的函数调用语句(Lua中语句之间的分隔符——分号并非必需,而是可选的)。但是不要忘记了foo(goo)(hoo)是一个语法上完全合法的函数调用形式(在编译过程中换行符作为空白符会被忽略掉),foo(goo)(hoo)(1979)也可以成为一个完整的函数调用语句。这样的话,编译器就无法知道程序员的真正意图了。

        我们可以再深入到编译过程里头一点看看。Lua语法的形式定义(转换成BNF标准形式)包含如下几个产生式:

    (1) stat -> functioncall  (语句的产生式)
    (2) prefixexp -> functioncall (前缀表达式的产生式)
    (3) functioncall -> prefixexp args
                      | prefixexp ':' Name args (函数调用的产生式)


    可以发现,functioncall既可以被规约(reduce)为stat,也可以被规约成prefixexp,(1)和(2)两个产生式发生了冲突,编译器不知道用哪一个对foo(goo)进行规约,所以便出现了错误。

        其实要解决这个问题歧义问题也很简单,在第一行后面加一个语句分隔符——分号,编译器就会把代码编译成两个独立的语句。或者把两行合并成一行,那么foo(goo)(hoo)(1979)就被看作是一个完整的函数调用(其实此时仍然是有歧义的,但是Lua5.04通过优先选择prefixexp -> functioncall进行规约解决了二义性)。

        实际上,还有另外3种情况也会引起歧义:

    -- prefixexp -> functioncall 与
    -- exp -> functioncall 冲突。
    -- 编译器不知道该把foo(goo)解释成表达式(exp)还是前缀表达式

    local v = foo(goo)
    (hoo)(1979)

    -- exp -> var 与 prefixexp -> var 冲突
    -- 第二行的变量(var)m不知道该被看成表达式还是前缀表达式

    m = foo
    local v = m
    (goo)(1979)

    -- prefixexp -> '(' exp ')' 与
    -- exp -> '(' exp ')' 冲突
    -- 不知道该把(t.fn)看成表达式还是前缀表达式

    t = {fn = foo}
    local v = (t.fn)
    (goo)(1979)

    第一个例子中解决歧义的两种方法同样也适用于这三种情况。至此我们不难发现,引起歧义的根本原因在于Lua语句之间的分隔符是可选而不是必需的。如果强制要求象C语言那样每条语句后跟一个分号,那么二义性就不复存在(这一点在本文作者构造Lua5.0的SLR解析表时得到了验证)。但是有许多人未必喜欢敲入那么多讨厌的分号,所以Lua的作者把选择的权利留给了程序员自己,付出的代价就是引进了这些模糊的代码(虽然出现的几率不大),这也算是语言设计时的一种折衷吧。

    发表于 @ 2005年09月17日 15:41:00|评论(loading...)|编辑

    新一篇: 为什么会出现LNK2005"符号已定义"的链接错误? | 旧一篇: C++的缺省参数与函数重载是正交特性吗?

    评论

    #soloist 发表于2005-11-07 12:02:00  IP: 218.78.224.*
    这是我为了开发一个Lua编译器,在构造SLR解析表时才发现的。
    #whinah 发表于2005-11-06 16:24:00  IP: 218.245.133.*
    楼主对语言的细节注意得很呀。
    #wing lee 发表于2005-11-21 17:40:00  IP: 10.56.64.18, 220.248.37.*
    soloist 好,我因为魔兽世界的关系开始接触LUA,觉得它具备一些很新鲜的特性。但是能够找到的文档就是官网的REF。楼主能不能共享一些关于LUA的笔记之类的东西,你的LUA方面的文章对于我来说还是太高阶了。非常感谢
    #soloist 发表于2005-11-21 19:54:00  IP: 218.78.226.*
    最好的入门教材是发明者本人写的《Programming in Lua》,条理清晰,循序渐进,非常适合自学。

    网址在这: http://www.lua.org/pil/
    #刘未鹏 发表于2005-11-22 05:48:00  IP: 222.94.28.*
    非常有意思:-)
    难得看到这样的blog.为什么以前没发现?
    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © soloist