Как не совпадать с токеном в кавычках, например, «здравствуйте», orld в javacc - PullRequest
0 голосов
/ 04 апреля 2019

Я делаю парсер redis-cli с помощью javacc. Я должен справиться с цитатой

например set "a b" "cd", я надеюсь, что ключевой токен a b и значение токена cd.

Вот мое решение:

RedisCommand.java

package com.demo.command;
public interface RedisCommand {
}

SetCommand .java

package com.demo.command;

public class SetCommand implements RedisCommand{

    private String key;

    private String value;

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}

RedisCommand.jj

options {
  STATIC = false;
  DEBUG_PARSER=true;
}

PARSER_BEGIN(RedisCommandParser)

package com.demo.parser;

import com.demo.command.*;
import java.util.*;

public class RedisCommandParser {

  public static void main(String args[]) throws ParseException {
    RedisCommandParser parser = new RedisCommandParser(System.in);
    parser.RedisCommand();
  }

}
PARSER_END(RedisCommandParser)

SKIP :
{
  <WHITESPACE: " " | "\t" | "\n" | "\r">
}

TOKEN :
{
  <K_SET: "set">
}

TOKEN :
{
   <SINGLE_QUOTE: "'">
   | <DOUBLE_QUOTE: "\"">
   | <SINGLE_STRING: <SINGLE_QUOTE> ((~["'"]) | "\\'" )+ <SINGLE_QUOTE>>
   | <DOUBLE_STRING: <DOUBLE_QUOTE> ((~["\""]) | "\\\"" )+ <DOUBLE_QUOTE>>
   | <RAW_STRING: (~[" "])+>
}

RedisCommand RedisCommand() :
{
  RedisCommand command = null;
}
{
  command=SetCommand() <EOF>
  {
    return command;
  }
}

SetCommand SetCommand() :
{
  SetCommand command = new SetCommand();
  String key = null;
  String value = null;
}
{
  <K_SET> key=StringParam() value=StringParam()
  {
    command.setKey(key);
    command.setValue(value);
    return command;
  }
}

String StringParam() :
{
  String s = null;
  Token token = null;
  String im = null;
}
{
  (token=<SINGLE_STRING> { im=token.image; s=im.substring(1, im.length()-1);}
  | token=<DOUBLE_STRING> { im=token.image; s=im.substring(1, im.length()-1);}
  | s=RawString()
  )
  {return s;}
}

String RawString() :
{}
{
  /* for reserved word
   * support like 'set set set'
   */
  (<K_SET>
  | <RAW_STRING>
  )
  {
    return token.image;
  }
}

SetCommandTest.java

package com.demo.command;

import com.demo.parser.ParseException;
import com.demo.parser.RedisCommandParser;
import org.junit.Test;

import java.io.StringReader;

public class SetCommandTest {

    @Test
    public void test() throws ParseException {
        //test1
        _test("set a b", "a", "b");

        //test2
        _test("set \"a b\" cd", "a b", "cd");

        //test3
        _test("set a\"b c\"d", "a\"b", "c\"d");

        //test4
        _test("set \"ab c\"d", "\"ab", "c\"d");
    }

    private void _test(String line, String expectKey, String expectValue) throws ParseException {
        RedisCommandParser parser = new RedisCommandParser(new StringReader(line));
        SetCommand command = (SetCommand) parser.RedisCommand();
        String key = command.getKey();
        assert key.equals(expectKey) : String.format("command[%s] key[%s] expect[%s]", line, key, expectKey);
        String value = command.getValue();
        assert value.equals(expectValue) :  String.format("command[%s] value[%s] expect[%s]", line, value, expectValue);
    }
}

test4 в SetCommandTest завершился неудачно, сообщение об ошибке

Call:   RedisCommand
  Call:   SetCommand
    Consumed token: <"set" at line 1 column 1>
    Call:   StringParam
      Consumed token: <<DOUBLE_STRING>: ""ab c"" at line 1 column 5>
    Return: StringParam
    Call:   StringParam
      Call:   RawString
        Consumed token: <<RAW_STRING>: "d" at line 1 column 11>
      Return: RawString
    Return: StringParam
  Return: SetCommand
  Consumed token: <<EOF> at line 1 column 11>
Return: RedisCommand
java.lang.AssertionError: command[set "ab c"d] key[ab c] expect["ab]
    at com.demo.command.SetCommandTest._test(SetCommandTest.java:33)
    at com.demo.command.SetCommandTest.test(SetCommandTest.java:26)

Он принимает "ab c" как <DOUBLE_STRING>, а это не то, что я хочу. Я думаю, что проблема в <DOUBLE_STRING>, кавычки после пробела и кавычки до пробела должны работать нормально. Не вся строка кавычки <DOUBLE_STRING>. но я не знаю как это сделать. Пожалуйста, помогите мне

...