我编写了一个库来将字符串与一组模式进行匹配,现在我可以轻松地将词法扫描器嵌入到 C 程序中。

我知道有许多成熟的工具可用于创建词法扫描器(lex 和 re2c,仅举出想到的前两个) 这个问题与词法分析器无关,而是关于“扩展”C 语法 的最佳方法。词法分析器示例只是一般问题的具体案例。

我可以看到两种可能的解决方案:

  • 编写一个预处理器 将带有嵌入词法分析器的源文件转换为普通的 C 文件,并且可能转换为要在编译中使用的一组其他文件。
  • 编写一组 C 宏 以更易读的形式表示词法分析器。

  • 我已经完成了这两项工作,但问题是:“根据以下标准,您认为哪种做法更好?”
  • 可读性。词法分析器逻辑应该清晰易懂
  • 可维护性。查找和修复错误不应该是一场噩梦!
  • 构建过程中的干扰。预处理器在构建过程中需要一个额外的步骤,预处理器必须在路径等中。

  • 换句话说,如果您必须维护或编写使用这两种方法之一的软件,那么哪种方法会让您失望?

    作为一个例子,这是一个用于以下问题的词法分析器:
  • 对所有数字求和(可以是十进制形式,包括指数,如 1.3E-4.2)
  • 跳过字符串(双引号和单引号)
  • 跳过列表(类似于 LISP 列表: (3 4 (0 1)() 3) )
  • 在遇到单词 end(大小写无关)或缓冲区末尾时停止

  • 在两种风格中。
    /**** SCANNER STYLE 1 (preprocessor) ****/
    #include "pmx.h"
    
    t = buffer
    
    while (*t) {
      switch pmx(t) { /* the preprocessor will handle this */
        case "&q" :         /* skip strings */
          break;
    
        case "&f<?=eE>&F" : /* sum numbers */
          sum += atof(pmx(Start,0));
          break;
    
        case "&b()":        /* skip lists */
          break;
    
        case "&iend" :      /* stop processing */
          t = "";
          break;
    
        case "<.>":         /* skip a char and proceed */
          break;
      }
    }
    
    /**** SCANNER STYLE 2 (macros) ****/
    #include "pmx.h"
    /* There can be up to 128 tokens per scanner with id x80 to xFF */
    #define TOK_STRING x81
    #define TOK_NUMBER x82
    #define TOK_LIST   x83
    #define TOK_END    x84
    #define TOK_CHAR   x85
    
    pmxScanner(   /* pmxScanner() is a pretty complex macro */
       buffer
     ,
       pmxTokSet("&q"         , TOK_STRING)
       pmxTokSet("&f<?=eE>&F" , TOK_NUMBER)
       pmxTokSet("&b()"       , TOK_LIST)
       pmxTokSet("&iend"      , TOK_END)
       pmxTokSet("<.>"        , TOK_CHAR)
     ,
       pmxTokCase(TOK_STRING) :   /* skip strings */
         continue;
    
       pmxTokCase(TOK_NUMBER) :   /* sum numbers */
         sum += atof(pmxTokStart(0));
         continue;
    
       pmxTokCase(TOK_LIST):      /* skip lists */
         continue;
    
       pmxTokCase(TOK_END) :      /* stop processing */
         break;
    
       pmxTokCase(TOK_CHAR) :     /* skip a char and proceed */
         continue;
    );
    

    如果有人对当前的实现感兴趣,代码在这里: http://sites.google.com/site/clibutl

    最佳答案

    预处理器将提供更健壮和通用的解决方案。另一方面,当示例关键字/ token 空间很小时,宏可以快速启动,提供良好的概念证明并且很容易。在某一点之后,使用宏扩展/包括新功能可能会变得乏味。我会说启动宏以开始,然后将它们转换为您的预处理器命令。

    另外,如果可能的话,尽量使用通用预处理器而不是自己编写。



    是的。但是,您编写的任何解决方案也是如此:) -- 而且您必须维护它。您命名的大多数程序都有可用的 Windows 端口(例如,请参阅 m4 for windows )。使用这种解决方案的优点是您可以节省大量时间。当然,缺点是您可能必须加快源代码的速度,如果出现奇怪的错误(尽管维护这些的人非常有帮助,并且肯定会确保您获得一切帮助)。

    再说一次,是的,我更喜欢打包的解决方案而不是我自己的解决方案。

    关于C 风格 : Macros or preprocessor?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/692382/

    10-12 02:38