# 脚本定义 ## 总体说明 在该 DSL 中,脚本由以下**三种结构**的若干块组成: 1. **CONFIG 块**:用于配置全局设置,如大小写敏感与否。 2. **VAR 声明**:定义全局变量,可在后续的 `RESPONSE` 文本中通过占位符 `${varName}` 引用。 3. **STATE 块**:描述对话状态及其匹配规则(`RULE`)和兜底规则(`DEFAULT`)。 脚本的整体外观示例: ```python CONFIG { case_sensitive = false } VAR bankName = "XX银行" STATE greeting { RULE greetRule { MATCH "你好" RESPONSE "您好,这里是${bankName}智能客服,请问有什么可以帮您?" GOTO askQuestion } DEFAULT { RESPONSE "抱歉,我没有听清。您可以说'你好'来开始咨询。" } } STATE askQuestion { RULE loan { MATCH "贷款" RESPONSE "好的,您想了解哪方面的贷款业务呢?" GOTO loanState } DEFAULT { RESPONSE "如果想咨询贷款业务,请说'贷款';如果咨询信用卡,请说'信用卡'。" } } ``` ## 词法定义 ### 标识符(Identifier, Ident) * 使用以下正则描述: $$ ident::=[A−Za−z][A−Za−z0−9]∗ $$ * 例如:`greeting`, `askQuestion`, `bankName`, `greetRule` 等。 ### 赋值与操作符 * `=`:用于配置或变量赋值,如 `case_sensitive = false`,`VAR bankName = "XX银行"` 等。 * `{` `}`:用于块结构的开始与结束。 * **关键字**:`CONFIG`, `VAR`, `STATE`, `RULE`, `DEFAULT`, `MATCH`, `RESPONSE`, `GOTO`。 * 其他保留字:`true`, `false`(若启用布尔配置)。 ### 字面量(StringLiteral) 在 DSL 中,**字符串**使用英文双引号 `"` 包裹,内部可包含除 `"` 之外的任意字符。 ### 注释与空白 * 允许行注释:如 `# 这是注释`。 * 空白字符(空格、制表符、换行符)一般可在**分隔标记的地方**任意出现;不影响语义但应被正确忽略或跳过。 ## 语法定义 以下使用 EBNF 的语法规则: * 使用 `[...]` 表示可选内容(0 或 1 次)。 * 使用 `{...}` 表示可重复 0 至多次。 * 使用 `|` 表示并列可选规则。 * 使用 `(...)` 对表达式进行分组。 ### 脚本整体 ``` Script = { ConfigBlock | VarDeclaration | StateBlock } ``` **Script**:一个脚本由零个或多个区块组成,每个区块可以是 `ConfigBlock`、`VarDeclaration` 或 `StateBlock`。 ### 配置块(CONFIG) ``` ConfigBlock = "CONFIG" "{" { ConfigLine } "}" ; ConfigLine = Ident "=" ConfigValue ; ConfigValue = Ident | BooleanLiteral | StringLiteral ; BooleanLiteral = "true" | "false" ; ``` * **ConfigBlock**:以关键字 `CONFIG {` 开始,以 `}` 结束,内部由若干行组成(`ConfigLine`)。 * **ConfigLine**:形如 `key = value`。其中的 `value` 可以是标识符、布尔值或字符串字面量等(也可扩展为数字等)。 * **BooleanLiteral**:定义了 `true` 或 `false` 两种布尔字面量。 示例: ``` CONFIG { case_sensitive = false logLevel = "DEBUG" } ``` ### 变量声明(VAR) ``` VarDeclaration = "VAR" Ident "=" StringLiteral ; ``` * **VarDeclaration**:定义全局可用的变量,例如:`VAR bankName = "XX银行"` ### 状态块(STATE) ``` StateBlock = "STATE" Ident "{" { RuleBlock } [ DefaultBlock ] "}" ; ``` * **StateBlock**:以 `STATE { ... }` 包裹若干规则块和(可选)默认规则块。 * 其中: * `Ident` 为状态名。 * 可以包含 0\~N 个 `RuleBlock`,以及最多 1 个 `DefaultBlock`(`DEFAULT {}`)。 #### 规则块(RULE) ``` RuleBlock = "RULE" Ident "{" RuleContent "}" ; RuleContent = "MATCH" StringLiteral "RESPONSE" StringLiteral [ "GOTO" Ident ] ; ``` * **RuleBlock**:以 `RULE { ... }` 开头,内部必须包含: * `MATCH`:用于指定匹配表达式(可为简单字符串或正则字符串)。 * `RESPONSE`:匹配成功后的回复文本。 * 可选的 `GOTO `:用于跳转到指定的下一个状态。 示例: ``` RULE greetRule { MATCH "你好" RESPONSE "您好,我是机器人~" GOTO askQuestion } ``` #### 默认规则块(DEFAULT) ``` DefaultBlock = "DEFAULT" "{" DefaultContent "}" ; DefaultContent = "RESPONSE" StringLiteral [ "GOTO" Ident ] ; ``` * **DefaultBlock**:以 `DEFAULT { ... }` 定义当没有任何 `RULE` 命中时的兜底应答。 * 内部包含 `RESPONSE` 字句,且可选 `GOTO` 进行跳转。 示例: ```dsl DEFAULT { RESPONSE "抱歉,我没有听清。请再说一次。" } ``` ## 综合 EBNF 描述 ``` Script = { ( ConfigBlock | VarDeclaration | StateBlock ) } ; ConfigBlock = "CONFIG" "{" { ConfigLine } "}" ; ConfigLine = Ident "=" ConfigValue ; ConfigValue = Ident | BooleanLiteral | StringLiteral | NumberLiteral BooleanLiteral = "true" | "false" ; VarDeclaration = "VAR" Ident "=" StringLiteral ; StateBlock = "STATE" Ident "{" { RuleBlock } [ DefaultBlock ] "}" ; RuleBlock = "RULE" Ident "{" RuleContent "}" ; RuleContent = "MATCH" StringLiteral "RESPONSE" StringLiteral [ "GOTO" Ident ] ; DefaultBlock = "DEFAULT" "{" DefaultContent "}" ; DefaultContent = "RESPONSE" StringLiteral [ "GOTO" Ident ] ; // --- Lexical tokens --- Ident = ? [A-Za-z_] [A-Za-z0-9_]* ? ; StringLiteral = ? '"' ( '\\"' | [^"] )* '"' ? ; NumberLiteral = ? Digit+ ( '.' Digit+ )? ? ; Digit = ? [0-9] ? ; ```