[英]Java BufferedReader on System.in ignores first line / command
[英]Java System.in, newline characters and parsing the command line
我正在尝试使用JFlex和Jacc在Java中创建一个简单的解析器。 为了进行测试,我编写了一个简单的词法分析器组合来识别字符串和数字。 我设法连接了词法分析器和解析器,但无法处理从System.io发送的换行符(ASCII 10)。
这是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”,然后显示可疑的ASCII10。接下来,我键入“ 1 2 3 4”,然后解析器将打印“ c”,等等。 9。
因此,当我输入“ abc”时,解析器将打印“ a”,“ b”,然后显示可疑的ASCII10。接下来,我键入“ 1 2 3 4”,然后解析器将打印“ c”,等等。 9。
这是意料之中的。 解析器仅打印语义值sim
符号,并且仅在将其inp
为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
符号设置正确的令牌类型。
在另一方面 ,如果换行不显著的语法,那么你应该完全忽略他们。 在这种情况下,根本不会出现您的问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.