Java StreamTokenizer会破坏整数和松散周期
我已经使用并修改了下面的代码,它在使用Java的StreamTokenizer标记Java代码方面做得非常好。其数字处理存在问题,但:Java StreamTokenizer会破坏整数和松散周期,java,tokenize,Java,Tokenize,我已经使用并修改了下面的代码,它在使用Java的StreamTokenizer标记Java代码方面做得非常好。其数字处理存在问题,但: 它将所有整数转换为双精度整数。我可以通过测试num%1==0来克服这个问题,但这感觉像是一个黑客 更为关键的是,一个。下面的空白被视为一个数字。“Class.method()”是合法的Java语法,但生成的标记是[Word“Class”]、[Whitespace”“]、[Number 0.0]、[Word“method”]、[Symbol”(“])和[Symbo
public class JavaTokenizer {
private String code;
private List<Token> tokens;
public JavaTokenizer(String c) {
code = c;
tokens = new ArrayList<>();
}
public void tokenize() {
try {
// Create the tokenizer
StringReader sr = new StringReader(code);
StreamTokenizer st = new StreamTokenizer(sr);
// Java-style tokenizing rules
st.parseNumbers();
st.wordChars('_', '_');
st.eolIsSignificant(false);
// Don't want whitespace tokens
//st.ordinaryChars(0, ' ');
// Strip out comments
st.slashSlashComments(true);
st.slashStarComments(true);
// Parse the file
int token;
do {
token = st.nextToken();
switch (token) {
case StreamTokenizer.TT_NUMBER:
// A number was found; the value is in nval
double num = st.nval;
if(num % 1 == 0)
tokens.add(new IntegerToken((int)num);
else
tokens.add(new FPNumberToken(num));
break;
case StreamTokenizer.TT_WORD:
// A word was found; the value is in sval
String word = st.sval;
tokens.add(new WordToken(word));
break;
case '"':
// A double-quoted string was found; sval contains the contents
String dquoteVal = st.sval;
tokens.add(new DoubleQuotedStringToken(dquoteVal));
break;
case '\'':
// A single-quoted string was found; sval contains the contents
String squoteVal = st.sval;
tokens.add(new SingleQuotedStringToken(squoteVal));
break;
case StreamTokenizer.TT_EOL:
// End of line character found
tokens.add(new EOLToken());
break;
case StreamTokenizer.TT_EOF:
// End of file has been reached
tokens. add(new EOFToken());
break;
default:
// A regular character was found; the value is the token itself
char ch = (char) st.ttype;
if(Character.isWhitespace(ch))
tokens.add(new WhitespaceToken(ch));
else
tokens.add(new SymbolToken(ch));
break;
}
} while (token != StreamTokenizer.TT_EOF);
sr.close();
} catch (IOException e) {
}
}
public List<Token> getTokens() {
return tokens;
}
}
公共类JavaTokenizer{
私有字符串码;
私有列表令牌;
公共JavaTokenizer(字符串c){
代码=c;
令牌=新的ArrayList();
}
公共void标记化(){
试一试{
//创建标记器
StringReader sr=新的StringReader(代码);
StreamTokenizer st=新的StreamTokenizer(sr);
//Java风格的标记化规则
圣帕西数字();
圣沃德查斯酒店;
st.Eologisicant(假);
//不要空白标记
//圣普通夏尔(0,);
//删除评论
st.slashSlashComments(正确);
st.Slashstar评论(正确);
//解析文件
int标记;
做{
token=st.nextToken();
交换机(令牌){
案例StreamTokenizer.TT_编号:
//找到一个数字;该值为nval
双数值=标准nval;
如果(数值%1==0)
add(新的IntegerToken((int)num);
其他的
添加(新的FPNumberToken(num));
打破
case StreamTokenizer.TT_字:
//找到一个单词;该值为sval
字符串字=st.sval;
添加(新单词token(word));
打破
案例'':
//找到双引号字符串;sval包含内容
字符串dquoteVal=st.sval;
添加(新的DoubleQuotedStringToken(dquoteVal));
打破
案例'\'':
//找到一个带引号的字符串;sval包含内容
字符串squoteVal=st.sval;
添加(新的SingleQuotedStringToken(squoteVal));
打破
案例StreamTokenizer.TT_下线:
//找到行尾字符
添加(新的EOLToken());
打破
case StreamTokenizer.TT_EOF:
//已到达文件末尾
添加(新的EOFToken());
打破
违约:
//找到了一个常规字符;该值是标记本身
char ch=(char)st.ttype;
if(字符.isWhitespace(ch))
添加(新的WhitespaceToken(ch));
其他的
添加(新的SymbolToken(ch));
打破
}
}while(token!=StreamTokenizer.TT_EOF);
高级关闭();
}捕获(IOE异常){
}
}
公共列表getTokens(){
归还代币;
}
}
有机会时,我会调查parboiled。与此同时,我为让它正常工作而实施的令人厌恶的解决方案是:
private static final String DANGLING_PERIOD_TOKEN = "___DANGLING_PERIOD_TOKEN___";
然后在tokenize()中
此解决方案专门针对我的需要,即不关心原始空格是什么(因为它在插入的“标记”周围添加了一些空格”)parseNumbers()在默认情况下处于“开”状态。使用resetSyntax()关闭数字解析和所有其他预定义字符类型,然后启用所需的字符类型
这就是说,手动数字解析可能会因为计算点和指数而变得棘手……使用扫描仪和正则表达式,实现您自己的标记器应该相对简单,完全符合您的需要。例如,您可能想看看
标记器
内部类:(最后约120 LOC)我已经使用了各种内置Java标记器类,我的收获是它们实际上功能不强。看看真正的解析器(它们有一个Java解析器,都是预先配置好的,随时可以使用,顺便说一句,不要试着自己制作。)也许你可以在“word chars”中添加
“,参见javadocOh,我知道,但ANTLR庞大而复杂,功能远远超出我的需要,而这仅仅是一个缺陷,无法完全满足我的需要,因此,如果我能解决这个问题,将比更换整个系统少几个小时的工作system@RC,很有趣。我不确定我是否理解StreamTokenizer.wordChars()上的javadoc。似乎只使用从firstArg到secondArg的字符来标识单词,但我偷来的代码示例将两个Arg都设置为下划线,并且它仍然可以识别单词。我还尝试将其设置为.wordChars(0x23,0xFF),其中包括句号,无法识别行为上的任何差异。我不是StringTokenizer方面的专家,抱歉,如果antlr对您来说太大,也许您应该看看这一点,这会更有意义。它现在工作得好多了。我希望文档能更清楚地说明parseNumbers()没有任何效果,除非resetSyntax()他被叫来了。
//a period following whitespace, not followed by a digit is a "dangling period"
code = code.replaceAll("(?<=\\s)\\.(?![0-9])", " "+DANGLING_PERIOD_TOKEN+" ");
case StreamTokenizer.TT_WORD:
// A word was found; the value is in sval
String word = st.sval;
if(word.equals(DANGLING_PERIOD_TOKEN))
tokens.add(new SymbolToken('.'));
else
tokens.add(new WordToken(word));
break;