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