好的,我得到它的工作。我决定用词汇操作而不是用MORE
处理来做到这一点,这似乎更直接。另外,我分裂词法/解析到两个部分,使事情更为简单:
- 首先解析出包含扩展语法的字符串,然后
- 在第二遍解析这些字符串与扩展的语法。
至于获得基于长度前缀的令牌,所述第一部分是定义令牌表示的命令:
<Extended> TOKEN :
{
<LINECOLOR: "c"> { singleCount = 1; }
| <FILLCOLOR: "C"> { singleCount = 1; }
| <FONT: "F"> { singleCount = 2; }
| <TEXT: "T"> { singleCount = 5; }
| <TEXTCHARS: "t">
| <SPLINE: "B"> { coordCount = 1; }
| <FILLEDSPLINE: "b"> { coordCount = 1; }
| <FILLEDELLIPSE: "E">
| <UNFILLEDELLIPSE: "e">
| <POLYLINE: "L"> { coordCount = 1; }
| <FILLEDPOLYGON: "P"> { coordCount = 1; }
| <UNFILLEDPOLYGON: "p"> { coordCount = 1; }
| <STYLE: "S"> { singleCount = 1; }
}
我加入语句的词法行动以指示长度标志将发生在命令令牌之后。在大多数情况下,它是子命令之后的第一个标记,但在某些情况下,还需要先解析其他介入标记。
接下来是定义令牌以匹配长度计数。当被触发消耗长度指定的标记时,词法动作会解码长度计数并从输入缓冲区中消耗适当数量的字符。获取正确的数据后,它会根据需要切换令牌图像和类型。该令牌还匹配默认词汇状态中的数字字符串。
/*
* Special number token. Normally just grabs a number.
* In the Extended lexical state can grab a fixed length
* string or a list of coordinate pairs.
*/
<DEFAULT,Extended> TOKEN:
{
<#NUM: (["0"-"9"]) >
| <NUMBER: (<NUM>)+ | (<NUM>)* "." (<NUM>)+ | (<NUM>)+ "." (<NUM>)* >
{
if (curLexState == Extended && singleCount-- == 1) {
// Get a single fixed length parameter
int len = Integer.parseInt(matchedToken.image);
StringBuilder sb = new StringBuilder();
try {
while (input_stream.readChar() != '-')
{ /* Do nothing */; };
for (int i=0; i<len; i++)
sb.append(input_stream.readChar());
} catch (IOException ioe) {
throw new TokenMgrError(true, curLexState, input_stream.getLine(), input_stream.getColumn(), sb.toString(), (char)0, TokenMgrError.LEXICAL_ERROR);
}
matchedToken.image = sb.toString();
matchedToken.endLine = input_stream.getEndLine();
matchedToken.endColumn = input_stream.getEndColumn();
matchedToken.kind = SINGLE;
}
if (curLexState == Extended && coordCount-- == 1) {
// Get a list of coordinate pairs
int len = Integer.parseInt(matchedToken.image);
StringBuilder sb = new StringBuilder();
try {
for (int i=0; i<len*2; i++) {
char c;
while ((c=input_stream.readChar()) == ' ')
{ /* Do nothing */; };
if (i>0) sb.append(" ");
do
{sb.append(c);}
while
((c=input_stream.readChar()) != ' ');
}
} catch (IOException ioe) {
throw new TokenMgrError(true, curLexState, input_stream.getLine(), input_stream.getColumn(), sb.toString(), (char)0, TokenMgrError.LEXICAL_ERROR);
}
matchedToken.image = sb.toString();
matchedToken.endLine = input_stream.getEndLine();
matchedToken.endColumn = input_stream.getEndColumn();
matchedToken.kind = COORDS;
}
}
}
的任何特殊标记必须声明,以及那举行的倒计时令牌变量解码:
/*
* Special extended token identifiers
*/
<Extended> TOKEN:
{
<COORDS: <NUMBER>>
| <SINGLE: <NUMBER>>
}
TOKEN_MGR_DECLS:
{
/*
* These keep track of where the length prefixed strings
* and coordinate pairs start in the extended xdot commands.
* Set these values in the lexical actions for the sub-command
* definitions.
*/
int singleCount = -1;;
int coordCount = -1;;
}
这实际上是很容易,一旦我明白词汇的行动是如何工作的,并令牌管理器API可以做些什么。
要利用这分析器,切换至增词法状态,并使用作品,如:
<LINECOLOR> color=<SINGLE>
或
<UNFILLEDPOLYGON> scoords=<COORDS>
或
<TEXT> sx=<NUMBER> sy=<NUMBER> sj=<NUMBER> sw=<NUMBER> label=<SINGLE>
这就是它。它似乎运作良好。
我这样做的唯一缺点是SKIP
处理不会发生在我手动从输入流中读取的字符上,所以我必须照顾空格(在我的代码示例中未完全实现)。
我认为你使用MORE的想法是完美的。为什么不实施它,然后回答自己的问题。没有必要担心LOOKAHEAD。 –
要表示令牌的结尾,请使用TOKEN生产。所以当再有一个字符时,切换到任何字符都是TOKEN的状态。 –