让解析python有趣的是缩进。该标准给出了插入INDENT和DEDENT标记的规则。我们可以在JavaCC中做到这一点,但下面采用了另一种方法,即使用语义前瞻。
void for_stmt() : {
int col = getToken(1).beginColumn ;
} {
"for" exprlist() "in" testlist() ":" suite(col)
[ {checkColumn( col ) ;} 'else' ':' suite(col) ]
}
void suite(int col) : {
int newCol ;
} {
<NEWLINE>
{ newCol = checkIndent(col) ; }
stmtsAndDedent(newCol)
|
simple_stmt(col)
}
// One or more stmt followed by a dedent
void stmtsAndDedent(int col) : {
stmt(col)
(
LOOKAHEAD( dedenting(col) ) {}
|
stmtsAndDedent(col)
)
}
}
void stmt(int col) : {
} {
simple_stmt(col)
|
{checkColumn(col) ;}
compound_stmt()
}
void simple_stmt() : {
} {
{checkColumn(col) ;}
small_stmt() (";" small_stmt())* [";"] <NEWLINE>
}
现在还需要编写一些java方法
int checkIndent(int col) {
Token tk = getToken(1) ;
int newCol = tk.beginColumn ;
if( newCol <= col ) {
throw new ParseException( "Expected token at line " +tk.beginLine+
" column " +tk.beginColumn+
" was expected to be indented by more than "
+col+ " characters.") ; }
return newCol ; }
boolean dedenting(int col) {
Token tk = getToken(1) ;
return tk.beginColumn < col ; }
void checkColumn(int col) {
Token tk = getToken(1) ;
int newCol = tk.beginColumn ;
if( newCol != col ) {
throw new ParseException( "Expected token at line " +tk.beginLine+
" column " +tk.beginColumn+
" was expected to be indented by exactly "
+col+ " characters.") ; } }
这一切都是未经测试的,但我认为一旦修复了小错误,它就会起作用。
一旦可以解析,计算行数就很简单了。