代码改变世界

扩展iQuery使其支持多种编程语言(上) – 兼编译器的词法分析简介

2012-08-27 12:38  知平软件  阅读(2039)  评论(0编辑  收藏  举报

iQuery是一个开源的自动化测试框架项目,有兴趣的朋友可以在这里下载:
https://github.com/vowei/iQuery/downloads

源码位置:
https://github.com/vowei/iQuery

在上一篇文章中,简单介绍了扩展iQuery,使其支持尽可能多的自动化测试平台,但剩下对编程语言的扩展没有讲。

当前iQuery已经实现了Java和JavaScript版本,对其他语言的支持仍在讨论当中,感兴趣的网友可以参照本文的讲解自行扩展。

Antlr是可以生成很多编程语言的源文件,在其官网上,可以看到其支持:C、Java、JavaScript、C#、Object-C、Python、Perl等编程语言,详细情况请参阅:http://www.antlr.org/wiki/display/ANTLR3/Code+Generation+Targets。

我们知道,一般来说编译器或者解释器的流程都是:
词法解析 -> 语法解析 -> 语义分析 -> 代码优化 -> 生成(执行)代码

由于iQuery很简单,充其量就是一个DSL,所以在实现时,就直接将语义分析、代码优化跳过了,后面在讲解iQA这个编程语言的时候会聊到那些内容。

首先看一下iQuery的完整语法(其实可以把它当作一个广义的正则表达式对待):
https://github.com/vowei/iQuery/blob/master/iQuery.g

因为语法非常简单,就没有必要将词法和语法分到两个文件去写了,直接合并在一个文件里,但合并并不意味着词法分析和语法分析这两个过程就合并成一个步骤了,antlr在生成代码是,还是会生成两个类,iQueryLexer和iQueryParser两个类,也就是说还是两个步骤。

先看词法分析过程,词法分析过程实际上就是将输入的字符串归类,归类过程中可以剔除一些不用的字符(比如空格、注释之类的),方便在语法分析过程中处理。词法分析和语法分析这两个过程,跟打牌类似,比如八十分,抓牌把牌分类的时候就是词法分析,打牌时就是语法和语义分析,抓牌后打牌前有个垫底过程,相当于在词法分析时扔掉一些不用的字符:

DESCENDANT: '>>';
EQ: 'eq';
GT: 'gt';
LT: 'lt';
NOT: 'not';
CONTAINS: 'contains';
EMPTY: 'empty';
HAS: 'has';
PREV: 'prev';
NEXT: 'next';
SIBLINGS: 'siblings';
NTH_CHILD: 'nth-child';
PARENT: 'parent';
LAST_CHILD: 'last-child';
FIRST_CHILD: 'first-child';
FIRST: 'first';
LAST: 'last';
INTEGER: DIGIT+;
PERCENTAGE: ('+' | '-')? DIGIT+ ('.' DIGIT+)? '%';
FLOAT: ('+' | '-')? DIGIT+ ('.' DIGIT+)?;
fragment DIGIT: ('0' .. '9');
ELEMENT: ('a'..'z'|'A'..'Z'|'_')('a'..'z'|'A'..'Z'|'0'..'9'|'_'|'.')*;
ASTERISK: '*';
QUOTED_STRING: '\'' .+ '\''; 
NEWLINE: '\r'? '\n';
WS: (' ' | '\t') { skip(); };

所有大写字母组成的单词都是词法分析后生成的记号(Token),匹配的方式是依照简化的正则表达式方式匹配,而且匹配的优先级依照记号在文件里的出现顺序。比如说:

  • 例如’a’ .. ‘z’表示匹配从字符’a’到’z’的所有字符,“?”表示可选匹配,“|”表示取一(Or)匹配,“*”表示匹配零到多次等等,这个跟大家熟悉的正则表达式语法很接近,不详述。
  • 当词法分析器(这里是iQueryLexer – 由上表的代码生成)碰到“>>”这个字符串,就将其归类为记号DESCENDANT。
  • 在匹配字符串时,词法分析器按照各记号在文件里的顺序依次匹配,比如碰到“text”这个字符串,词法分析器从DESCENDANT开始匹配,由于在ELEMENT之前都没有匹配成功,最后将其归类为ELEMENT(因为其匹配)。
  • 如果所有记号都不匹配,那么词法分析器会扔出一个错误,antlr已经能够处理很多词法、语法方面的错误了,但是其还是留了一个接口,供我们精炼词法、语法方面的错误处理,错误处理会在后文讲到。
  • 如果在记号前加了一个fragment关键字,则说明该记号不是一个独立记号,会被其他记号引用,详情参看:INTEGER、PERCENTAGE、FLOAT和DIGIT。
  • 对于空格、注释等内容,使用skip()函数跳过,也就是说在语法分析阶段不会看到这些字符,详情参看:WS。
  • 最后,针对每一个记号,antlr都会生成一个函数,这个函数里的代码可以放入一些自定义的代码,这里由于iQuery很简单,因此没有扩展词法分析器,后面讲解iQA的实现方式时,会提到它,我以前有一篇文章也谈到了这一点:python等缩进语言的词法分析实现

今天先聊到这里,关于语法分析的内容,下一篇再讲。

本文由知平软件 施懿民编写,请关注我们的微博