擴展iQuery使其支持多種編程語言(四) – 兼編譯器的語法錯誤處理簡介

擴展iQuery使其支持多種編程語言(四) – 兼編譯器的語法錯誤處理簡介css

iQuery是一個開源的自動化測試框架項目,有興趣的朋友能夠在這裏下載:https://github.com/vowei/iQuery/downloadshtml

源碼位置:https://github.com/vowei/iQueryjava

相關的使用文檔,請參看:git

開源類庫iQuery Android版使用說明
類jQuery selector的控件查詢iQuery開源類庫介紹
開源手機自動化測試框架iQuery入門教程(一)
開源手機自動化測試框架iQuery入門教程(二)
開源手機自動化測試框架iQuery入門教程(三)
上一篇文章中,簡單介紹了iQuery解釋器的語義分析部分。github

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):
編程語言

 1: public String getErrorMessage(RecognitionException e,
 2:                                     String[] tokenNames)

當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 )。測試

 1: if (e instanceof MismatchedTokenException) {
 2:             MismatchedTokenException mte = (MismatchedTokenException) e;
 3:             String tokenName = "<unknown>";
 4:             if (mte.expecting == Token.EOF) {
 5:                 tokenName = "EOF";
 6:             } else if (tokenNames != null) {
 7:                 tokenName = tokenNames[mte.expecting];
 8:             } else {
 9:                 tokenName = new String(new char[] {(char)mte.expecting});
 10:             }
 11:  
 12:             if ( e.token != null ) {
 13:                 msg = String.format("%1$s: 沒有關閉的語句,指望%2$s,當前碰到的是'%3$s'!",
 14:                         hdr, tokenName, recognizer.getTokenErrorDisplay(e.token));
 15:             } else {
 16:                 msg = String.format("%1$s: 沒有關閉的語句,指望%2$s!",
 17:                         hdr, tokenName);
 18:             }
 19:         }

JavaScript版本里getErrorMessage函數的聲明相似,處理方式也相似參考代碼:https://github.com/vowei/iQuery/blob/master/iOS/lib/iQuery.ghttps://github.com/vowei/iQuery/blob/master/iOS/lib/error.js ):

 1: function onMismatchedTokenException(mte, tokenNames, recognizer) {
 2:     debug("onMismatchedTokenException");
 3:  
 4:     var tokenName = "<unknown>";
 5:     if (mte.expecting == org.antlr.runtime.Token.EOF) {
 6:         tokenName = "EOF";
 7:     } else if (tokenNames != null) {
 8:         tokenName = tokenNames[mte.expecting];
 9:     } else {
 10:         debug("[onMismatchedTokenException] - mte.expecting: " + mte.expecting);
 11:         tokenName = mte.expecting;
 12:     }
 13:  
 14:     if (mte.token != null) {
 15:         return "沒有關閉的語句,指望" + tokenName + ",當前碰到的是'" + recognizer.getTokenErrorDisplay(mte.token) + "'!";
 16:     } else if (tokenName != undefined) {
 17:         return "沒有關閉的語句,指望" + tokenName + "!";
 18:     } else {
 19:         return "沒有關閉的語句!";
 20:     }
 21: }

因爲詞法分析器(Lexer)和語法分析器(Parser)是兩個類,並且詞法和語法分析過程都有可能發生錯誤,所以須要分別在兩個分析器裏定義getErrorMessage函數,添加的方式很簡單,在antlr的語法定義.g文件裏,添加在@lexer::members和@parser::members代碼塊裏便可,例以下面是JavaScript版本的聲明方式:

 1: @lexer::members {
 2: _errors = [];
 3: this.getErrorMessage = function(e, tokenNames)
 4: {
 5:     var error = getErrorsHelper(e, null, tokenNames, this);
 6:  
 7:     if ( _errors != undefined && _errors != null ) {
 8:         _errors.push(error);
 9:     }
 10: 
 11:     return error;
 12: }
 13: }
 14:  
 15: @parser::members {
 16: _errors = [];
 17: this.getErrorMessage = function(e, tokenNames)
 18: {
 19:     var error = getErrorsHelper(e, this.input, tokenNames, this);
 20:  
 21:     if ( _errors != undefined && _errors != null ) {
 22:         _errors.push(error);
 23:     }
 24: 
 25:     return error;
 26: }
 27: }
相關文章
相關標籤/搜索