Antlr будет показывать ноль предупреждений при компиляции этой грамматики, но при вызове из входного файла он будет повторяться вечно в org.antlr.v4.runtime.atn.LexerATNSimulator.closure
.Любая идея, как создать грамматики синтаксического анализа макросов, которые должны работать на лексерах с любыми символами, кроме специальных?
Лексер:
lexer grammar e8pp_lexer;
NEWLINE: '\r' '\n' | '\n' | '\r';
CONTENT: NEWLINE CONTENTF+;
MACRODEF : NEWLINE 'MACRO' -> pushMode(MACRO_DEF);
MACROUSE : NEWLINE '`' -> mode (MACRO_USE);
fragment CONTENTF: .* ;
mode MACRO_DEF;
MACRONAME: LETTERS+ ;
MACROPARAMSTART: '[' ;
MACROPARAM: LETTERS+ ;
MACROSEP: ',';
MACROPARAMEND : ']' ;
MACRODEF_DEF : ':' -> pushMode(MACRO_MODE);
WHITESPACE: WS+ -> skip;
fragment WS: [ \t\r\n\u000C];
fragment LETTERS : [a-zA-Z];
mode MACRO_MODE;
NEWLINE_CONTENT: '\r' '\n' | '\n' | '\r';
ENDMACRO : NEWLINE_CONTENT 'ENDMACRO' -> popMode;
MACRO_CONTENT : NEWLINE_CONTENT MACRO_CONTENTF+;
fragment MACRO_CONTENTF: .* ;
mode MACRO_USE;
MU_ID: LETTERS+ ;
MU_PARAMSTART: '(';
MU_PARAM: LETTERS+;
MU_PARAMSEP : ',';
MU_PARAM_END: ')' -> popMode;
fragment MU_WS: [ \t\r\n\u000C];
fragment MU_LETTERS : [a-zA-Z];
Парсер
grammar e8pp_parser;
options { tokenVocab=e8pp_lexer; }
content:
contentElement+ EOF
;
contentElement:
data | macro
;
data:
contentData | macroUse
;
contentData:
CONTENT
;
macroUse:
MACROUSE macroId MU_PARAMSTART macroUseParams? MU_PARAM_END
;
macroId:
MU_ID
;
macroUseParams:
macroUseParam (MU_PARAMSEP macroUseParam)*
;
macroUseParam:
MU_PARAM
;
macro:
MACRODEF macroName
MACROPARAMSTART macroParams? MACROPARAMEND MACRODEF_DEF
macroBody?
NEWLINE_CONTENT ENDMACRO
;
macroName:
MACRONAME
;
macroParams:
macroParam (MACROSEP macroParam)*
;
macroParam:
MACROPARAM
;
macroBody:
MACRO_CONTENT+
;
Идеяявляется то, что это будет анализировать специальные блоки с макросами, возвращая все остальное как данные.Использование Java:
private ByteArrayInputStream parseMacros() throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
e8pp_lexer lexer = new e8pp_lexer(new ANTLRFileStream(srcFile.getAbsolutePath(), "utf-8"));
CommonTokenStream tokens = new CommonTokenStream(lexer);
e8pp_parserParser parser = new e8pp_parserParser(tokens);
ContentContext cc = parser.content();
Map<String, MacroDef> macros = new HashMap<String, MacroDef>();
for (ContentElementContext ctx : cc.contentElement()) {
parseMacroElement(ctx, bos, macros);
}
return new ByteArrayInputStream(bos.toByteArray());
}
private void parseMacroElement(ContentElementContext ctx, ByteArrayOutputStream bos, Map<String, MacroDef> macros) throws Exception {
if (ctx.data() != null) {
if (ctx.data().contentData() != null) {
bos.write(ctx.data().contentData().getText().getBytes(Charset.forName("UTF-8")));
} else {
resolveMacro(ctx.data().macroUse(), bos, macros);
}
} else {
defineMacro(ctx.macro(), macros);
}
}
private void defineMacro(MacroContext macro, Map<String, MacroDef> macros) {
String name = macro.macroName().getText();
if (macros.containsKey(name)) {
throw new AssemblyException("Duplicate macro name " + name);
}
MacroDef md = new MacroDef();
md.content = macro.macroBody().getText();
md.argNames = parseMacroArgs(macro.macroParams());
}
private List<String> parseMacroArgs(MacroParamsContext ctx) {
List<String> params = new ArrayList<String>();
for (MacroParamContext p : ctx.macroParam()) {
params.add(p.getText());
}
return params;
}
private void resolveMacro(MacroUseContext ctx, ByteArrayOutputStream bos, Map<String, MacroDef> macros) throws Exception {
String macroName = ctx.macroId().getText();
if (!macros.containsKey(macroName)) {
throw new AssemblyException("Unknown macro " + macroName);
}
MacroDef md = macros.get(macroName);
List<String> values = parseMacroParams(ctx.macroUseParams());
if (values.size() != md.argNames.size()) {
throw new AssemblyException("Bad macro param count for macro " + macroName);
}
String replaced = md.content;
for (int i=0; i<md.argNames.size(); i++) {
String paramName = md.argNames.get(i);
String replaceValue = values.get(i);
replaced = replaced.replaceAll(Pattern.quote(paramName), replaceValue);
}
bos.write(replaced.getBytes(Charset.forName("UTF-8")));
}
private List<String> parseMacroParams(MacroUseParamsContext ctx) {
List<String> params = new ArrayList<String>();
for (MacroUseParamContext p : ctx.macroUseParam()) {
params.add(p.getText());
}
return params;
}