编译原理 词法分析:介绍,KMP 匹配算法
Posted 小键233
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了编译原理 词法分析:介绍,KMP 匹配算法相关的知识,希望对你有一定的参考价值。
词法分析,Lexcical analysis, 是将编程语言从字符转变成一个个token的分析器。 这也通常是一个编译器的开始阶段。
token 也称之为词素。
举个例子, 下面这段程序转变成token的输出如下:
printf("Total is %d\\n,", score);
token 的输出和匹配上的内容顺序:
printf 函数名字
( 符号
"Total is %d\\n" 字符常量
, 符号
score id,指向符号表来查询实际的内容
) 符号
; 符号
Token, Pattern, Lexeme 的区别
Token 包含一个名字和可选的属性。它是一类符号抽象的表示。 比如 token literal 表示字符常量, 那么上面的 "Total is %d\\n"
就是一个token literal。 那其他的字符常量也是这个token。
Pattern 指的是一种可以推导得到lexemes 的可能是形式。 比如对数字的pattern 是:
digit -> 0|1|...|9
digits -> digit digit*
*
表示的是可以匹配0 个或者多个
Lexeme 是一些字符的组合, 表示的是token的某个实例。 比如 "Total is %d\\n"
就是一个字符常量的词素, 它说明了这是一个literal 的token, 同时给出了它的值(也就是它的内容)
正则表达式
正则表达式是用来识别token的强有力的工具。通过推导的形式,可以定义出正则表达式的内容。 比如上面的举例说明的pattern。
* 表示可以匹配0 个或者多个
| 表示或者匹配
+ 表示至少匹配一个
C 语言中定义一个变量名 id 的规则式以下滑线或者字母开头的,后面是下滑线、字母和数字的组合。使用正则定义这个pattern 可以是:
letter_ -> A | B|...|Z|a|b| ... |z
digit -> 0 | 1 | ... | 9
id -> letter_ (letter_ | digit )*
(在这里只是使用了一些简单的正则表达式的规则来达到目的, 正则表达式本身是很强大的工具, 还包含了其他的规则)
LEX
Lex 是一个产生语法分析器的程序。 通过正则定义和一些其他的规则,可以直接生成一个对应的c 语言程序的词法分析器。
一些资料:
Lex与YACC详解
Lex Yacc规则格式
KMP 字符串匹配算法
最后附上一个字符串匹配算法的内容。KMP 算法。
一个暴力思想的字符串匹配是一一比对。 比如字符串 ababaa,在字符串 abababaab 中搜索,那么最常见的方式就是, 一一比对 ababaa 的前缀, 直到遇到某个前缀不匹配了, 那么就往跳一个字符, 重新开始比对ababaa 的前缀。 假如采用这样的算法, 最差的时间复杂度可能达到 O(M * N), M 是被搜索的字符串的长度,N 是字符串的长度。
KMP 算法的核心思想是, 如果在某一个匹配失败了,那么怎么避免之前已经比对过的前缀, 重新再进行一次比对呢。
对 ababaa 来说, 对于不同长度的前缀, 如果匹配失败了, 那么每次可以从哪个位置重新开始的说明如下:
a --> ababaa
ab --> ababaa
aba --> a babaa
abab --> ab abaa
ababa --> aba baa
以最后一个case 举例,假如匹配字符的过程如下:
abababaa
1: ababaa -> b != a , 进入下一个匹配 2
2: ababaa
所以我们可以建立一个表格来表明如果匹配到某个阶段失败以后, 可以往哪个下标开始匹配 :
| 已经匹配的前缀的长度 | 1 | 2 | 3 | 4 | 5 | 6 |
| -------- | -----: | -----: | -----: | :----: |
| f(s) | 0 | 0 | 1 | 2 | 3 | 1
建立表格的方法是,对于已经匹配了的前缀,可以从后面往前匹配的和从前面往后面匹配的最长的一样的字符的个数, 比如abab, 这个长度是2.
建立这个表格以后,在字符串匹配中,如果在某个位置不匹配这个字符串, 我们可以通过表格来确定下一次匹配开始的位置。
有了这个基础, 在下一篇中, 我们介绍确定性有限自动机(DFA) 和不确定性有限自动机(NFA),从正则表达式转换成自动机的方法。
以上是关于编译原理 词法分析:介绍,KMP 匹配算法的主要内容,如果未能解决你的问题,请参考以下文章