脚本定义

总体说明

在该 DSL 中,脚本由以下三种结构的若干块组成:

  1. CONFIG 块:用于配置全局设置,如大小写敏感与否。

  2. VAR 声明:定义全局变量,可在后续的 RESPONSE 文本中通过占位符 ${varName} 引用。

  3. STATE 块:描述对话状态及其匹配规则(RULE)和兜底规则(DEFAULT)。

脚本的整体外观示例:

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 = falseVAR bankName = "XX银行" 等。

  • { }:用于块结构的开始与结束。

  • 关键字CONFIG, VAR, STATE, RULE, DEFAULT, MATCH, RESPONSE, GOTO

  • 其他保留字:true, false(若启用布尔配置)。

字面量(StringLiteral)

在 DSL 中,字符串使用英文双引号 " 包裹,内部可包含除 " 之外的任意字符。

注释与空白

  • 允许行注释:如 # 这是注释

  • 空白字符(空格、制表符、换行符)一般可在分隔标记的地方任意出现;不影响语义但应被正确忽略或跳过。

语法定义

以下使用 EBNF 的语法规则:

  • 使用 [...] 表示可选内容(0 或 1 次)。

  • 使用 {...} 表示可重复 0 至多次。

  • 使用 | 表示并列可选规则。

  • 使用 (...) 对表达式进行分组。

脚本整体

Script = { ConfigBlock | VarDeclaration | StateBlock } 

Script:一个脚本由零个或多个区块组成,每个区块可以是 ConfigBlockVarDeclarationStateBlock

配置块(CONFIG)

ConfigBlock = "CONFIG" "{" { ConfigLine } "}" ;
ConfigLine  = Ident "=" ConfigValue ;
ConfigValue = Ident | BooleanLiteral | StringLiteral ;
BooleanLiteral = "true" | "false" ;
  • ConfigBlock:以关键字 CONFIG { 开始,以 } 结束,内部由若干行组成(ConfigLine)。

  • ConfigLine:形如 key = value。其中的 value 可以是标识符、布尔值或字符串字面量等(也可扩展为数字等)。

  • BooleanLiteral:定义了 truefalse 两种布尔字面量。

示例:

CONFIG {
    case_sensitive = false
    logLevel = "DEBUG"
}

变量声明(VAR)

VarDeclaration = "VAR" Ident "=" StringLiteral ;
  • VarDeclaration:定义全局可用的变量,例如:VAR bankName = "XX银行"

状态块(STATE)

StateBlock = "STATE" Ident "{" { RuleBlock } [ DefaultBlock ] "}" ;
  • StateBlock:以 STATE <state_name> { ... } 包裹若干规则块和(可选)默认规则块。

  • 其中:

    • Ident 为状态名。

    • 可以包含 0~N 个 RuleBlock,以及最多 1 个 DefaultBlockDEFAULT {})。

规则块(RULE)

RuleBlock = "RULE" Ident "{" RuleContent "}" ;
RuleContent = 
    "MATCH" StringLiteral
    "RESPONSE" StringLiteral
    [ "GOTO" Ident ] ;
  • RuleBlock:以 RULE <rule_name> { ... } 开头,内部必须包含:

    • MATCH:用于指定匹配表达式(可为简单字符串或正则字符串)。

    • RESPONSE:匹配成功后的回复文本。

    • 可选的 GOTO <state_name>:用于跳转到指定的下一个状态。

示例:

RULE greetRule {
    MATCH "你好"
    RESPONSE "您好,我是机器人~"
    GOTO askQuestion
}

默认规则块(DEFAULT)

DefaultBlock = "DEFAULT" "{" DefaultContent "}" ;
DefaultContent =
    "RESPONSE" StringLiteral
    [ "GOTO" Ident ] ;
  • DefaultBlock:以 DEFAULT { ... } 定义当没有任何 RULE 命中时的兜底应答。

  • 内部包含 RESPONSE 字句,且可选 GOTO 进行跳转。

示例:

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] ? ;