парсер с областями действия и условными выражениями - PullRequest
2 голосов
/ 11 июня 2010

Я пишу систему сборки на C / C ++ / ... (я понимаю, что это безумие;)), и у меня возникают проблемы при разработке моего парсера.

Мои "рецепты" выглядят так:

global
{
    SOURCE_DIRS src
    HEADER_DIRS include
    SOURCES bitwise.c \
            framing.c
    HEADERS \
            ogg/os_types.h \
            ogg/ogg.h
}
lib static ogg_static
{         
   NAME ogg
}
lib shared ogg_shared
{
    NAME ogg
}

(это основано на супер простом дереве исходного кода libogg)

# - это комментарии, \ - это "переводы новой строки", что означает, что строка продолжается на следующей строке (см. Синтаксис QMake). {} - это области действия, как в C ++, а глобальные - настройки, которые применяются к каждой «цели». Это все предыстория, а не , которая актуальна ... Я действительно не знаю, как работать со своими прицелами. Мне нужно иметь несколько областей действия, а также форму условной обработки в строках:

win32:DEFINES NO_CRT_SECURE_DEPRECATE

Функция синтаксического анализа должна знать, на каком уровне она находится, и вызывать себя всякий раз, когда она увеличивается. Существует также проблема с расположением скобок (global { или global{ или как в примере).

Как я могу это сделать, используя Standard C ++ и STL? Я понимаю, что это большая работа, и именно поэтому мне нужна хорошая отправная точка. Спасибо!

У меня уже есть целое хранилище ifstream и внутренняя строка / строковый поток, поэтому я могу читать слово за словом.

Ответы [ 4 ]

2 голосов
/ 12 июня 2010

boost::spirit - хороший генератор синтаксического анализатора рекурсивного спуска, который использует шаблоны C ++ в качестве расширения языка для описания синтаксического анализатора и лексера. Он хорошо работает для нативных компиляторов C ++, но не компилируется под Managed C ++.

У Codeproject есть учебная статья , которая может помочь.

2 голосов
/ 12 июня 2010

Я бы предложил (и это более или менее прямо из учебников по компилятору), что вы подходите к проблеме поэтапно.Это ломает вещи так, что проблема становится намного более управляемой на каждой фазе.

Сосредоточьтесь сначала на фазе лексера.Ваша фаза лексизма должна взять необработанный текст и дать вам последовательность токенов, таких как слова и специальные символы.Фаза лексера может заботиться о продолжении строки и обрабатывать пробелы или комментарии в зависимости от ситуации.Обрабатывая пробелы, лексер может упростить задачу вашего синтаксического анализатора: вы можете написать лексер так, чтобы global{, global { и даже

global<br/> {

приводили к двум токенам:один, представляющий global, и другой, представляющий {.

Также обратите внимание, что лексер может прикрепить номера строк и столбцов к токенам для использования позже, если вы нажмете ошибки.

После того, как вы получите хороший поток токенов, приступайте к фазе анализа.Анализатор должен взять эту последовательность токенов и построить абстрактное синтаксическое дерево, которое моделирует синтаксические структуры вашего документа.На этом этапе вам не следует беспокоиться о ifstream и operator>>, поскольку лексер должен был выполнить все это чтение за вас.

Вы указали на заинтересованность в рекурсивном вызове функции синтаксического анализа один разВы видите область.Это, безусловно, один из способов.Как вы увидите, дизайнерское решение, которое вы должны будете неоднократно принимать, заключается в том, хотите ли вы буквально вызывать одну и ту же функцию синтаксического анализа рекурсивно (с учетом конструкций типа global { global { ... } }, которые вы, возможно, захотите запретить синтаксически), или хотите лиопределить немного (или даже значительно) другой набор синтаксических правил, которые применяются внутри области.

Как только вы обнаружите, что вам нужно изменить правила: ключ заключается в повторном использовании, путем рефакторинга в функции, столько вещей, сколькоВы можете повторно использовать различные варианты синтаксиса.Если вы продолжаете двигаться в этом направлении - используя отдельные функции, которые представляют различные фрагменты синтаксиса, с которыми вы хотите иметь дело, и заставляете их вызывать друг друга (возможно, рекурсивно) там, где это необходимо - в конечном итоге вы получите то, что мы называем парсер рекурсивного спуска .У записи Википедии есть хороший простой пример одного;см. http://en.wikipedia.org/wiki/Recursive_descent_parser.

Если вы действительно хотите углубиться в теорию и практику лексеров и синтаксических анализаторов, я рекомендую вам получить хороший твердый учебник по компилятору, который поможет вам.Тема переполнения стека, упомянутая в комментариях выше, поможет вам начать: Обучение написанию компилятора

1 голос
/ 12 июня 2010

ANTLR (используйте ANTLRWorks ), после этого вы можете искать FLEX / BISON и другие, такие как lemon . Существует много инструментов, но ANTLR и flex / bison должно быть достаточно. Мне лично слишком нравится ANTLRWorks, чтобы рекомендовать что-то еще.

ПОЗЖЕ : с помощью ANTLR вы можете генерировать код синтаксического анализатора / лексера для множества языков .

0 голосов
/ 11 июня 2010

Если бы целью проекта не было конкретно научиться писать лексер и синтаксический анализатор смещения-сдвига, я бы порекомендовал использовать Flex и Bison, которые будут выполнять большую часть работы по анализу для вас. Написание грамматического и семантического анализа все равно будет большой работой, не волнуйтесь;)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...