您的位置:首页 > 产品设计 > UI/UE

扩展iQuery使其支持多种编程语言(四) – 兼编译器的语法错误处理简介

2012-09-28 16:50 381 查看
扩展iQuery使其支持多种编程语言(四)–兼编译器的语法错误处理简介

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

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

相关的使用文档,请参看:

开源类库iQueryAndroid版使用说明
类jQueryselector的控件查询iQuery开源类库介绍
开源手机自动化测试框架iQuery入门教程(一)
开源手机自动化测试框架iQuery入门教程(二)
开源手机自动化测试框架iQuery入门教程(三)
上一篇文章中,简单介绍了iQuery解释器的语义分析部分。

ANTLR已经自带了一些对词法和语法错误的处理功能,当一行语句出现语法错误时,ANTLR会尽量跳过出错的一行代码,恢复编译和解释功能,通过一个回调函数,我们可以向最终用户显示更细致的错误提示。

一般来说,好的错误提示应该有以下几个性质:
1.   需要指明错误的行号和列号,以便用户快速在源代码中定位出错的那一行代码,这个功能ANTLR会在调用我们的回调函数时传入这些信息。
2.   需要指明错误原因,例如“不匹配的字符”这样的错误信息显然没有“第1行,第25列:没有关闭的语句,期望']',当前碰到的是''<EOF>''!”这样的信息更明确。
3.   需要指明导致出错的文字,例如在编程中,针对使用一个未定义的变量的编程错误,当然需要在错误信息里指出这个未定义的变量名。
4.   最好给出修复错误的建议。

在ANTLR里,可以在代码里定义一个getErrorMessage函数,以便ANTLR回调。在Java版本中,getErrorMessage函数的声明形式如下(代码实现在:https://github.com/vowei/iQuery/blob/master/java/iquery/iquery-core/src/main/java/cc/iqa/iquery/iQuery.g):
publicStringgetErrorMessage(RecognitionExceptione,


[code]String[]tokenNames)
[/code]

.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

当ANTLR碰到词法或者语法错误时,会抛出一个基类为RecognitionException的异常,并传递给getErrorMessage函数,而第二个参数tokenNames就是导致词法/语法错误时的源码符号,getErrorMessage函数的返回值就是细化后的错误消息。

ANTLR针对不同的词/语法错误会生成不同的RecognitionException的继承类,在这些继承类里,分别定义了一些对细化错误消息有帮助的属性。下面代码是一个细化错误消息的例子,其中MismatchedTokenException表示一个未匹配的语法,在MismatchedTokenException的对象里,可以通过expecting字段获取期望的词法符号(原始代码位置是:https://github.com/vowei/iQuery/blob/master/java/iquery/iquery-core/src/main/java/cc/iqa/iquery/ErrorMessageHelper.java)。

if(einstanceofMismatchedTokenException){


[code]MismatchedTokenExceptionmte=(MismatchedTokenException)e;

StringtokenName="<unknown>";


if(mte.expecting==Token.EOF){


tokenName="EOF";


}elseif(tokenNames!=null){


tokenName=tokenNames[mte.expecting];


}else{


tokenName=newString(newchar[]{(char)mte.expecting});


}


 


if(e.token!=null){


msg=String.format("%1$s:没有关闭的语句,期望%2$s,当前碰到的是'%3$s'!",


hdr,tokenName,recognizer.getTokenErrorDisplay(e.token));


}else{


msg=String.format("%1$s:没有关闭的语句,期望%2$s!",


hdr,tokenName);


}


}

[/code]

.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

JavaScript版本里getErrorMessage函数的声明类似,处理方式也类似参考代码:https://github.com/vowei/iQuery/blob/master/iOS/lib/iQuery.g和https://github.com/vowei/iQuery/blob/master/iOS/lib/error.js):

functiononMismatchedTokenException(mte,tokenNames,recognizer){


[code]debug("onMismatchedTokenException");

 


vartokenName="<unknown>";


if(mte.expecting==org.antlr.runtime.Token.EOF){


tokenName="EOF";


}elseif(tokenNames!=null){


tokenName=tokenNames[mte.expecting];


}else{


debug("[onMismatchedTokenException]-mte.expecting:"+mte.expecting);


tokenName=mte.expecting;


}


 


if(mte.token!=null){


return"没有关闭的语句,期望"+tokenName+",当前碰到的是'"+recognizer.getTokenErrorDisplay(mte.token)+"'!";


}elseif(tokenName!=undefined){


return"没有关闭的语句,期望"+tokenName+"!";


}else{


return"没有关闭的语句!";


}


}

[/code]

.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

由于词法分析器(Lexer)和语法分析器(Parser)是两个类,而且词法和语法分析过程都有可能发生错误,因此需要分别在两个分析器里定义getErrorMessage函数,添加的方式很简单,在antlr的语法定义.g文件里,添加在@lexer::members和@parser::members代码块里即可,例如下面是JavaScript版本的声明方式:

@lexer::members{


[code]_errors=[];

this.getErrorMessage=function(e,tokenNames)


{


varerror=getErrorsHelper(e,null,tokenNames,this);


 


if(_errors!=undefined&&_errors!=null){


_errors.push(error);


}




returnerror;


}


}


 


@parser::members{


_errors=[];


this.getErrorMessage=function(e,tokenNames)


{


varerror=getErrorsHelper(e,this.input,tokenNames,this);


 


if(_errors!=undefined&&_errors!=null){


_errors.push(error);


}




returnerror;


}


}

[/code]

.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐