代码之家  ›  专栏  ›  技术社区  ›  Tim Cooper

解析:加载到内存或使用流

  •  0
  • Tim Cooper  · 技术社区  · 14 年前

    我正在编写一个小解析器,我想知道不同方法加载要解析的数据的优缺点。我想到的两种方法是:

    • 将文件的内容加载到字符串中,然后分析该字符串(在数组位置访问该字符)
    • 解析为读取文件流( fgetc )

    前者允许我有两个功能:一个用于 parse_from_file parse_from_string 但是我相信这个模式会占用更多的内存。后者不会有使用更多内存的缺点。

    有人对这件事有什么建议吗?

    3 回复  |  直到 14 年前
        1
  •  2
  •   nategoose    14 年前

    读取整个文件或内存映射会更快,但如果您希望您的语言能够 #include 其他文件,因为这些文件将被内存映射或读取到内存中。

    stdio函数可以很好地工作,因为它们通常尝试为您缓冲数据,但它们也是通用的,因此它们还尝试查找不同于从头到尾读取文件的使用模式,但这不应该是太多的开销。

    一个好的平衡是有一个大的循环缓冲区(x*2*4096是一个好的大小),您用文件数据加载它,然后让标记器读取它。每当一个块的数据值被传递给记号赋予器(并且您知道它不会被推回)时,您可以用文件中的新数据重新填充该块,并更新一些缓冲区位置信息。

    另一个需要考虑的问题是,如果有任何机会,记号赋予器将需要能够被用来从管道或直接输入某些文本的人那里读取。在这些情况下,如果不在文件末尾,您的读操作返回的数据可能比您要求的要少,而且我上面提到的缓冲方法会变得更复杂。stdio缓冲对于这个很好,因为它可以很容易地切换到/从线路或块缓冲(或没有缓冲)。

    使用GNU Fast-Lex(flex,但不是Adobe Flash)或类似工具可以极大地缓解所有这些问题。您应该研究如何使用它为记号赋予器(词汇分析)生成C代码。

    无论你做什么,你都应该试着去做,这样你的代码就可以很容易地被修改为使用不同形式的下一个字符peek和consume函数,这样如果你改变主意,你就不必重新开始。

        2
  •  0
  •   Gilles 'SO- stop being evil'    14 年前

    考虑使用lex(如果语法的语言与其功能匹配,也可能使用yacc)。lex将为您处理词汇分析的所有细节,并生成有效的代码。您可能可以将内存占用量减少几个字节,但您希望为此花费多少精力?

        3
  •  0
  •   Jens Gustedt    14 年前

    在POSIX系统上最有效的方法可能不是这两种方法(如果您愿意,也可以是第一种方法的变体):只需以只读方式映射文件 mmap ,然后分析它。现代系统的效率相当高,因为它们在检测到流访问等时会预取数据,您的程序解析同一文件的多个实例将获得相同的物理内存页等,我认为接口处理起来相对简单。