gpt4 book ai didi

parsing - 使用 ANTLR 进行 DSL 的代码替换

转载 作者:行者123 更新时间:2023-12-03 00:11:43 24 4
gpt4 key购买 nike

我正在开发的 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;'

只要发现 & 变量标记,我们就会立即转而解释该变量的值。如上所述,这可能意味着您以无效的方式设置代码,其中充满了仅在值正确时才完成的半语句。可以在文本中的任何位置重新定义变量。

严格来说,当前的语言定义不允许相互嵌套 &var,但当前的解析无法处理此问题,如果不允许,我也不会感到不安。

目前我正在使用访问者构建一个解释器,但我一直坚持这个。

如何构建一个词法分析器/解析器/解释器来允许我执行此操作?感谢您的帮助!

最佳答案

所以我找到了解决该问题的方法。我认为它可能会更好 - 因为它可能会进行大量数组复制 - 但至少现在它可以工作。

编辑:我之前错了,我的解决方案将消耗它找到的任何 & ,包括有效位置中的内容,例如字符串常量内的内容。这似乎是一个更好的解决方案:

首先,我扩展了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;
}
...
...

不幸的是,此方法是最终,因此这将使维护变得更加困难,但目前它有效。

关于parsing - 使用 ANTLR 进行 DSL 的代码替换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22370956/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com