我是ANTLR的新手,目前正在阅读“最终的ANTLR参考”。
我能够使用ANTLR找到一个可以解析一些基本SQL语句的现有程序。但是,我需要扩展此程序,以便我可以解析IN
运算符在WHERE
子句中的语句。
我能够得到一些半工作的东西(我正在使用ANTLR版本3)。
Combinations of IN Operator
-- IN (21) -- Works correct, even for (21, 86, 155)
-- IN (50-100) -- Works correct even for multiple ranges ( (50-100, 120-200, 350-420))
-- IN (21, 50-100)
-- IN (50-100, 21, 150-200)
-- IN (21, 50-100, 155)
-- IN (21, 86, 50-100, 155)
我的代码在所有其他场景中都不起作用 - 我必须遗漏一些东西。
这是我在语法文件中写的:
.........
.......
// in expression
inExpression
: field_name RESERVED_NOT? RESERVED_IN^ inCondition
;
inCondition
: OPEN_PAREN!
( (select_statement) => select_statement
| (inElement) (COMMA! inElement)*)
CLOSE_PAREN!
;
inElement
: unary_expression
| range_expression
;
...........
............
unary_expression
: constant
;
// MCK
range_expression
: unary_expression RANGE^ unary_expression
;
constant
: INT
| FLOAT
| STRING
| CHAR
;
这是我的树解析器。我无法弄清楚需要采取哪些措施来支持上面提到的IN
运算符的所有方案:
joinCondition returns [SqlWhere cond = null;]
@init {
List<string> inList = new List<string>();
bool notModifier = false;
StringBuilder builder = new StringBuilder(255);
List<string> rangeList = new List<string>();
}
: ^(RESERVED_IN field = fieldName (RESERVED_NOT { notModifier = true; })? ((node1 = unaryExpression
{
inList.Add(node1.Text);
}
)*
|
(rlist = rangeExpression
{
foreach(CommonTree ritem in rlist)
{
rangeList.Add(ritem.Text);
}
}
)* ) )
{
if(inList.Count > 0)
{
int i = 0;
if (!field.IsComplex)
{
field.Parameters = parameters;
// Append the field name into the buffer
//builder.Append("(");
builder.Append(field.ToString());
// If the not modifier is being used
if (notModifier)
{
builder.Append(" NOT ");
}
// Place the paren
builder.Append(" IN (");
// Build the in list
foreach (string inItem in inList)
{
if (i == 0)
{
builder.Append(inItem);
}
else
{
builder.Append(", ");
builder.Append(inItem);
}
i++;
}
builder.Append(')');
if (field.Type == ColumnType.ForeignKey)
{
Query.AddSubQueryWhere(new SqlWhere(builder.ToString()));
}
else
{
$cond = new SqlWhere(builder.ToString());
}
}
}
if (rangeList.Count > 0)
{
int i = 0;
// build the rangeList with BETWEEN and AND
foreach(string rangeItem in rangeList)
{
if (i == 0 || ((i \% 2) == 0))
{
if(inList.Count > 0 || i > 1)
{
builder.Append(" OR ");
}
builder.Append("(");
builder.Append(field.ToString());
builder.Append(" BETWEEN ");
builder.Append(rangeItem);
builder.Append(" AND ");
}
else
{
builder.Append(rangeItem);
builder.Append(") ");
}
i++;
}
if (field.Type == ColumnType.ForeignKey)
{
Query.AddSubQueryWhere(new SqlWhere(builder.ToString()));
}
else
{
$cond = new SqlWhere(builder.ToString());
}
}
}
........ ......
unaryExpression returns [string cons]
: #(UNARY_MINUS conString = constant)
{
$cons = String.Format("-{0}", conString);
}
| #(UNARY_PLUS conString = constant)
{
$cons = conString;
}
| conString = constant
{
$cons = conString;
}
;
// MCK
rangeExpression returns [List<string> row]
@init
{
$row = new List<string>();
}
: ^(RANGE left=unaryExpression right=unaryExpression)
{
$row.Add(left);
$row.Add(right);
}
;
constant returns [string cons]
: ni=INT
{
$cons = ni.Text;
}
| nf=FLOAT
{
$cons = nf.Text;
}
| sl=STRING
{
$cons = "\"" + sl.Text + "\"";
}
| cl=CHAR
{
$cons = cl.Text;
}
;