ANTLR 4 - Несоответствующий ввод - PullRequest
4 голосов
/ 02 июля 2019

Я пытаюсь разработать небольшой DSL с ANTLR для одного из моих проектов.Поэтому я написал определения для лексера ...

lexer grammar SpamkillerLexer;

MAILBOX: 'Mailbox';
PASSWORD: 'Password';
HOST: 'Host';
USER: 'User';
FOLDER: 'Folder';
PORT: 'Port';
ACTIONS: 'Actions';

WHEN: 'When';
SUBJECT: 'Subject';
BODY: 'Body';
EQUALS: 'Equals';
CONTAINS: 'Contains';
THEN: 'Then';
DELETE: 'Delete';
REDIRECT: 'Redirect';
TO: 'to';

BR_OP: '{';
BR_CL: '}';
EQ: '=';

STRING: '"' ( '\\"' | . )*? '"';
LITERAL: [a-zA-Z_0-9]+;

WS : [ \n\t\r]+ -> skip ;

... и парсера ...

parser grammar SpamkillerParser;
mailboxes: mailbox+;
mailbox: MAILBOX LITERAL BR_OP settings BR_CL;

settings: setting+;
setting: (key EQ STRING | ACTIONS EQ actions);
key: MAILBOX | PASSWORD | HOST | USER | FOLDER | PORT;

actions: BR_OP action* BR_CL;
action: WHEN condition THEN job;
condition: (SUBJECT | BODY) (EQUALS | CONTAINS) STRING;
job: (DELETE | (REDIRECT TO STRING));

Мой тестовый файл выглядит так:

Mailbox Foobar {
    Port = "123"
    Host = "foohost"
    User = "foouser"
    Password = "foopass"
    Folder = "Inbox"
    Actions = {
        When Subject Equals "fooooo" Then Delete
        When Body Contains "fooooo" Then Redirect to "foo@bar.baz"
    }
}

Когда я проверяю mailboxes в плагине ANTLR IntelliJ, он работает отлично, и я получаю соответствующий AST:

AST

Но когда я пытаюсьПроанализируйте мой тестовый файл программно, я получаю сообщение об ошибке ...

line 1:8 mismatched input 'Foobar' expecting LITERAL

Я пытался изменить порядок своих правил лексера, но ни одна из моих попыток не помогла мне избавиться от ошибки.Кто-нибудь знает, как решить эту проблему?

Мой код для анализа моего файла выглядит так:

String input = FileUtils.readFileToString(new File("test.txt"), Charsets.UTF_8);
CodePointCharStream inputStream = CharStreams.fromString(input);
SpamkillerLexer lexer = new SpamkillerLexer(inputStream);
CommonTokenStream commonTokenStream = new CommonTokenStream(lexer);
SpamkillerParser parser = new SpamkillerParser(commonTokenStream);
SpamkillerParser.MailboxesContext mailboxes = parser.mailboxes();

1 Ответ

2 голосов
/ 03 июля 2019

Вы не указали в вашем парсере, какой словарный токен должен использоваться.Таким образом, ANTLR создает неявные токены (которые на самом деле являются простыми терминалами) для вашего синтаксического анализатора вместо использования в лексере.

Чтобы исправить это, укажите параметр tokenVocab:

parser grammar SpamkillerParser;

options {
   tokenVocab=SpamkillerLexer;
}

mailboxes: mailbox+;
mailbox: MAILBOX LITERAL BR_OP settings BR_CL;

settings: setting+;
setting: (key EQ STRING | ACTIONS EQ actions);
key: MAILBOX | PASSWORD | HOST | USER | FOLDER | PORT;

actions: BR_OP action* BR_CL;
action: WHEN condition THEN job;
condition: (SUBJECT | BODY) (EQUALS | CONTAINS) STRING;
job: (DELETE | (REDIRECT TO STRING));
...