编译器定义文件处理技巧总结

83 阅读4分钟

本文档总结了在编写编译器定义文件时使用的处理技巧和设计原则,包括递归处理、运算符优先级处理、模块化和可扩展性、空白符和注释处理以及代码块处理。

1. 递归和组合

1.1 递归规则

递归规则用于处理可以重复出现的语法结构。通过递归,可以轻松处理多个相同类型的语法结构。

示例:

statements -> statement        {% ([statement1]) => statement1 %}
            | statements _ statement {% ([statements1, _2, statement3]) => {
                const result = []
                if (Array.isArray(statements1.statements)) {
                    result.push(...statements1.statements)
                } else {
                    result.push(statements1)
                }
                result.push(statement3)
                return {
                    type: "statements",
                    statements: result
                }
            } %}
  • 递归组合statements 规则通过递归组合多个 statement,形成一个语句序列。
  • 数组组合:通过递归组合,将多个 statement 组合成一个数组。

1.2 递归组合模块导入和定义

import_defineMod -> importMod {% id %}
                 |  defineMod {% id %}
                 |  import_defineMod _ importMod {% ([import_defineMod1, _2, importMod3]) => {
                    const result = []
                    if(Array.isArray(import_defineMod1)) {
                        result.push(...import_defineMod1)
                    } else {
                        result.push(import_defineMod1)
                    }
                    result.push(importMod3)
                    return result
                 } %}
                 |  import_defineMod _ defineMod {% ([import_defineMod1, _2, defineMod3]) => {
                    const result = []
                    if(Array.isArray(import_defineMod1)) {
                        result.push(...import_defineMod1)
                    } else {
                        result.push(import_defineMod1)
                    }
                    result.push(defineMod3)
                    return result
                 } %}
  • 递归组合import_defineMod 规则通过递归组合多个 importMod 或 defineMod,形成一个模块导入和定义的序列。
  • 数组组合:通过递归组合,将多个 importMod 或 defineMod 组合成一个数组。

2. 运算符优先级

通过定义不同的非终结符来处理运算符的优先级,确保运算符的优先级和结合性正确。

示例:

expression -> term (_ ("+" | "-") _ term):* {% ([term1, optional2]) => {
                optional2 = [...optional2];
                return optional2.reduce((acc, [_1, opkw2, _3, term4])=> {
                    return {
                        type: 'op',
                        opkw: opkw2,
                        left: acc,
                        right: term4
                    }
                }, term1)
            } %}

term -> factor (_ ("*" | "/") _ factor):* {% ([factor1, optional2]) => {
            optional2 = [...optional2];
            return optional2.reduce((acc,[_1, opkw2, _3, factor4])=> {
                return {
                    type: 'op',
                    opkw: opkw2,
                    left: acc,
                    right: factor4
                }
            }, factor1)
        } %}
  • 分层处理:通过定义不同的非终结符(expression 和 term)来处理运算符的优先级。
  • 递归组合:通过递归组合,将多个运算符和操作数组合成一个表达式。

3. 模块化和可扩展性

3.1 模块化规则

将不同的语法结构(如 importModdefineModassignStatement 等)定义为独立的规则,便于管理和扩展。

示例:

importMod -> "import" _ "{" _ ident _ "}" 
            {% ([import1, _2, lbrace3, _4, ident5, _6, rbrace7])=>{
                return {
                    type: "importStatement",
                    modName: ident5.value,
                    line: ident5.line,
                    col: ident5.col
                }
            } %}

defineMod -> "mod" _ ident 
            {% ([mod1, _2, ident3]) => {
                return {
                    type: "defineModStatement",
                    modName: ident3.value,
                    line: ident3.line,
                    col: ident3.col
                }
            } %}
  • 独立规则importMod 和 defineMod 规则是独立的,便于管理和扩展。

3.2 组合规则

通过组合规则(如 program 和 import_defineMod)来处理复杂的语法结构。

示例:

program -> _ statements _ {% ([_1, statements2, _3]) => statements2 %}
program -> _ codeblock _ {% ([_1, codeblock2, _3]) => codeblock2 %}
program -> _ import_defineMod _ {% ([_1, codeblock2, _3]) => codeblock2 %}
program -> _ import_defineMod _ codeblock _ {% ([_1, import_defineMod2, _3, codeblock4]) => [import_defineMod2, codeblock4] %}
program -> _ import_defineMod _ statements _ {% ([_1, import_defineMod2, _3, statements4]) => [import_defineMod2, statements4] %}
  • 组合规则program 规则通过组合 statementscodeblock 和 import_defineMod 来处理复杂的语法结构。

4. 空白符和注释处理

使用 _ 规则来处理空白符和注释,避免在语法规则中显式处理空白符。

示例:

nearley

复制

_ -> WS {% () => null %}
_ -> NL {% () => null %}
_ -> Comment {% () => null %}
__ -> WS WS {% () => null %}
  • 空白符处理:使用 _ 规则来处理空白符和注释,避免在语法规则中显式处理空白符。

5. 代码块

定义代码块规则,用于处理由大括号包围的语句序列。

示例:

codeblock -> "{" _ statements _ "}" {% ([lbrace1, _2, statements3, _4, rbrace5]) => {
    return {
        type: "codeblock",
        statements: statements3
    }
} %}
  • 代码块codeblock 规则匹配一个代码块,即由大括号包围的 statements

6. 关键字和符号声明

在 moo 中声明关键字和符号,确保在 nearley 和 moo 配合处理时能够正确识别 token。

示例:

const moo = require('moo')
const lexer = moo.compile({
    eq: '=',
    lb: '{', rb: '}',
    lp: '(', rp: ')',
    plus: '+', sub: '-', multi: '*', divide: '/', 
    Number: /-?[0-9]+(?:.[0-9]+)?/,
    Identifier: {
        match: /[a-zA-Z_][a-zA-Z0-9_]*/,
        type: moo.keywords({
            KW: ['mod', 'import', 'const'],
        })},
    WS: /[ \t]/,
    SPACE: {match: /\s+/, lineBreaks: true},
    NL: { match: /\n/, lineBreaks: true },
})
  • 关键字声明:使用 moo.keywords 来声明关键字,如 modimportconst
  • 符号声明:声明符号如 {}+-*/ 等。

总结

在你的编译器定义文件中,展示了多种语法规则的处理技巧:

  • 递归和组合:通过递归规则和数组组合,处理多个相同类型的语法结构。
  • 运算符优先级:通过定义不同的非终结符来处理运算符的优先级。
  • 模块化和可扩展性:将不同的语法结构定义为独立的规则,并通过组合规则处理复杂的语法结构。
  • 空白符和注释处理:使用 _ 规则来处理空白符和注释,避免在语法规则中显式处理空白符。
  • 代码块:定义代码块规则,用于处理由大括号包围的语句序列。
  • 关键字和符号声明:在 moo 中声明关键字和符号,确保在 nearley 和 moo 配合处理时能够正确识别 token。

这些技巧使得你的编译器定义文件结构清晰、易于扩展和维护。