ANTLR v. 3-Использование синтаксического предиката для lookahead
Все еще учимся Правильно Использовать ANTLR... Вот в чем моя проблема.
Предположим, что у вас есть (подмножество) грамматики UML и лексера/синтаксического анализатора ANTLR со следующими правилами:
// Parser Rules
model
: 'MODEL' IDENTIFIER list_dec
;
list_dec
: declaration*
;
declaration
: class_dec ';'
| association ';'
| generalization ';'
| aggregation ';'
;
class_dec
: 'CLASS' IDENTIFIER class_content
;
...
association
: 'RELATION' IDENTIFIER 'ROLES' two_roles
;
two_roles
: role ',' role
;
role
: 'CLASS' IDENTIFIER multiplicity
;
...
Я хотел бы, чтобы правило 'role' разрешало маркер идентификатора только в том случае, если он соответствует существующему идентификатору класса. Другими словами, если вам дан входной файл и вы запускаете в нем лексер/синтаксический анализатор, то все классы, на которые ссылаются (например, идентификатор в правиле ассоциации), должны существовать. Проблема в том, что класс может не существовать (пока) во время выполнения (он может быть объявлен в любом месте файла). Каков наилучший подход к этому ?
Заранее благодарю...
1 ответ:
Это, вероятно, лучше всего сделать после разбора. Синтаксический анализатор создает для вас какое-то дерево, а затем вы проходите по дереву и собираете информацию об объявленных классах, а затем проходите по нему еще раз, чтобы проверить дерево/Правило
role
.Конечно, некоторые вещи можно было бы сделать с помощью специального кода:
grammar G; options { ... } @parser::members { java.util.Set<String> declaredClasses = new java.util.HashSet<String>(); } model : 'MODEL' IDENTIFIER list_dec ; ... class_dec : 'CLASS' id=IDENTIFIER class_content { declaredClasses.add($id.text); } ; ... role : 'CLASS' id=IDENTIFIER multiplicity { if(!declaredClasses.contains($id.text)) { // warning or exception in here } } ; ...
EDIT
Или с помощью пользовательских методов:
@parser::members { java.util.Set<String> declaredClasses = new java.util.HashSet<String>(); void addClass(String id) { boolean added = declaredClasses.add(id); if(!added) { // 'id' was already present, do something, perhaps? } } void checkClass(String id) { if(!declaredClasses.contains(id)) { // exception, error or warning? } } } ... class_dec : 'CLASS' id=IDENTIFIER class_content {addClass($id.text);} ; role : 'CLASS' id=IDENTIFIER multiplicity {checkClass($id.text);} ;