Lua lpeg解析一阶逻辑项

Lua lpeg解析一阶逻辑项,lua,peg,first-order-logic,lpeg,Lua,Peg,First Order Logic,Lpeg,正如标题所说,我正在尝试解析例如 term(A, b, c(d, "e", 7)) 在一张像Lua一样的桌子上 {term, {A, b, {c, {d, "e", 7}}}} 这是我建立的语法: local pattern = re.compile[=[ term <- variable / function argument <- variable / lowercase /number / string function <- {|lower

正如标题所说,我正在尝试解析例如

term(A, b, c(d, "e", 7))
在一张像Lua一样的桌子上

{term, {A, b, {c, {d, "e", 7}}}}
这是我建立的语法:

local pattern = re.compile[=[
  term      <- variable / function
  argument  <- variable / lowercase /number / string
  function  <- {|lowercase {|(open argument (separator (argument / function))* close)?|}|}
  variable  <- uppercase
  lowercase <- {[a-z][A-Za-z0-9]*}
  uppercase <- {[A-Z][A-Za-z0-9]*}
  string    <- '"' {~ [^"]* ~} '"'
  number    <- {[0-9]+}
  close     <- blank ")"
  open      <- "(" blank
  separator <- blank "," blank
  blank     <- " "*
]=]
local pattern=re.compile[=[

term对不起,我没有LPeg方面的经验,但通常的Lua模式足以轻松解决您的任务:

local str = 'term(A, b, c(d, "e", 7))'

local function convert(expr)
    return (expr:gsub('(%w+)(%b())',
        function (name, par_expr)
            return '{'..name..', {'..convert(par_expr:sub(2, -2))..'}}'
        end
    ))
end

print(convert(str))  -- {term, {A, b, {c, {d, "e", 7}}}}

现在只需
load()
转换字符串来创建一个表。

在语法中,您有:

argument  <- variable / lowercase /number / string
function  <- {|lowercase {|(open argument (separator (argument / function))* close)?|}|}
自从您的代码>变量< /> >非终结符被列在代码>函数< /> >之前,LPEG不考虑后者,因此它停止解析随后出现的令牌。

作为一个实验,我稍微修改了您的语法,并为您感兴趣的大多数非终端添加了一些表和命名捕获

local pattern = re.compile
[=[
  term      <- {| {:type: '' -> "term" :} term_t |}
  term_t    <- func / var
  func      <- {| {:type: '' -> "func":} {:name: func_id:} "(" arg(separator arg)* ")" |}
  func_id   <- lower / upper
  arg       <- number / string / term_t
  var       <- {| {:type: '' -> "var" :} {:name: lower / upper:} |}
  string    <- '"' {~ [^"]* ~} '"'
  lower <- {%l%w*}
  upper <- {%u%w*}
  number    <- {%d+}
  separator <- blank "," blank
  blank     <- " "*
]=]
这将在我的机器上提供以下输出:

{
  {
    {
      type = "var",
      name = "A"
    },
    {
      type = "var",
      name = "b"
    },
    {
      {
        "42",
        type = "func",
        name = "d"
      },
      "e",
      {
        type = "var",
        name = "f"
      },
      "7",
      type = "func",
      name = "c"
    },
    type = "func",
    name = "fun"
  },
  type = "term"
}
仔细查看上面的内容,您会注意到函数参数按照传入的顺序出现在表的索引部分。
type
name
可以以任何顺序出现,因为它位于表的关联部分。您可以包装这些“属性”并将该内部属性表放在外部表的索引部分

编辑:这里有一个修改过的语法,使解析更加统一。我删除了
术语
捕获,以帮助修剪一些不必要的分支

local pattern2 = re.compile
[=[
  term      <- term_t
  term_t    <- func / var
  func      <- {| {:type: '' -> "func":} {:name: func_id:} "(" args? ")" |}
  func_id   <- lower / upper
  arg       <- number / string / term_t
  args      <- arg (separator args)?
  var       <- {| {:type: '' -> "var" :} {:name: lower / upper:} |}
  string    <- {| {:type: '' -> "string" :}'"' {:value: [^"]* :} '"' |}
  lower     <- {%l%w*}
  upper     <- {%u%w*}
  number    <- {| {:type: '' -> "number":} {:value: %d+:} |}
  separator <- blank "," blank
  blank     <- " "*
]=]

非常感谢!Pegs让我有点困惑。我将采用您的语法并从那里继续。有没有办法获得类似->的内容@キキジキ 你的意思是给
术语
分支起一个名字?这可能是通过某种方式调整语法来实现的。注意,语法当前的定义方式,
fun
被解析为一个函数,因此它是
术语
的子项。
术语
本身在这里实际上没有名字。
术语
应该取什么名字开?它应该偷第一个孩子的名字吗?如果那个孩子没有名字怎么办@キキジキ 另一个想法是将
术语
捕获完全去掉。在这种情况下,AST中只剩下函数、变量和其他原始终端,如数字、字符串等。这可能没问题,因为它看起来不像
术语
在示例中真正添加了任何其他信息。我希望有更多的uniform元素。在“c”中,“e”和“7”看起来是这样的,但d和f是表。我想做的是,每个元素都表示为相同的。例如,由于“42”是“d”的参数,所以应该有一个带有名称和类型的d表,然后是一个带有参数列表的嵌套表,如{d,{42}。带有类型和名称标签,应该是{name=“d”,type=“fun”,“{{name=“42”,type=“num”}}}。如果type和name位于指定的索引,比如{fun,d{num,42}}},也可以。关于term,我碰巧称它为“term”但它可以是其他的东西。太好了!谢谢你花时间回答我的问题。嗯,你是对的,这是一个非常好的解决方案!如果我找到一种方法使pegs工作,我可以获得更多的数据(比如元素的类型),并最终将其扩展为添加运算符,但如果太复杂,我可能会使用你的解决方案。
{
  {
    {
      type = "var",
      name = "A"
    },
    {
      type = "var",
      name = "b"
    },
    {
      {
        "42",
        type = "func",
        name = "d"
      },
      "e",
      {
        type = "var",
        name = "f"
      },
      "7",
      type = "func",
      name = "c"
    },
    type = "func",
    name = "fun"
  },
  type = "term"
}
local pattern2 = re.compile
[=[
  term      <- term_t
  term_t    <- func / var
  func      <- {| {:type: '' -> "func":} {:name: func_id:} "(" args? ")" |}
  func_id   <- lower / upper
  arg       <- number / string / term_t
  args      <- arg (separator args)?
  var       <- {| {:type: '' -> "var" :} {:name: lower / upper:} |}
  string    <- {| {:type: '' -> "string" :}'"' {:value: [^"]* :} '"' |}
  lower     <- {%l%w*}
  upper     <- {%u%w*}
  number    <- {| {:type: '' -> "number":} {:value: %d+:} |}
  separator <- blank "," blank
  blank     <- " "*
]=]
{
  {
    type = "var",
    name = "A"
  },
  {
    type = "var",
    name = "b"
  },
  {
    {
      {
        type = "number",
        value = "42"
      },
      type = "func",
      name = "d"
    },
    {
      type = "string",
      value = "e"
    },
    {
      type = "var",
      name = "f"
    },
    {
      type = "number",
      value = "7"
    },
    type = "func",
    name = "c"
  },
  type = "func",
  name = "fun"
}