【问题标题】:How to deal with operators while tokenizing in Java (StreamTokenizer)在 Java 中标记化时如何处理运算符(StreamTokenizer)
【发布时间】:2011-04-18 21:59:22
【问题描述】:

我正在用 Java 编写一个标记器,它必须处理运算符,并且标记之间的空格字符不是必需的。

我需要将“

现在我有:

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

StreamTokenizer 是否可以自行执行此操作?我已通读 API,但什么也没看到。

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

谢谢!

【问题讨论】:

  • 看起来StreamTokenizer 不是适合您的工具。

标签: java stream operators tokenize


【解决方案1】:

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

您必须非常明智地使用nextToken()pushBack()。例如,在下面我正在处理&lt;&lt;&lt;&lt;=。如果您看到运算符&lt;,则在流中向前看以寻找线索,如果您没有找到后续&lt;=,则将向前看标记推回流中。

>> 示例代码

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;
                }
            }
            }
        }

    }
}

希望这会有所帮助。

【讨论】:

    【解决方案2】:

    这不是提供的标记器类的典型场景。更像是一个成熟的解析器必须处理的东西。即使您需要手动构建这样的分词器,您也会发现学习由解析器生成器(如 javacc 或 antlr)生成的代码很有教育意义。专注于他们如何处理“前瞻”,这就是您在此处询问的内容。

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

    【讨论】:

    【解决方案3】:

    看起来StreamTokenizer有点基础。

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

    更好的是,bin StreamTokenizer 并编写一个仅直接查看字符的词法分析器。 StreamTokenizer 做的太少,无法用于解析高级语法。

    【讨论】:

      【解决方案4】:

      nextToken() 将跳过空格,因此 +++ + 将被识别为相同!

      【讨论】:

        【解决方案5】:

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

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

        你读了一个'

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

        PS:使用更大的表达式会变得更加复杂,如果您确实想要更多功能,您应该深入研究词法分析器和解析器

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-04-07
          • 1970-01-01
          相关资源
          最近更新 更多