我们一般的做法是使用正则表达来做这个事情,以 Python 为例,系统提供的 API 我们可以看做分三步走:
1 2 3 4 5
import re
pattern = "^([0-9])-([0-9]+)$" // 1. write regex string of phone number prog = re.compile(pattern) // 2. compile regex to a matcher result = prog.match(string) // 3. match string and handle results
# Expression Expression -> AddSubExpression {% id %}
# Expression for Add Sub AddSubExpression -> AddSubExpression _ "+" _ MulDivExpression {% d => buildAssignmentExpression(d) %} | AddSubExpression _ "-" _ MulDivExpression {% d => buildAssignmentExpression(d) %} | MulDivExpression {% id %}
# Expression for Mul Div MulDivExpression -> Identifier _ "*" _ MulDivExpression {% d => buildAssignmentExpression(d) %} | Identifier _ "/" _ MulDivExpression {% d => buildAssignmentExpression(d) %}
| Value _ "*" _ MulDivExpression {% d => buildAssignmentExpression(d) %} | Value _ "/" _ MulDivExpression {% d => buildAssignmentExpression(d) %} | Value {% id %} | Identifier {% id %}
| Value _ "*" _ MulDivExpression {% d => buildAssignmentExpression(d) %} | Value _ "/" _ MulDivExpression {% d => buildAssignmentExpression(d) %} | Value {% id %} | Identifier {% id %}
Nearley 里面 | 这个运算符其实是个语法糖,上面的产生式其实可以表示成多条产生式:
1 2 3 4 5 6
MulDivExpression -> Identifier _ "*" _ MulDivExpression {% d => buildAssignmentExpression(d) %} MulDivExpression -> Identifier _ "/" _ MulDivExpression {% d => buildAssignmentExpression(d) %} MulDivExpression -> Value _ "*" _ MulDivExpression {% d => buildAssignmentExpression(d) %} MulDivExpression -> Value _ "/" _ MulDivExpression {% d => buildAssignmentExpression(d) %} MulDivExpression -> Value {% id %} MulDivExpression -> Identifier {% id %}
在介绍每一个产生式之前,我们先介绍两个概念:
符号:它代表代码某一部分,例如 if 语句 if (...) { ... } 整一块可以看做是一个符号,字符串 "123" 可以看做是一个符号,符号是一个递归的概念,符号可以包含其他符号。例如 if (...) { a = "123" } 这个 “if” 符号包含了字符串符号 "123"。
ExpOr -> ExpOr __ "or" __ ExpAnd {% d => buildExpression(d) %} | ExpAnd {% id %}
ExpAnd -> ExpAnd __ "and" __ ExpComparison {% d => buildExpression(d) %} | ExpComparison {% id %}
ExpComparison -> Name _ "<" _ Value {% d => buildExpression(d) %} | Name _ ">" _ Value {% d => buildExpression(d) %} | Name _ "<=" _ Value {% d => buildExpression(d) %} | Name _ ">=" _ Value {% d => buildExpression(d) %} | Name _ "~=" _ Value {% d => buildExpression(d) %} | Name _ "==" _ Value {% d => buildExpression(d) %}
type Identifier = { type: "Identifier", name: string }
type Value = { type: "Value", value: number | string }
export default function __eval(ast: Expression, _: any) {
function evalExpression(expression: Expression) { switch (expression.op) { case "or": return _.or([ evalExpression((expression as any).left), evalExpression((expression as any).right), ]); break; case "and": return _.and([ evalExpression((expression as any).left), evalExpression((expression as any).right), ]); break; case "<": return { [(expression as any).left.name]: _.lt((expression as any).right.value) } break; case ">": return { [(expression as any).left.name]: _.gt((expression as any).right.value) } break; case ">=": return { [(expression as any).left.name]: _.gte((expression as any).right.value) } break; case "<=": return { [(expression as any).left.name]: _.lte((expression as any).right.value) } break; case "~=": return { [(expression as any).left.name]: _.neq((expression as any).right.value) } break; case "==": return { [(expression as any).left.name]: _.eq((expression as any).right.value) } break; default: throw new Error("invalid expression"); break; } }