我正在研究的DSL允许用户定义“完整文本替换”变量。在解析代码时,我们需要查找变量的值并从该代码再次开始解析。
替换可以非常简单(单个常量)或整个语句或代码块。 这是一个模拟语法,我希望能说明我的观点。
grammar a;
entry
: (set_variable
| print_line)*
;
set_variable
: 'SET' ID '=' STRING_CONSTANT ';'
;
print_line
: 'PRINT' ID ';'
;
STRING_CONSTANT: '\'' ('\'\'' | ~('\''))* '\'' ;
ID: [a-z][a-zA-Z0-9_]* ;
VARIABLE: '&' ID;
BLANK: [ \t\n\r]+ -> channel(HIDDEN) ;
然后连续执行的以下语句应该有效;
SET foo = 'Hello world!';
PRINT foo;
SET bar = 'foo;'
PRINT &bar // should be interpreted as 'PRINT foo;'
SET baz = 'PRINT foo; PRINT'; // one complete statement and one incomplete statement
&baz foo; // should be interpreted as 'PRINT foo; PRINT foo;'
任何时候&发现变量令牌后,我们立即切换到解释该变量的值。如上所述,这可能意味着您以无效的方式设置代码,这些半语句只有在值恰到好处时才会完成。可以在文本中的任何位置重新定义变量。
严格地说,当前的语言定义不会在彼此内部禁止嵌套和变换,但当前的解析不会处理这个问题,如果不允许,我不会感到沮丧。
目前我正在使用访客建立翻译,但是我坚持这个。
如何构建一个词法分析器/解析器/解释器,这将允许我这样做?谢谢你的帮助!
答案 0 :(得分:0)
所以我找到了解决这个问题的方法。我认为它可能会更好 - 因为它可能会进行大量的数组复制 - 但至少它现在可以正常工作。
编辑:之前我错了,我的解决方案会消耗任何&它找到了,包括那些在有效位置,如内部字符串常量。这似乎是一个更好的解决方案:首先,我扩展了InputStream,以便能够在& amp;遇到了。不幸的是,这涉及到复制数组,我将来可以解决这个问题:
<强> 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;
}
}
}
其次,我扩展了Lexer,以便在遇到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
,所以这会使维护变得更加困难,但它现在可以工作。
答案 1 :(得分:-1)
处理您的要求的标准模式是实现符号表。最简单的形式是关键:价值存储。在访问者中,添加遇到的var声明,并在遇到var引用时读出值。
如上所述,您的DSL未对声明的变量定义范围要求。如果你确实需要范围变量,那么使用一堆key:value存储,在范围输入和推出时推送和弹出。
请参阅此相关StackOverflow answer.
另外,由于您的字符串可能包含命令,因此您可以简单地将内容解析为初始解析的一部分。也就是说,使用包含完整有效内容集的规则扩展语法:
set_variable
: 'SET' ID '=' stringLiteral ';'
;
stringLiteral:
Quote Quote? (
( set_variable
| print_line
| VARIABLE
| ID
)
| STRING_CONSTANT // redefine without the quotes
)
Quote
;