Обратите внимание, я немного знаю C и не имею опыта работы с C для ANTLR, но код Java из моих примеров не должен быть слишком сложным для перезаписи на C.
Вы можете сделать это, переопределив метод emit(Token)
из базового класса Lexer
и отслеживая последние Token
ваших процессов лексера:
private Token last;
@Override
public void emit(Token token) {
last = token;
super.emit(token);
}
Чтобы включить это в свой лексер,добавьте его в свою грамматику между следующими словами:
@lexer::members {
// your code here
}
Теперь вы должны поставить Other
rule перед вашим ExtraData
правилом и поставить стробированный семантический предикат перед правилом Other
, которое проверяет, был ли токен last
токеном ExtraData
:
Other
: {behind(ExtraData)}?=> ~'-' (~' ')*
;
, где метод behind(int)
- это пользовательский метод в разделе @lexer::members { ... }
:
protected boolean behind(int tokenType) {
return last != null && last.getType() == tokenType;
}
, что приведет к совпадению токена Other
only , если последний токен был ExtraData
.
Небольшая демонстрационная грамматика всего этого:
grammar LookBehind;
@lexer::members {
private Token last;
@Override
public void emit(Token token) {
last = token;
super.emit(token);
}
protected boolean behind(int tokenType) {
return last != null && last.getType() == tokenType;
}
}
parse
: token+ EOF
;
token
: Argument {System.out.println("Argument :: "+$Argument.text);}
| Other {System.out.println("Other :: "+$Other.text);}
| ExtraData {System.out.println("ExtraData :: "+$ExtraData.text);}
;
Argument
: '-'+ (~('-' | '#' | ' '))+
;
Other
: {behind(ExtraData)}?=> ~('-' | ' ') (~' ')*
;
ExtraData
: '#' (~'#')* '#'
;
Space
: (' ' | '\t' | '\r' | '\n') {skip();}
;
и основной класс для его проверки:
import org.antlr.runtime.*;
public class Main {
public static void main(String[] args) throws Exception {
String source = "-argument -argument#with hashed data# #plainhashedData#";
ANTLRStringStream in = new ANTLRStringStream(source);
LookBehindLexer lexer = new LookBehindLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
LookBehindParser parser = new LookBehindParser(tokens);
parser.parse();
}
}
Сначала сгенерируйте парсер и лексер из грамматики:
java -cp antlr-3.2.jar org.antlr.Tool LookBehind.g
, затем скомпилируйте все .java
файлы:
javac -cp antlr-3.2.jar *.java
и, наконец, запустите основной класс:
java -cp .:antlr-3.2.jar Main
(в Windows: java -cp .;antlr-3.2.jar Main
)
, который затем выдаст следующий вывод:
Argument :: -argument
Argument :: -argument
ExtraData :: #with hashed data#
Other :: #plainhashedData#
РЕДАКТИРОВАТЬ
Как вы (Билли) упомянули в своем комментарии, вC вы не можете переопределить методы.Вы также можете установить логический флаг в предложении @after{ ... }
каждого правила лексера, чтобы отслеживать, когда последний токен является ExtraData
, и использовать этот флаг в своем предикате:
grammar LookBehind;
@lexer::members {
private boolean lastExtraData = false;
}
parse
: token+ EOF
;
token
: Argument {System.out.println("Argument :: "+$Argument.text);}
| Other {System.out.println("Other :: "+$Other.text);}
| ExtraData {System.out.println("ExtraData :: "+$ExtraData.text);}
;
Argument
@after{lastExtraData = false;}
: '-'+ (~('-' | '#' | ' '))+
;
Other
@after{lastExtraData = false;}
: {lastExtraData}?=> ~('-' | ' ') (~' ')*
;
ExtraData
@after{lastExtraData = true;}
: '#' (~'#')* '#'
;
Space
: (' ' | '\t' | '\r' | '\n') {skip();}
;
Хотя этонемного хак: в каждом правиле лексера вы должны будете установить флаг.
Вы также можете отправить вопрос в список рассылки ANTLR : помимо многих экспертов ANTLR, человек, поддерживающий там частоту выполнения C-ANTLR.
Удачи!