Милош Силханек дал мне файл ANTLR, определяющий язык программирования Karel . Давайте теперь создадим редактор для этого.
- Прежде всего, давайте посмотрим на файл ANTLR:
grammar AntlrKarel; options { language = Java; output = AST; k=1; // character lookahead } tokens { KWD_STEP; KWD_LEFT; KWD_RIGHT; KWD_PUT; KWD_PICK; KWD_STOP; KWD_IF; KWD_WHILE; KWD_REPEAT; KWD_ELSE; KWD_END; KWD_TIMES; KWD_DEFINE; KWD_AS; KWD_IS; KWD_NOT; KWD_WALL; KWD_SIGN; KWD_NORTH; KWD_EAST; KWD_SOUTH; KWD_WEST; IDENTIFIER; NUMBER; LINECOMMENT; WS; THEN; BLOCK; COND; CALL; } @header { package cz.uf.karel.core.lang; } @lexer::header { package cz.uf.karel.core.lang; import cz.uf.karel.core.KarelKeyWords; import java.util.Locale; import java.util.HashMap; import java.util.Map; } @lexer::members { private List syntaxErrors = new ArrayList(); public AntlrKarelLexer(CharStream input, RecognizerSharedState state , Locale locale) { super(input, state); } public List getSyntaxErrors() { return syntaxErrors; } @Override public String getErrorMessage(RecognitionException e, String[] tokenNames) { String message = super.getErrorMessage(e, tokenNames); SyntaxError syntaxError = new SyntaxError(); syntaxError.exception = e; syntaxError.message = message; syntaxError.line = e.line; syntaxError.charPositionInLine = e.charPositionInLine; syntaxErrors.add(syntaxError); return message; } @Override public void emitErrorMessage(String msg) { super.emitErrorMessage(msg); } /*@Override public void reportError(RecognitionException e) { throw e; }*/ } @parser::members { private List syntaxErrors = new ArrayList(); private boolean incomment = false; public List getSyntaxErrors() { return syntaxErrors; } @Override public String getErrorMessage(RecognitionException e, String[] tokenNames) { String message = super.getErrorMessage(e, tokenNames); SyntaxError syntaxError = new SyntaxError(); syntaxError.exception = e; syntaxError.message = message; syntaxError.line = e.line; syntaxError.charPositionInLine = e.charPositionInLine; syntaxErrors.add(syntaxError); return message; } @Override public void emitErrorMessage(String msg) { super.emitErrorMessage(msg); } /* protected void mismatch(IntStream input, int ttype, BitSet follow) throws RecognitionException { throw new MismatchedTokenException(ttype, input); } @Override public Object recoverFromMismatchedSet(IntStream input, RecognitionException e, BitSet follow) throws RecognitionException { throw e; } } // Alter code generation so catch-clauses get replace with // this action. @rulecatch { catch (RecognitionException e) { throw e; } */ } /* ********-****************** PARSER ******************************* */ parseSource : ( statement | definition )*; statement : satomic | swhile | srepeat | sif | linecomment | command // TODO change token.type=CALL ? ; definition : KWD_DEFINE name KWD_AS block KWD_END -> ^(KWD_DEFINE name ^(block) ) ; swhile : KWD_WHILE conditionexpr block KWD_END -> ^(KWD_WHILE conditionexpr block) ; srepeat : KWD_REPEAT NUMBER KWD_TIMES block KWD_END -> ^(KWD_REPEAT NUMBER block) ; sif : KWD_IF conditionexpr b1=block (KWD_ELSE b2=block )? KWD_END -> ^( KWD_IF conditionexpr ^(THEN $b1) ^(KWD_ELSE $b2)? ) ; block : (statement)* -> ^( BLOCK (statement)* ) ; conditionexpr : condprefix condition -> ^(COND condprefix condition) ; condprefix : ( KWD_IS | KWD_NOT ); condition : ( KWD_WALL | KWD_SIGN | KWD_EAST | KWD_SOUTH | KWD_WEST | KWD_NORTH ) ; linecomment : LINECOMMENT^ // -> ^(LINECOMMENT // { $LINECOMMENT.setText($LINECOMMENT.getText().trim()); } // ) ; command : IDENTIFIER -> ^(CALL IDENTIFIER) ; name : IDENTIFIER -> ^(IDENTIFIER) ; satomic : KWD_STEP | KWD_LEFT | KWD_RIGHT | KWD_PUT | KWD_PICK | KWD_STOP ; KWD_STEP : 'KWD_STEP'; KWD_LEFT : 'KWD_LEFT'; KWD_RIGHT : 'KWD_RIGHT'; KWD_PUT : 'KWD_PUT'; KWD_PICK : 'KWD_PICK'; KWD_STOP : 'KWD_STOP'; KWD_DEFINE : 'KWD_DEFINE'; KWD_IF : 'KWD_IF'; KWD_WHILE : 'KWD_WHILE'; KWD_REPEAT : 'KWD_REPEAT'; KWD_ELSE : 'KWD_ELSE'; KWD_TIMES : 'KWD_TIMES'; KWD_AS : 'KWD_AS'; KWD_END : 'KWD_END'; KWD_IS : 'KWD_IS'; KWD_NOT : 'KWD_NOT'; KWD_WALL : 'KWD_WALL'; KWD_SIGN : 'KWD_SIGN'; KWD_NORTH : 'KWD_NORTH'; KWD_EAST : 'KWD_EAST'; KWD_SOUTH : 'KWD_SOUTH'; KWD_WEST : 'KWD_WEST'; IDENTIFIER : ('a'..'z'|'A'..'Z'|'_'|'?') ('a'..'z'|'A'..'Z'|'0'..'9'|'_'|'-')* ; NUMBER : ('0'..'9')+ ; LINECOMMENT options {greedy=false;} : '#' (~('\n'|'\r')*) ; WS : ( ' ' | '\t' | '\r' | '\n' ) {$channel=HIDDEN;} ; /* Tree parser */
- Далее давайте расширим возможности IDE NetBeans для понимания файлов ANTLR. Вот плагин NetBeans ANTLR Editor , но учтите, что он не работает «из коробки» для IDE NetBeans 7.0 и 7.0.1. Я должен был проверить репозиторий hg из Kenai , затем удалить модуль «Библиотека редактора», повторно добавить его, а затем смог собрать его. Обратите внимание, что этот плагин использует устаревшую платформу Шлимана (GLF), но это не проблема, просто установите плагин в IDE, и все готово. Хорошая окраска синтаксиса — ваша награда за этот шаг, а также навигатор:
Как вы можете себе представить, плагин, показанный в приведенном выше действии, полезен, если вы создаете файлы ANTLR (или, возможно, редактируете чей-либо существующий файл ANTLR), не столько для использования или обработки файла ANTLR, а на самом деле мы делать в этой статье.
- Теперь мы выполним эти шаги, чтобы присоединить и использовать инструмент ANTLR. Я нашел эти инструкции действительно очень хорошими. Я создал новую библиотеку классов Java, сгенерировал парсер и лексер, как описано в этих шагах, а затем просто следовал всему остальному, описанному здесь . Я закончил с приложением, состоящим из двух модулей:
Затем я запустил приложение, и в окне «Параметры» были показаны мои шрифты и цвета:
И вот раскраска синтаксиса в действии. Обратите внимание, что я не совсем понимаю синтаксис Karel, поэтому просто бросил несколько вещей в этот файл:
Это все. Обратите внимание, что Милош Силханек имеет довольно обширный плагин поддержки Karel для IDE NetBeans здесь:
http://kenai.com/projects/karelnb/sources/mercurial/show
Тем не менее, я начал эту статью с нуля, просто чтобы посмотреть, сколько работы требуется для интеграции файла ANTLR, как первого шага, в платформу NetBeans, то есть первый шаг подразумевает окрашивание синтаксиса. И, как указывалось выше, оказалось, что работы совсем немного, благодаря различным доступным ресурсам.