IMHO.WS

IMHO.WS (http://www.imho.ws/index.php)
-   Программирование (http://www.imho.ws/forumdisplay.php?f=40)
-   -   Ищу парсер ? (http://www.imho.ws/showthread.php?t=117913)

crawler 12.04.2007 16:24

Ищу парсер ?
 
Задача: чтение INI-подобного файла. С поддержкой простых макросов. Например:
Код:

baseDir = c:\work
resultDir = $(baseDir)\result

То есть переменная resultDir в результате получит значение c:\work\result
Основное требование к синтаксису - чтобы создвать такие ini-файлы было удобно и просто. Код должен быть на С/С++.

Я понял что XML дает похожие возможности, но с ним не знаком, поэтому если это возможно сделать с XML - давайте примеры.

Drakosha 12.04.2007 18:59

по моему xml тут не причем. Трудно поверить что есть ТОЧНО такой готовый парсер. Поэтому, http://en.wikipedia.org/wiki/Yacc и вперед...

crawler 12.04.2007 19:18

Проблема в том, что я не особо программер, а тут нужен кто-то, кто имел хотя бы небольшой опыт с парсерами. Мне не сильно важен синтакс, мне нужна функционaльность

Код:

[Common]
BaseDir = c:\base
ResultDir = $(BaseDir)\result
[Start]
inputFile =  $(BaseDir)\input.txt
outputFile = $(ResultDir)\start_out.txt
[Continue]
inputFile = $([Start]outputFile)
outputFile = $(ResultDir)\cont_out.txt

и тогда inputFile в секции Continue будет иметь значение c:\base\result\start_out.txt

TRiPLE 12.04.2007 20:03

Если ваяешь в билдере, то полезно будет использовать объект типа TIniFile - там немножко к нему прикрутить функциональности и тебе будет самое то. Если надо без привязки к среде разработки, то смотри вот здесь: _http://www.codeproject.com/cpp/rexsearch.asp

Bishop 13.04.2007 13:54

Как я понял, нужна такая процедура:
Код:

#include <stdio.h>
#include <tchar.h>
#include <windows.h>

BOOL GetString(TCHAR* fileName, TCHAR* section, TCHAR* key, // [in]
          TCHAR* value, // [out]
          DWORD sizeOfValue, TCHAR* commonSection = NULL) // [in]
{
        //TCHAR common_section[] = _T("Common");
        BOOL need_free = !commonSection;
        if (need_free)
                commonSection = _tcsdup(_T("Common"));
        TCHAR seps[] = _T("$()"), *token, *next_token;
        TCHAR inner_buffer[MAX_PATH];

        // получим исходную строку
        int ret_val = GetPrivateProfileString(section, key, NULL, value, sizeOfValue, fileName);

        TCHAR* start_mark = NULL; // начало замещаемой конструкции
        while (start_mark = _tcschr(value, _T('$')))
        {
                _tcscpy_s(inner_buffer, MAX_PATH, value);
                value[0] = _T('\0');
                start_mark += inner_buffer - value + 2;
                token = _tcstok_s(inner_buffer, seps, &next_token);
                while (token != NULL)
                {
                        size_t cur_len = _tcsnlen(value, sizeOfValue);
                        if (token == start_mark)
                        {
                                // если [секция]имя, разбиваем их нулем [секция0имя
                                // и секцию читаем с первого символа
                                TCHAR* custom_section = NULL;
                                if (custom_section = _tcschr(token, _T(']')))
                                        *custom_section = _T('\0');
                                ret_val = GetPrivateProfileString(
                                        custom_section?token+1:commonSection,
                                        custom_section?++custom_section:token,
                                        NULL, value + cur_len, sizeOfValue - cur_len, fileName);
                                if (ret_val == 0)
                                        break; // нет какого-то ключа/секции
                                // следующая замещаемая конструкция
                                start_mark = _tcschr(next_token, _T('$')) + 2;
                        }
                        else
                                _tcscpy_s(value + cur_len, sizeOfValue - cur_len, token);
                        token = _tcstok_s(NULL, seps, &next_token);
                }
                if (ret_val == 0)
                        break;
        }

        if (need_free)
                free(commonSection);

        return ret_val;
}

int _tmain(int argc, _TCHAR* argv[])
{
        TCHAR ini_file[] = _T("e:\\Visual Studio Projects\\INIParser\\test.ini");
        TCHAR buffer[MAX_PATH];
        TCHAR common_section[] = _T("Common");
        TCHAR section[] = _T("Final");
        TCHAR key[] = _T("megaFile");

        _putts(
                GetString(ini_file, section, key, buffer, sizeof(buffer)/sizeof(TCHAR))?
                buffer:_T("Error"));

        return 0;
}

Но в этом случае пути не должны содержать скобок. Что неправильно. Ведь никогда не знаешь, когда твоя программа окажется в каталоге Program Files (x86). Предлагаю в макросах заменить их на что-нибудь недопустимое, например ':'. Или '%'.
Приведенный код обрабатывает любое число подстановок в строке, например:
Код:

[Final]
part = public\release
megaFile = $(ResultDir)\$([Final]part)\release.txt

Про скобки в путях можно почитать в статьях:
_http://blog.not-a-kernel-guy.com/2006/08/15/33
_http://blog.not-a-kernel-guy.com/2006/11/29/106

crawler 18.04.2007 11:48

Bishop, спасибо, ты натолкнул меня на правильный путь. Я понял что мне нужно ;). В связи с этим и может кому понадобиться на будущее несколько проектов, которые облегчат жизнь:

DotConf : парсер конфигурационных файлов с синтаксисом похожим на ХМЛ, на С
DotConf++ : то же самое, но на С++. Сейчас довожу напильником до идеала.
Nini парсер на .NET со множеством опций. Был бы на с++ , выбрал бы его.
Boost.Program_options Какая-то супер крутая библиотека. я с ней не разобрался, но сам факт того что она входит в БУСТ внушает уважение.

Есть еще много всякого, но они меня не устроили.

к модераторам: переименуйте пожалуйста тему в "Парсер для файлов конфигурации / .cfg / .ini


Часовой пояс GMT +4, время: 07:59.

Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.