Библиотека синтаксического анализа файла конфигурации стиля Keyword-Label-Value для C - PullRequest
1 голос
/ 21 марта 2012

Существует ли уже библиотека разбора конфигурации, которая будет считывать следующий стиль файла:

Keyword Label Value;

С вложением по { } с заменой Значения; дополнительные ярлыки; поддержка "Включить" была бы хороша.

Пример файла конфигурации может выглядеть следующим образом:

Listen Inside 127.0.0.1:1000;
Listen Outside {
    IP 1.2.3.4;
    Port 1000;
    TLS {
        CertFile /path/to/file;
    };
};
ACL default_acl {
    IP 192.168.0.0/24;
    IP 10.0.0.0/24;
};

Ответы [ 3 ]

2 голосов
/ 22 марта 2012

С какими языками программирования вы знакомы? Мое впечатление от вашего вопроса - C.

Похоже, что токены вашего языка конфигурации являются регулярными выражениями:

  • Listen
  • 127.0.0.1: 1000
  • 1000
  • ;
  • {
  • }
  • и т.д.

Почти все современные языки программирования имеют некоторую поддержку для них.

Если реализация C, я бы, вероятно, использовал flex. Он генерирует функцию, которая будет применять набор регулярных выражений, помещать соответствующий текст в строку C и возвращать тип этого регулярного выражения (просто int, которое вы выбираете). Функция представляет собой «лексический анализатор» или «токенизатор». Он разбивает потоки символов на удобные единицы, соответствующие вашим потребностям, по одному регулярному выражению за раз.

Flex довольно прост в использовании. Он имеет несколько преимуществ перед lex. Во-первых, у вас может быть несколько функций лексического анализатора, поэтому, если вам нужно сделать что-то странное для включаемого файла, тогда у вас может быть вторая функция лексического анализатора для этой работы.

Ваш язык выглядит просто. Bison / Yacc - очень мощные инструменты, и «с большой силой приходит большая ответственность» :-)

Я думаю, это достаточно просто, чтобы я мог просто написать парсер вручную. Это может быть только несколько функций для управления его структурой. Техника, которая очень проста, называется парсером рекурсивного спуска. Вы получили степень бакалавра или понимаете это?

Множество людей (на данном этапе) скажут вам, чтобы вы получили « Книгу Дракона » или одну из ее более новых версий, часто потому что именно так они поступили в колледже. Книга Дракона великолепна, но это все равно, что сказать кому-то прочитать всю Википедию, чтобы узнать о китах. Отлично, если у вас есть время, и вы многому научитесь.

Разумное начало - статья парсера рекурсивного спуска Wikipedia . Рекурсивный спуск очень популярен, потому что его относительно просто понять. То, что делает это простым, - это иметь правильную грамматику, которая приведена в форму, которую легко проанализировать при рекурсивном спуске. Затем вы буквально пишете функцию для каждого правила с простым механизмом обработки ошибок (вот почему я спросил об этом). Вероятно, есть инструменты для их генерации, но вы могли бы быстрее написать их. Первый разрез может занять один день, тогда вы будете в хорошем положении, чтобы принять решение.

Очень изящная функция lex / flex - любые символы, которые не совпадают, просто выводятся на стандартный вывод. Таким образом, вы можете видеть, что совпадают ваши регулярные выражения, и можете добавлять их постепенно. Когда вывод «иссякает», все сопоставляется.

Предупреждение о понтификации: ИМХО, больше программистов на С должны научиться использовать flex. Он относительно прост в использовании и очень мощный для обработки текста. ИМХО многие откладываются, потому что им также говорят использовать yacc / bison, которые являются гораздо более мощными, тонкими и сложными инструментами. конец понтификации.

Если вам нужна помощь с грамматикой, пожалуйста, спросите. Если есть хорошая грамматика (возможно, это не так, но ваши примеры выглядят хорошо), реализация проста.

Я нашел две ссылки на ответы stackoverflow, которые выглядят полезными:

Вот пример использования flex.

Flex принимает «скрипт» и генерирует функцию C с именем yylex (). Это входной скрипт.

Помните, что все регулярные выражения сопоставляются внутри этой функции yylex, поэтому, хотя скрипт выглядит странно, на самом деле это обычная функция Си. Чтобы сообщить вызывающей стороне, которая будет вашим анализатором рекурсивного спуска, с каким типом регулярного выражения сопоставлено, он возвращает целочисленное значение, которое вы выберете, как и любая обычная функция Си.

Если анализатору нечего рассказать, например, пробел и, возможно, какая-то форма комментария, он не возвращается.Он «молча» поглощает этих персонажей.Если для использования синтаксиса необходимо использовать для использования новой строки, то это будет распознано как токен, и подходящее значение токена будет возвращено парсеру.Иногда проще сделать его более свободным, поэтому этот пример поглощает и игнорирует все пробелы.

Эффективно, функция yylex - это все от первого %% до второго %%.Он ведет себя как большой оператор switch().Регулярные выражения похожи (очень экзотично) на case: ярлыки.Код внутри { ... } является обычным C. Он может содержать любые операторы C и должен быть надлежащим образом вложен в { ... }

Материал перед первым %% - это место для размещения определений flex,и несколько «инструкций» для сгибания.Вещество внутри %{ ... %} является обычным C и может включать в себя любые заголовки, необходимые для C в файле, или даже определять глобальные переменные.

Вещество после второго %% - это обычное C, без необходимостидля дополнительного синтаксиса, поэтому нет %{ ... %].

/* scanner for a configuration files */ 
%{ 
    /* Put headers in here */ 
#include <config.h>

%} 
%%
[0-9]+                  { return TOK_NUMBER; } 
[0-9]+"."[0-9]+"."[0-9]+"."[0-9]+":"[0-9]+ { return TOK_IP_PORT; } 
[0-9]+"."[0-9]+"."[0-9]+"."[0-9]+"/"[0-9]+ { return TOK_IP_RANGE; } 
"Listen"                { return TOK_KEYWORD_LISTEN; } 
[A-Za-z][A-Za-z0-9_]*   { return TOK_IDENTIFIER; }
"{"                     { return TOK_OPEN_BRACE; }
"}"                     { return TOK_CLOSE_BRACE; }
";"                     { return TOK_SEMICOLON; }
[ \t\n]+        /* eat up whitespace, do nothing */ 
.           { fprintf(stderr,  "Unrecognized character: %s\n", yytext ); 
              exit(1); 
            }
%%

/* -------- A simple test ----------- */
int main(int argc, char *argv[])
{ 
    int tok;
    yyin = stdin;
    while (tok=yylex()) {
        fprintf(stderr, "%d %s\n", tok, yytext);
    }
}

Имеет минимальный фиктивный main, который вызывает функцию yylex () для получения значения следующего токена (enum).yytext - строка, совпадающая с регулярным выражением, поэтому main просто печатает ее.

ПРЕДУПРЕЖДЕНИЕ, это едва проверено, чуть больше, чем:

flex config.l
gcc lex.yy.c -ll
./a.out <tinytest

Значения являются целыми числами, поэтомуenum в заголовке:

#ifndef _CONFIG_H_
#define _CONFIG_H_

enum TOKENS { 
 TOK_KEYWORD_LISTEN = 256, 
 TOK_IDENTIFIER = 257, 
 TOK_OPEN_BRACE = 258, 
 TOK_CLOSE_BRACE = 259, 
 TOK_SEMICOLON = 260, 
 TOK_IP_PORT = 261, 
 TOK_IP_RANGE = 262, 
 TOK_NUMBER = 263, 
};
#endif _CONFIG_H_

В вашем парсере вызовите yylex, когда вам понадобится следующее значение.Скорее всего, вы обернете yylex чем-то, что копирует yytext, прежде чем передать значение типа токена обратно в синтаксический анализатор.

Вам понадобится удобная обработка памяти.Если это большой файл, возможно, используйте malloc для выделения места.Но для небольших файлов и для облегчения начала работы и отладки, возможно, имеет смысл написать свой собственный «тупой» распределитель.«Тупая» система управления памятью может значительно облегчить отладку.Изначально просто статически выделите большой массив символов и раздайте кусочки mymalloc ().Я могу представить, что данные конфигурации никогда не получаются свободными () 'd.Сначала все может храниться в C-строках, поэтому отладку просто, потому что точная последовательность ввода находится в массиве char.Усовершенствованная версия может «статировать» файл и выделить достаточно большой фрагмент.

То, как вы справляетесь с фактическими значениями конфигурации, немного выше того, что я могу описать.Текстовые строки могут быть все, что нужно, или, может быть, уже есть механизм для этого.Часто нет необходимости хранить текстовое значение «Ключевые слова», потому что анализатор распознал, что это значит, и программа может преобразовать другие значения, например IP-адреса, в некоторое внутреннее представление.

1 голос
/ 21 марта 2012

Вы смотрели на lex и yacc (или, альтернативно, flex и bison)? Это немного сложно, но мы используем их для анализа файлов, которые выглядят точно так же, как ваш файл конфигурации. Вы можете определять подструктуры, используя скобки, анализировать списки переменной длины с одним и тем же ключом и т. Д.

Под ярлыками вы подразумеваете комментарии? Вы можете определить свою собственную структуру комментариев, мы используем '#' для обозначения строки комментария.

Не поддерживает, включает AFAIK.

0 голосов
/ 21 марта 2012

Существуют библиотеки C для JSON и YAML .Они выглядят так, как вам нужно.

...