【问题标题】:What can create a lexical error in C?什么会在 C 中产生词法错误?
【发布时间】:2011-07-28 23:08:55
【问题描述】:

除了不关闭评论/*...,C 语言中的词法错误是什么?

【问题讨论】:

    标签: c compiler-errors lexical-analysis


    【解决方案1】:

    格式错误的浮点常量(例如123.34e123.45.33)。

    【讨论】:

    • 哼……科学记数法很原创!谢谢。
    • 'ABC' 是一个定义明确的词法元素。参见标准中字符常量的定义。
    【解决方案2】:

    词法错误:

    1. 未终止的评论
    2. 任何不是有效预处理器标记的非注释和非空白字符序列
    3. 任何不是有效 C 令牌的预处理器令牌;一个例子是0xe-2,它看起来像一个表达式,但根据标准实际上是一个语法错误——一个奇怪的极端情况,由 pp-tokens 规则产生。

    【讨论】:

      【解决方案3】:

      非法身份

      int 3d = 1;
      

      非法的预处理指令

      #define x 1
      

      意外的令牌

      if [0] {}
      

      无法解析的id

      while (0) {}            
      

      【讨论】:

      • OP 询问 lexical 错误。 “int 3d = 1”的合法词位为“int”、“3”、“d”、“=”、“1”。 "#defune" 被视为两个词位 "#","define";后者可能是非法的。意外的标记和拼写错误的关键字是语法错误,而不是词法错误。
      【解决方案4】:

      如果放在字符串或注释之外的任何地方,C 中的 [@$`] 和其他类似的符号(可能来自 unicode)是否会出现词法错误?它们不构成该语言的任何有效词汇序列。它们无法通过词法分析器,因为词法分析器无法将它们识别为任何类型的有效标记。通常,词法分析器是基于 FSM 或正则表达式的,因此这些符号只是无法识别的输入。

      例如在下面的代码中有几个词法错误:

      int main(void){
      ` int a = 3;
      @ —
      return 0;
      }
      

      我们可以通过将它提供给 gcc 来支持它,这给了

      ../a.c: In function ‘main’:
      ../a.c:2: error: stray ‘`’ in program
      ../a.c:3: error: stray ‘@’ in program
      ../a.c:3: error: stray ‘\342’ in program  
      ../a.c:3: error: stray ‘\200’ in program
      ../a.c:3: error: stray ‘\224’ in program
      

      GCC 很聪明,并且会进行错误恢复,因此它解析了一个函数定义(它知道我们在“main”中),但这些错误绝对看起来像词法错误,它们不是语法错误,这是正确的。 GCC 的词法分析器没有可以从这些符号构建的任何类型的标记。请注意,它甚至将一个三字节的 UTF-8 符号视为三个无法识别的符号。

      【讨论】:

        【解决方案5】:

        如果编译器根据此语法进行词法分析,则基本上任何不符合 ISO C 9899/1999 附件 A.1“词法语法”的内容都是词法错误。以下是一些示例:

        "abc<EOF> // invalid string literal (from Ira Baxter's answer) (ISO C 9899/1999 6.4.4.5)
        
        'a<EOF> // invalid char literal (6.4.4.4)
        

        EOF 是文件的结尾。

        double a = 1e*3; // misguided floating point literal (6.4.4.2)
        
        int a = 0x0g; // invalid integer hex literal (6.4.4.1)
        
        int a = 09; // invalid octal literal (6.4.4.1)
        
        char a = 'aa'; // too long char literal (from Joel's answer, 6.4.4.4)
        
        double a = 0x1p1q; // invalid hexadecimal floating point constant (6.4.4.2)
        // instead of q, only a float suffix, that is 'f', 'l', 'F' or 'L' is allowed.
        
        // invalid header name (6.4.7)
        #include <<a.h>
        #include ""a.h"
        

        【讨论】:

        • 我不认为 0x0g 是一个词法错误。我认为这是两个令牌。它可能总是产生 g 作为变量名的 syntax 错误。
        • 当您通过前导 0 识别八进制文字的开头并期望它与正则表达式 0[0-7]* 匹配时,我认为是。
        • GCC 3.4.5 输出:八进制常量中的无效数字“9”
        • 这里的问题是 GCC 没有告诉错误的类型。我知道解析器检测到位置错误,而不是词法分析器。但是阅读 hexa 和 octal 的标记定义,我可能同意这两个确实是 lex 错误。我仍然对此感到不安。
        • @Ira 0x0g 是根据标准的单个预处理器令牌。
        【解决方案6】:

        这里有一些:

         "abc<EOF>
        

        其中 EOF 是文件的结尾。事实上,很多词位中间的EOF应该会产生错误:

         0x<EOF>
        

        我认为在字符串中使用错误的转义是非法的:

          "ab\qcd"
        

        浮点指数可能有问题

         1e+%
        

        可以说,您不应该在预处理器指令的末尾添加内容:

        #if x   %
        

        【讨论】:

        • 哼...不是关闭字符串。当我看到类似的未结束评论时,我应该想到这一点。但是谢谢,有效的!
        • 你会认为"abc&lt;EOL&gt; 是一个词法错误吗? (行尾而不是文件尾)
        • @Dr Beco: 不是关于我的……我认为 C 的标准版本不允许包含换行符的字符串文字。 IIRC,某些版本的 GCC(不是标准)确实允许这样做;他们是否仍然这样做我不知道。
        • @Ira 是否标准允许不是问题,而是编译器如何遵守标准。我可以想到一个yacc 规则来检查这个语法QUOTE LETTERS QUOTE,或者一个lex 正则表达式来完成\"[a-z]*\" 的工作(当然是简化版)。现在,这是 lex 还是语法错误,取决于实现?还是有一些我们都同意的默认值?
        • @Dr Beco:abc 无法通过词法分析器,因此您无法使用解析器规则在语法上检查这一点。唯一可以/将反对的是词法分析器。你会发现描述字符串的词法规则比你写的要复杂得多,当你包括转义、双宽字符和所有其他进入真正编译器的怪异时,但是是的,大多数正则表达式会坚持每端的引号,不存在,因此字符序列无法识别--> 词法错误。
        猜你喜欢
        • 1970-01-01
        • 2019-03-04
        • 2016-11-19
        • 2012-09-13
        • 1970-01-01
        • 2011-07-08
        • 2018-03-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多