World Conquest Chronicles

World Conquest Chronicles

Wizard Parser, v1.0

Пример AST-дерева

LL(*)-парсер на C++ с поддержкой DSL для описания грамматики в EBNF непосредственно в коде программы.

Мажорный релиз.

Возможности

  • парсинг ASCII-текста;
  • описание грамматики на EBNF непосредственно в коде программы (посредством DSL);
  • представление результата в виде:
    • дерева парсинга;
    • AST;
  • гибкое управление представлением нод в AST:
    • задание имени ноды;
    • объединение нод;
    • скрытие ноды;
  • сериализация AST в XML;
  • поддержка полноценной грамматики в качестве разделителя для основной;
  • комбинаторы:
    • следование;
    • альтернатива;
    • повторение:
      • 0 или больше раз;
      • 1 или больше раз;
    • опциональность;
    • исключение;
    • список с разделителем;
  • парсеры:
    • пустой (ничего не парсит);
    • граница слова (правило \b в регулярных выражениях);
    • конец текста;
    • парсеры символов:
      • парсер определённого символа;
      • парсер любого символа;
      • парсеры любого символа из определённого набора:
        • парсер любого символа из определённого набора;
        • парсер пробельных символов;
        • парсер букв;
        • парсер цифр;
        • парсер букв, цифр и символа _;
    • парсеры определённого текста:
      • парсер определённого текста;
      • парсер определённого текста, ограниченного границами слова (правило \b в регулярных выражениях).

Пример использования

#include <wizard_parser/parser/Parser.h>
#include <cstring>
#include <iostream>

using namespace thewizardplusplus::wizard_parser::parser;

/* Grammar description in EBNF:
 *
 * expression = disjunction;
 * disjunction = conjunction, {"or", conjunction};
 * conjunction = equality, {"and", equality};
 * equality = comparison, {("==" | "/="), comparison};
 * comparison = sum, {("<" | "<=" | ">" | ">="), sum};
 * sum = product, {("+" | "-"), product};
 * product = unary, {("*" | "/"), unary};
 * unary = {"-" | "not"}, atom;
 * atom = number | ("(", expression, ")");
 * number = ? /\d+(\.\d+)?/ ?;
 */
Parser grammar(void) {
    const auto expression = dummy();

    WP_RULE(number)
        disable_separation(lexeme(+digit() >> !('.'_s >> +digit())))
    WP_END
    WP_RULE(atom) number | hide('('_s) >> expression >> hide(')'_s) WP_END
    WP_RULE(unary) *('-'_s | word("not"_t)) >> atom WP_END
    WP_RULE(product) list(unary, '*'_s | '/'_s) WP_END
    WP_RULE(sum) list(product, '+'_s | '-'_s) WP_END
    WP_RULE(comparison) list(sum, '<'_s | "<="_t | '>'_s | ">="_t) WP_END
    WP_RULE(equality) list(comparison, "=="_t | "/="_t) WP_END
    WP_RULE(conjunction) list(equality, hide(word("and"_t))) WP_END
    WP_RULE(disjunction) list(conjunction, hide(word("or"_t))) WP_END
    assign(expression, disjunction);

    const auto grammar = expression >> end();
    const auto separator = hide(*space());
    return separation(separator, grammar);
}

int main(int number_of_arguments, char* arguments[]) try {
    if (number_of_arguments == 1 || std::strlen(arguments[1]) == 0) {
        throw std::invalid_argument("expression not specified");
    }

    const auto expression = arguments[1];
    const auto parser = grammar();
    std::cout
        << "<?xml version = \"1.0\" encoding = \"utf-8\" ?>"
        << parse(parser, expression, SimplifyLevel::AST)
        << "\n";
} catch (std::exception& exception) {
    std::cerr << "Error: \"" << exception.what() << "\".\n";
    std::exit(EXIT_FAILURE);
}

Репозиторий

Ссылка: https://github.com/thewizardplusplus/wizard-parser/tree/v1.0.

Содержание: код, документация, пример использования.

Лицензия: MIT.