如何在Java中进行标记化处理运算符(StreamTokenizer)

时间:2011-04-18 21:59:22

标签: java stream operators tokenize

我正在用Java编写一个必须处理运算符的标记化器,并且没有必要在标记之间使用空格。

我需要识别像“< =”这样的标记,同时还要识别“<”和“=”。

现在我有:

if (token == '<')
        if (nextToken == '=')
            this.tokenList.add(27); // <=
        else
            // add 2 tokens separately

StreamTokenizer有没有自己做到这一点?我已阅读API,但我没有看到任何内容。

我可以指定可以算作一个令牌的组合吗?理想情况下,getNextToken会立即删除两个令牌。

谢谢!

5 个答案:

答案 0 :(得分:3)

StreamTokenizer为您提供的是基本Lexer的功能。您必须使用它们来制作高端版本。

您必须非常明智地使用nextToken()pushBack()。例如,下面我正在处理<<<<=。如果您看到一个运算符<,那么请在流中向前查找线索,如果找不到以下<=,则将前瞻标记推回到流中

<强>&GT;&GT;示例代码

import java.io.IOException;
import java.io.StreamTokenizer;
import java.io.StringReader;

public class LexerTest 
{
    private StringReader r;

    public LexerTest(StringReader stringReader) {
        r = stringReader;
    }

    public static void main(String[] args) throws IOException 
    {
        String s = "test = test1 + (test2 * test3 * (test4 - 2);";
        new LexerTest(new StringReader(s)).printTokens();

        System.out.println("\n### Test 2 ###\n");
        s = "test = if(test1 < test2){ test3 = (test4 - 2);}";
        new LexerTest(new StringReader(s)).printTokens();

        System.out.println("\n### Test 3 ###\n");
        s = "test = if(test1 <= test2){ test3 = (test4 - 2);}";
        new LexerTest(new StringReader(s)).printTokens();

        System.out.println("\n### Test 4 ###\n");
        s = "test = if(test1 < test2){ test3 = (test4 << 2);}";
        new LexerTest(new StringReader(s)).printTokens();
    }

    private void printTokens() throws IOException 
    {
        StreamTokenizer st = new StreamTokenizer(r);
        st.eolIsSignificant(true);

        int token = st.nextToken();
        while (token != StreamTokenizer.TT_EOF) 
        {
            token = st.nextToken();
            switch (token) 
            {
            case StreamTokenizer.TT_NUMBER:
                double num = st.nval;
                System.out.println("Number found: " + num);
                break;
            case StreamTokenizer.TT_WORD:
                String word = st.sval;
                System.out.println("Word found: " + word);
                break;
            case '+':
                break;
            case '-':
                break;
            case '/':
                break;
            case '*':
                break;
            case '<':
            {
                int t = st.nextToken();
                switch(t)
                {
                case '=':
                    System.out.println("<=");
                    break;
                case '<':
                    System.out.println("<<");
                    break;
                    default:
                        st.pushBack();
                        System.out.println("<");
                        break;
                }
            }
            }
        }

    }
}

希望这会有所帮助。

答案 1 :(得分:2)

这不是所提供的tokenizer类的典型场景。更像是一个完全成熟的解析器必须处理的东西。即使您需要手动构建这样的标记化器,您也可能会发现研究由解析器生成器(如javacc或antlr)生成的代码具有教育意义。关注他们如何处理“前瞻”,这就是你在这里所要求的。

除非这是一个不允许使用解析器生成器的作业问题,否则使用解析器生成器会得到更好的结果。

答案 2 :(得分:0)

看起来StreamTokenizer有点基本了。

我建议你在StreamTokenizer之上构建一个词法分析器。这个词法分析器会做的是给你一个通常意义上的实际标记流。也就是说,<=将作为单个令牌提供,而不是两个单独的令牌。

更好的是,bin StreamTokenizer并编写一个只直接查看字符的词法分析器。 StreamTokenizer对于解析高级语法几乎没有用。

答案 3 :(得分:0)

nextToken()会跳过空格,因此+++ +会被识别为相同的内容!

答案 4 :(得分:0)

StreamTokenizer是处理此问题的非常基本的工具。

您可以创建自己的lookAhead功能来解决您的目的。

你读了'&lt;'然后打电话给你的前瞻,如果有'=' - 据此采取行动

您可以使用堆栈来保存以前的状态。

PS:对于更大的表达式,这会变得更加复杂。如果你想要更多的功能肯定你应该深入研究词法分析器&amp;解析器