好的,我得到它的工作。我決定用詞彙操作而不是用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的狀態。 –