作者reader (读者)
看板CSSE
标题[心得] 没效率的源码分析法
时间Fri Dec 31 18:34:24 2004
我一直觉得 strtok() 很难用, lex 更难用。但不知道为什麽,
人人都说要这样子做,好像只有这麽用才是正确的。
可是我怎麽都觉得是因为教科书上这麽教,而且非本科系的人,
往往都不会用,所以在某种优越感之下,就完全不讨论怎样做才
是真的好用,而一面倒地教别人要这麽做,甚或嘲笑别人没水准
没知识。从十几年前到现在,网路上的讨论区,都是这个样子。
实际上,明明就有更方便的做法,虽然很没效率,然而不是每个
时候都是效率第一的,何况实测上速度也未必比较慢。
简单来说,就是正视源码文件的结构。
基本上,现代的程式语言,大约就是由以下的结构:
(以 C 为例)
1. break : ;
2. quote : "..." '...'
3. block : { ... } ( ... ) [ ... ]
4. remark : /* ... */
5. notice : // ... \n, # ... \n
6. keyword : if, else, int, ...
7. identifier : [a-zA-Z_][0-9a-zA-Z_]*
8. operator : +-*/= ...
於是,只要照着分析即可,其中最重要的就是 block 的处理,例如
这样的源码:
#include <stdio.h>
int main() {
printf("Hello, world!\n");
return 0;
}
得到的结果应该是这样:
(notice, "#include <stdio.h>")
(keyword, "int")
(identifier, "main")
(block, "()")
(block, "{\n\n printf(\"Hello, world!\n\");\nreturn0;\n\n}")
如果还需要再分析 main() 的 code, 就会得到:
(identifier, "printf")
(block, "(\"Hello, world!\n\")")
(break, ";")
(keyword, "return")
(value, "0")
(break, ";")
另一种做法是这样:
// block_1: {}
// block_2: ()
// quote_1: ""
block[0] = {
{notice, "#include <stdio.h>"},
{keyword, "int"},
{identifier, "main"},
{block_2, ""},
{block_1, 1} // reference to block[1]
};
block[1] = {
{text, "printf"}, // not analysis yet
{block_2, 2} // reference to block[2]
{text, ";\nreturn 0;"} // not analysis yet
};
block[2] = {
{quote_1, "Hello, world!\n"}
};
因为要得到 block, 就需要检查其中的 sub-block 和 quote,
不想重复检查的话,则可以记录下来。当然这可以设成参数,
看是要记录多少层次的 block.
无论如何,第一层分析就可以得到 global 的资料,如果想要
列出全部的函数定义,就只要寻找 (keyword, [keyword...,]
identifier, block, block) 序列即可。
如果要更仔细的话, keyword, operator 或其他东西,都还可以
再分类。
总之,顺着源码的结构来读取资料,无论如何都比起用 token
一个一个来处理方便许多,一个 block 就可以跨过中间的许多
枝枝节节,而让我们直接处理同一层级的资料。
这只需要写出一个通用模组,往後就很方便了。
也就是说,不要把源码分析当做是一个特别的东西,非得利用
lex 不可,该怎麽写程式就怎麽写程式。
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 61.222.173.26
1F:→ maxisam:不知道版主是在业界还是学术界 68.89.158.5 01/01