所以我找到了一個解決方案。我認爲它可能會更好 - 因爲它可能做了很多陣列複製 - 但至少現在它工作。
編輯:我錯了,我的解決方案會消耗它發現的任何&,包括那些在有效的位置,如內部字符串常量。這似乎是一個更好的解決方案:
首先,我擴展了InputStream,以便它能夠在遇到&時重寫輸入蒸汽。這不幸的是涉及複製陣列,我可以在將來解決:
MacroInputStream。的java
package preprocessor;
import org.antlr.v4.runtime.ANTLRInputStream;
public class MacroInputStream extends ANTLRInputStream {
private HashMap<String, String> map;
public MacroInputStream(String s, HashMap<String, String> map) {
super(s);
this.map = map;
}
public void rewrite(int startIndex, int stopIndex, String replaceText) {
int length = stopIndex-startIndex+1;
char[] replData = replaceText.toCharArray();
if (replData.length == length) {
for (int i = 0; i < length; i++) data[startIndex+i] = replData[i];
} else {
char[] newData = new char[data.length+replData.length-length];
System.arraycopy(data, 0, newData, 0, startIndex);
System.arraycopy(replData, 0, newData, startIndex, replData.length);
System.arraycopy(data, stopIndex+1, newData, startIndex+replData.length, data.length-(stopIndex+1));
data = newData;
n = data.length;
}
}
}
其次,我延長詞法,使得在遇到VARIABLE令牌時,重寫上述方法被稱爲:
MacroGrammarLexer.java
package language;
import language.DSL_GrammarLexer;
import org.antlr.v4.runtime.Token;
import java.util.HashMap;
public class MacroGrammarLexer extends MacroGrammarLexer{
private HashMap<String, String> map;
public DSL_GrammarLexerPre(MacroInputStream input, HashMap<String, String> map) {
super(input);
this.map = map;
// TODO Auto-generated constructor stub
}
private MacroInputStream getInput() {
return (MacroInputStream) _input;
}
@Override
public Token nextToken() {
Token t = super.nextToken();
if (t.getType() == VARIABLE) {
System.out.println("Encountered token " + t.getText()+" ===> rewriting!!!");
getInput().rewrite(t.getStartIndex(), t.getStopIndex(),
map.get(t.getText().substring(1)));
getInput().seek(t.getStartIndex()); // reset input stream to previous
return super.nextToken();
}
return t;
}
}
最後,我修改生成的解析器以在解析時設置變量:
DSL_GrammarParser.java
...
...
HashMap<String, String> map; // same map as before, passed as a new argument.
...
...
public final SetContext set() throws RecognitionException {
SetContext _localctx = new SetContext(_ctx, getState());
enterRule(_localctx, 130, RULE_set);
try {
enterOuterAlt(_localctx, 1);
{
String vname = null; String vval = null; // set up variables
setState(1215); match(SET);
setState(1216); vname = variable_name().getText(); // set vname
setState(1217); match(EQUALS);
setState(1218); vval = string_constant().getText(); // set vval
System.out.println("Found SET " + vname +" = " + vval+";");
map.put(vname, vval);
}
}
catch (RecognitionException re) {
_localctx.exception = re;
_errHandler.reportError(this, re);
_errHandler.recover(this, re);
}
finally {
exitRule();
}
return _localctx;
}
...
...
不幸的是這種方法是final
所以這會使維護有點難度,但它適用於現在。
這是在你的語法中解釋一些討厭的詭計。在單個「條目」中可以出現「VARIABLE」的情況和限制?我的意思是,這是否允許:'SET a ='P'; SET b ='R'; SET c ='I'; SET d ='N'; SET e ='T'; SET f =''; SET g =''''; SET h ='ouch!'; SET i =''''; SET j =';'; &a&b&c&d&e&f&g&h&i&j'最終評估'PRINT'ouch!';'? –
是的,這確實是一個有效的陳述:/我懷疑有人以這種方式使用它,但應用程序已經存在很多年了,所以你永遠無法確定客戶做了什麼。當讀取字符來構成標記時,當前的實現只需切換到從變量值讀取,但我不知道ANTLR是否與ANTLR兼容。 – Trasvi
我不認爲在解析過程中有一種簡單的方法來插入代碼/標記。至少不提供所提供的API類(您當然可以實現自己的'TokenStream'並將其提供給解析器)。 –