仅用于SELECT语句的SQL引擎 - 用c ++编写的手写解析器

时间:2010-10-11 06:51:35

标签: c++ sql parsing

我是编译器的新手,但我得到了一个项目SQL引擎 - 仅用于select语句。为此,我必须只使用手写的解析器和引擎。我研究了LL(k)语法和递归下降技术的样本(由stackoverflow建议用于手动编写解析器)。但是在任何一个样本中,都没有找到从函数构造解析树的方法。
你们中的任何人都可以告诉我,如何一步一步地完成整个编译过程,只需要 “从表中选择columnname1,columnname2”示例。还有一件事 - 升级库也是不允许的。数据在内存中。我使用结构存储数据。提前谢谢。

2 个答案:

答案 0 :(得分:0)

我想说更简单的方法是将其作为编译器处理:

  • 标记化
  • 解析(创建AST)

标记化是关于识别“单词”,对于你的例子,这给出了:

"Select", "columnname1", ",", "columnanme2", "from", "table"

解析是将这个令牌列表解释为抽象语法树。鉴于您的要求:

  • 第一个令牌应为“select”(不区分大小写)
  • 后面可以跟“*”或以逗号分隔的列名列表
  • “from”(不区分大小写)标记列表的结尾
  • 后面是表名

我将在Python中概述这个

class Select:
  def __init__(self):
    self.columnList = None
    self.tableName = None

def Tokenize(statement):
  result = []
  for word in statement.split(" "):
    sub = word.split(",")             # the comma may not be separated by space
    for i in range(len(sub)-1):
      result.append(sub[i].lower())   # case insensitive
      result.append(",")
    result.append(sub[-1])
  return result

def CreateSelect(tokens):
  if len(tokens) == 0: raise NoToken()
  if tokens[0] != "select": raise NotASelectStatement()

  select = Select()

  i = 1
  while tokens[i] != "from":
    if tokens[i] == "*":
      select.columnList == ALL
      break
    else:
      select.columnList.append(tokens[i])
      i = i + 1
      if tokens[i] != ",": raise ExpectedComma(i)
      i = i + 1

   select.tableName = tokens[i+1]

当然,正如您所知,这是一个有限的例子:

  • 不考虑多个表格
  • 不考虑别名
  • 不考虑嵌套的select语句

然而它运作良好且效率很高。如果我们将标记化和解析阶段结合起来,它通常会更有效率,但我发现它通常只会使代码更难以阅读。

另请注意,正确的错误报告会更好:

  • 不要更改令牌(.lower()),只是使用不区分大小写的比较
  • 将每个令牌(行/列)的正确源位置连接起来,以便能够将用户指向正确的位置

修改

使用一个不那么人为的例子,A​​ST会是什么样子?

"select foo, bar from FooBar where category = 'example' and id < 500;"

我们走吧:

Select
|_ Columns (foo, bar)
|_ Table (FooBar)
\_ Where
   \_ And
      |_ Equal (category, 'example')
      \_ LessThan (id, 500)

这里有一个树状结构,这就是你想要产生的结构。

答案 1 :(得分:0)

您可能还会在网上找到BNF grammars for SQL 92, 99 and 2003,这可能很方便。

这些是完整的语法,但不应该仅仅难以隔离SELECT分支。

另外,您可以在http://www.antlr.org/grammar/list探索已有的语法;那里有一些SQL风格。