Java System.in, символы новой строки и синтаксический анализ командной строки

Я пытаюсь создать простой анализатор в Java с использованием JFlex и Jacc. Для тестирования я написал простую комбинацию лексера-парсера для распознавания строк и чисел. Мне удалось соединить лексер и анализатор, но я не могу обработать символы новой строки (ASCII 10), отправленные из System.io.

Вот lexer.flex

import java.io.*;

%%

%class Lexer
%implements ParserTokens

%function yylex
%int

%{

    private int token;
    private String semantic;

    public int getToken()
    {
        return token;
    }

    public String getSemantic()
    {
        return semantic;
    }

    public int nextToken()
    {
        try
        {
            token = yylex();
        }
        catch (java.io.IOException e)
        {
            System.out.println("IO exception occured:\n" + e);
        }
        return token;
    }

%}


ID = [a-zA-Z_][a-zA-Z_0-9]*
NUMBER = [0-9]+
SPACE = [ \t]
NL = [\n] | [\r] | [\n\r]


%%

{ID}        { semantic = yytext(); return ID; }
{NUMBER}    { semantic = yytext(); return NUM; }
{SPACE}     {  }
{NL}        { System.out.println("Kill the bugger!"); }
<<EOF>>     {  }

Parser.jacc:

%{

    import java.io.*;

%}

%class Parser
%interface ParserTokens

%semantic String

%token <String> ID
%token <String> NUM
%token <String> SPACE

%type <String> inp


%%

inp : inp sim { System.out.println($2); }
    | sim { System.out.println($1); }
    ;

sim : ID
    | NUM
    ;


%%

    private Lexer lexer;

    public Parser(Reader reader)
    {
        lexer = new Lexer(reader);
    }


    public void yyerror(String error)
    {
        System.err.println("Error: " + error);
    }

    public static void main(String args[]) throws IOException
    {
        Parser parser = new Parser(
            new InputStreamReader(System.in));

        parser.lexer.nextToken();
        parser.parse();
    }

Пример терминальной сессии:

[johnny@test jacc]$ java Parser
a b c
a
b
Kill the bugger!
1 2 3 4
c
1
2
3
Kill the bugger!

Поэтому, когда я ввожу "abc", парсер печатает "a", "b", а затем убогий ASCII 10. Затем я набираю "1 2 3 4", и только потом парсер печатает "c" и т. Д. Я нахожусь на Linux / Java 9.

1 ответ

Решение

Поэтому, когда я ввожу "a b c", парсер печатает "a", "b", а затем убогий ASCII 10. Затем я набираю "1 2 3 4", и только потом парсер печатает "c" и т. Д. Я нахожусь на Linux / Java 9.

Этого следовало ожидать. Ваш парсер печатает только семантические значения sim символы, и только тогда, когда это уменьшает их до или в inp, Он не будет выполнять такое сокращение без маркера предварительного просмотра, несмотря на тот факт, что в вашем конкретном синтаксическом анализаторе выбор всегда должен уменьшаться, когда символ в конце очереди является sim, Но ваш лексер печатает сообщение новой строки, как только сканируется новая строка в процессе получения такого жетона предварительного просмотра, до сокращения, которое приводит к печати предыдущего семантического значения.

Если переводы строки важны для вашей грамматики, тогда ваш лексер должен испускать для них токены, а не работать с ними напрямую, и ваша грамматика должна учитывать эти токены. Например:

inp : line         { System.out.print($1); }
    | inp NL line  { System.out.println("NEWLINE WAS HERE"); System.out.print($3); }
    ;

line : /* empty */ { $$ = new StringBuilder(); }
    | line sim     { $$ = $1.append($2).append('\n'); }
    ;

sim : ID
    | NUM
    ;

Там предполагается, что лексер испускает NL токен вместо печати сообщения. Обратите внимание, что вся печать в этом примере происходит на одном уровне. Если печать - это то, что вы действительно хотите сделать, то выполнение всего этого на одном уровне значительно упрощает контроль и прогнозирование порядка, в котором будут печататься данные.

Примечание: этот анализатор немного быстрый и грязный, содержит конфликт сдвиг / уменьшение. По умолчанию разрешение сдвига является правильным. Конфликт оказывается сложным для правильной сортировки, если только вы не заставите свой лексер вставить синтетический токен NL в конце ввода. Кроме того, вам, конечно, нужно установить правильный тип токена для line условное обозначение.

С другой стороны, если переводы строки не имеют значения для грамматики, вы должны полностью их игнорировать. В этом случае ваша проблема не возникает вообще.

Другие вопросы по тегам