0

我正在尝试更改 JSqlParser 项目中的语法,该项目处理指定标准 SQL 语法的 javacc 语法文件 .jj。我很难让一个部分工作,我把它缩小到以下,大大简化了语法。

基本上我有一个定义 Column : [table ] 。场地

但表本身也可以包含“。” char,这会导致混乱。

我直观地认为以下语法应该接受以下所有句子:

选择 mytable.myfield

选择我的领域

选择 mydb.mytable.myfield

但实际上它只接受上面的第 2 和第 3。每当它看到“.”时,它就会进入要求 2 点版本的表格(即表格的第一推导规则)

我怎样才能使这个语法起作用?

非常感谢杨

    options{
        IGNORE_CASE=true ;
        STATIC=false;
            DEBUG_PARSER=true;
        DEBUG_LOOKAHEAD=true;
        DEBUG_TOKEN_MANAGER=false;
    //  FORCE_LA_CHECK=true;
        UNICODE_INPUT=true;
    }

    PARSER_BEGIN(TT)

    import java.util.*;

    public class TT {

    }
    PARSER_END(TT)


    ///////////////////////////////////////////// main stuff concerned
    void Statement() :
    { }
    {
    <K_SELECT> Column()
    }

    void Column():
    {
    }
    {
    [LOOKAHEAD(3) Table()  "." ]
    //[ 
    //LOOKAHEAD(2) (
    //      LOOKAHEAD(5) <S_IDENTIFIER> "."  <S_IDENTIFIER>  
    //      |
    //      LOOKAHEAD(3) <S_IDENTIFIER>
    //)
    //
    //
    //
    //]

    Field()
    }

    void Field():
    {}{
       <S_IDENTIFIER>
    }

    void Table():
    {}{
            LOOKAHEAD(5) <S_IDENTIFIER> "."  <S_IDENTIFIER>
            |
            LOOKAHEAD(3) <S_IDENTIFIER>
    }

    ////////////////////////////////////////////////////////



SKIP:
{
    " "
|   "\t"
|   "\r"
|   "\n"
}

TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */
{
<K_CREATE: "CREATE">
|
<K_SELECT: "SELECT">
}


TOKEN : /* Numeric Constants */
{
   < S_DOUBLE: ((<S_LONG>)? "." <S_LONG> ( ["e","E"] (["+", "-"])? <S_LONG>)?
                        |
                        <S_LONG> "." (["e","E"] (["+", "-"])? <S_LONG>)?
                        |
                        <S_LONG> ["e","E"] (["+", "-"])? <S_LONG>
                        )>
  |     < S_LONG: ( <DIGIT> )+ >
  |     < #DIGIT: ["0" - "9"] >
}


TOKEN:
{
        < S_IDENTIFIER: ( <LETTER> | <ADDITIONAL_LETTERS> )+ ( <DIGIT> | <LETTER> | <ADDITIONAL_LETTERS> | <SPECIAL_CHARS>)* >
|       < #LETTER: ["a"-"z", "A"-"Z", "_", "$"] >
|   < #SPECIAL_CHARS: "$" | "_" | "#" | "@">
|   < S_CHAR_LITERAL: "'" (~["'"])* "'" ("'" (~["'"])* "'")*>
|   < S_QUOTED_IDENTIFIER: "\"" (~["\n","\r","\""])+ "\"" | ("`" (~["\n","\r","`"])+ "`") | ( "[" ~["0"-"9","]"] (~["\n","\r","]"])* "]" ) >

/*
To deal with database names (columns, tables) using not only latin base characters, one
can expand the following rule to accept additional letters. Here is the addition of german umlauts.

There seems to be no way to recognize letters by an external function to allow
a configurable addition. One must rebuild JSqlParser with this new "Letterset".
*/
|   < #ADDITIONAL_LETTERS: ["ä","ö","ü","Ä","Ö","Ü","ß"] >
}
4

4 回答 4

1

你可以像这样重写你的语法

Statement --> "select" Column
Column --> Prefix <ID>
Prefix --> (<ID> ".")*

现在唯一的选择是是否迭代。假设一个“。” 不能跟随列,这很容易通过前瞻 2 完成:

Statement --> "select" Column
Column --> Prefix <ID>
Prefix --> (LOOKAHEAD( <ID> ".") <ID> ".")*
于 2015-05-08T15:33:54.470 回答
0

flex+bison(LR解析器)中的以下语法确实可以正常工作,正确识别以下所有句子:

创建 mydb.mytable 创建 mytable 选择 mydb.mytable.myfield 选择 mytable.myfield 选择 myfield

所以这确实是由于 LL 解析器的限制

%%

statement:
        create_sentence
        |
        select_sentence
        ;

create_sentence:  CREATE table
        ;

select_sentence: SELECT  table '.'  ID
                |
                SELECT ID
                ;

table : table '.' ID
        |
        ID
        ;



%%
于 2015-05-09T00:24:42.877 回答
0

如果您需要 Table 成为它自己的非终结符,您可以通过使用一个布尔参数来执行此操作,该参数表示该表是否应该跟一个点。

void Statement():{}{
    "select" Column() | "create" "table" Table(false) }

void Column():{}{
    [LOOKAHEAD(<ID> ".") Table(true) "."] <ID> }

void Table(boolean expectDot):{}{
    <ID> MoreTable(expectDot) }

void MoreTable(boolean expectDot) {
    LOOKAHEAD("." <ID> ".", {expectDot}) "." <ID> MoreTable(expectDot)
|
    LOOKAHEAD(".", {!expectDot}) "." <ID> MoreTable(expectDot)
|
    {}
}

这样做会直接或间接地排除在任何语法前瞻规范中使用 Table 的可能性。例如,您的语法中不应该有LOOKAHEAD( Table())任何地方,因为在语法超前期间不使用语义超前。有关更多信息,请参阅常见问题解答。

于 2015-05-09T14:51:17.527 回答
0

使用JSqlParser V0.9.x ( https://github.com/JSQLParser/JSqlParser )可以很好地解析您的示例

CCJSqlParserUtil.parse("SELECT mycolumn");
CCJSqlParserUtil.parse("SELECT mytable.mycolumn");
CCJSqlParserUtil.parse("SELECT mydatabase.mytable.mycolumn");
于 2015-05-28T11:54:39.083 回答