Как работать с операторами при токенизации в Java (StreamTokenizer) - PullRequest
3 голосов
/ 19 апреля 2011

Я пишу токенайзер на Java, который имеет дело с операторами, и пробелы между символами не нужны.

Мне нужно распознать что-то вроде "<=" как токен, но также и распознать"<" и "=". </p>

Сейчас у меня есть:

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

Есть ли у StreamTokenizer возможность сделать это самостоятельно?Я прочитал API, но ничего не вижу.

Могу ли я указать комбинацию токенов, которую можно считать одним?В идеале getNextToken удаляет оба токена одновременно.

Спасибо!

Ответы [ 5 ]

3 голосов
/ 19 апреля 2011

Что StreamTokenizer предоставляет вам функциональность базового Lexer. Вы должны использовать их, чтобы сделать вашу версию высокого класса.

Вы должны использовать nextToken() и pushBack() очень разумно. Например, ниже я присматриваю за <, << и <=. Если вы видите оператор <, то посмотрите в потоке подсказку, а если вы не найдете следующего < или =, затем верните жетон предварительного просмотра в поток.

>> Пример кода

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 голосов
/ 19 апреля 2011

Это не типичный сценарий для предоставленных классов токенизатора. Больше похоже на то, с чем должен справиться полноценный парсер. Даже если вам необходимо создать такой токенизатор вручную, вы можете найти его полезным для изучения кода, созданного генераторами синтаксических анализаторов, такими как javacc или antlr. Сосредоточьтесь на том, как они справляются с «lookahead», о чем вы спрашиваете здесь.

Если это не проблема с домашней работой, когда вам не разрешено использовать генератор парсера, вы получите лучшие результаты при его использовании.

0 голосов
/ 18 июня 2015

StreamTokenizer - очень простой инструмент для обработки этого.

Вы можете создать свою собственную функцию lookAhead для решения вашей задачи.

Вы читаете '<', затем вызываете свой lookahead, и если естьa '=' или нет - действуйте соответственно </p>

вы можете использовать стек для сохранения вашего предыдущего состояния.

PS: это будет намного сложнее с большими выражениями и если вы, конечно, захотите больше функциональностиВы должны углубиться в лексеры и парсеры

0 голосов
/ 20 августа 2013

nextToken() пропустит пробел, поэтому ++ и + + будут распознаны как одинаковые!

0 голосов
/ 19 апреля 2011

Похоже, StreamTokenizer немного на базовой стороне.

Я бы порекомендовал вам построить лексер поверх StreamTokenizer. Этот лексер даст вам поток фактических токенов в обычном смысле. То есть <= будет дан как одиночный токен , а не как два отдельных токена.

Еще лучше, bin StreamTokenizer и напишите лексер, который просто смотрит на символы напрямую. StreamTokenizer делает слишком мало, чтобы быть полезным для анализа расширенной грамматики.

...