Token Parser

一个直观的 Token Parser,包含语法/文法定义、词法分析和语法分析。

特点

  • 词法分析
  • 解析
  • 语法/文法定义

入门

dart pub add token_parser

并导入该包

import 'package:token_parser/token_parser.dart';

用法

词法分析过程分为三个步骤

  1. 语法/文法定义
  2. 词法分析
  3. 解析

下面将简要介绍每个步骤。

语法/文法定义

语法/文法定义是通过定义每个 token 必须具有的属性来完成的。

token 代表一个表达式,然后可以在其他 token 中使用它来构成一个文法。

final abc = 'a' | 'b' | 'c';
final def = 'd' | 'e' | 'f';

final expression = abc & def;

使用 & 运算符将 token 组合为“与”关系,使用 | 运算符将 token 组合为“或”关系,我们可以定义一个可以接受 token abcdef 的任意组合的表达式。

token 可以扩展以具有略微不同的属性

final abc = ('a' | 'b' | 'c').multiple;

final expression = abc & 'd'.optional;

为了方便起见,可以使用正则表达式定义 token

final digit = '[0-9]'.regex;
final number = digit.multiple & ('.' & digit.multiple).optional;

final letter = '[a-zA-Z]'.regex;
final word = letter.multiple;
final phrase = word & ((' ' & word).multiple).optional;

词法分析

任何 token

解析

final abc = 'a' | 'b' | 'c' | Token.reference('def');
final def = ('d' | 'e' | 'f') & Token.self();

final parser = TokenParser(
  main: phrase | number,
  token: {
    'digit': digit,
    'number': number,

    'letter': letter,
    'word': word,
    'phrase': phrase,

    'abc': 'a' | 'b' | 'c',
    'def': 'd' | 'e' | 'f',
  },
);

final parser = TokenParser();

parser.add('digit', digit);
parser.add( ... );

parser.addMain(phrase | number);

parser.parse('123');
parser.parse('123.456');

parser.parse('word');
parser.parse('two words');

final match = parser.parse('two words');

final words = match?.get(word);
final letters = match?.get(letter);

print('Words: ${ words?.map((match) => match.value) }');
print('Letters: ${ letters?.get(letter).map((match) => match.value) }');
  • match.children
  • match.get(token)
  • match.getNamed('name')

示例

词法分析 (example/main.dart)

import 'package:token_parser/token_parser.dart';

void main() {
  final whitespace = ' ' | '\t';
  final lineBreak = '\n' | '\r';
  final space = (whitespace | lineBreak).multiple;

  final letter = '[a-zA-Z]'.regex;
  final digit = '[0-9]'.regex;

  final identifier = letter & (letter | digit).multiple.optional;
  
  final number = digit.multiple & ('.' & digit.multiple).optional;
  final string = '"' & '[^"]*'.regex & '"'
               | "'" & "[^']*".regex & "'";

  final variableDeclaration =
    'var' & space & identifier & space.optional & '=' & space.optional & (number | string) & space.optional & (';' | space);

  final parser = TokenParser(
    main: (variableDeclaration | space).multiple,
    tokens: {
      'whitespace': whitespace,
      'lineBreak': lineBreak,
      'space': space,

      'letter': letter,
      'digit': digit,

      'identifier': identifier,

      'number': number,
      'string': string,

      'variableDeclaration': variableDeclaration,
    },
  );

  final match = parser.parse('''
    var hello = "world";
    var foo = 123;
    var bar = 123.456;
  ''');
  
  final numbers = match?.get(number).map((match) => match.group(0));
  final identifiers = match?.get(identifier).map((match) => '"${ match.group(0) }"');

  print('Numbers: $numbers');
  print('Identifiers: $identifiers');
}
引用 (example/reference.dart)

import 'package:token_parser/token_parser.dart';

void main() {
  final expression = 'a' & Token.reference('characterB').optional;
  final characterB = 'b'.token();

  final recursive = 'a' & Token.self().optional;

  final parser = TokenParser(
    main: expression,
    tokens: {
      'expression': expression,
      'characterB': characterB,
      
      'recursive': recursive,
    }
  );

  print(parser.parse('ab')?.get(characterB));
  print(parser.parse('aaa', recursive)?.get(recursive));
}

GitHub

查看 Github