PDA

Просмотр полной версии : Ищу парсер ?


crawler
12.04.2007, 15:24
Задача: чтение INI-подобного файла. С поддержкой простых макросов. Например:

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

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

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

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

crawler
12.04.2007, 18: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, 19:03
Если ваяешь в билдере, то полезно будет использовать объект типа TIniFile - там немножко к нему прикрутить функциональности и тебе будет самое то. Если надо без привязки к среде разработки, то смотри вот здесь: _http://www.codeproject.com/cpp/rexsearch.asp

Bishop
13.04.2007, 12: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, 10:48
Bishop, спасибо, ты натолкнул меня на правильный путь. Я понял что мне нужно ;). В связи с этим и может кому понадобиться на будущее несколько проектов, которые облегчат жизнь:

DotConf (http://www.azzit.de/dotconf/) : парсер конфигурационных файлов с синтаксисом похожим на ХМЛ, на С
DotConf++ (http://a.krivoshey.kiev.ua/dotconfpp.html) : то же самое, но на С++. Сейчас довожу напильником до идеала.
Nini (http://nini.sourceforge.net/index.php) парсер на .NET со множеством опций. Был бы на с++ , выбрал бы его.
Boost.Program_options (http://http://www.boost.org/doc/html/program_options.html) Какая-то супер крутая библиотека. я с ней не разобрался, но сам факт того что она входит в БУСТ внушает уважение.

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

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