Интересует вопрос, есть ли смысл вместо встроенных макросредств ЯП использовать внешний парсер/препроцессор. Видимо основное препятствие - несовместимость внешней программы с ИДЕ, однако не так уж мало вещей пишутся в блокноте и компилируются бат-файлами. Так что стоит ли задумываться о создании своей "удобной" грамматики, написании своего (использования готового) препроцессора? Ссылки: http://en.wikipedia.org/wiki/Parsing http://en.wikipedia.org/wiki/Comparison_of_parser_generators http://en.wikipedia.org/wiki/Compiler-compiler
GoldFinch Смысла нет, но многие производители софта делают это для, как они считают, удобства пользователя. Я не поддерживаю такой прием. Вместо встроенных ЯП, я использую config-файлы и, если надо, открываю примеры на си / с++ или еще чем-то для cоздания модуля или плагина. Большинство компаний-разработчиков считают, что используя встроенный ЯП, они улучшают не только сам программный продукт в плане удобства (как, например, 1C ( ones_alfasoft corporation) ), но и раскручивают свою ТМ. Однако, как показывает общественное мнение подавляющего большинства программистов, от встроенных ЯП никто не в восторге.
Я говорю об использовании парсеров при разработке. Например, компиля исходник в масме, используем бат-файл if exist "%1.obj" del "%1.obj" if exist "%1.exe" del "%1.exe" \masm32\bin\ml /c /coff "%1.asm" \masm32\bin\Link /SUBSYSTEM:WINDOWS /OPT:NOREF "%1.obj" а файле куча конструкций типа invoke func1,arg1,arg2,TEXT("str"),... mov var1,eax можем средствами языка написать макрос fncall и использовать его: fncall var1,func1,arg1,arg2,TEXT("str"),... invoke func2,arg,... fncall var2,func3,arg,... и написать еще дофига других полезных макросов, делать библиотеки макросов, или каждый раз записывать макросы в файл по-новой. а можем использовать парсер, дописав его в этот бат-файл if exist "%1.obj" del "%1.obj" if exist "%1.exe" del "%1.exe" _parser_.exe %1.txt %1.asm \masm32\bin\ml /c /coff "%1.asm" \masm32\bin\Link /SUBSYSTEM:WINDOWS /OPT:NOREF "%1.obj" и использовать например такой синтаксис: var1:=func1(arg1,arg2,"str1",...); func2(arg,...); var2:=func3(arg,...)
GoldFinch, давно хочу такую сделать как экстендед препроцессор для C/C++, хочу добавить там много фичей, но пока этим не занимался. Кстати видел такой экстендед препроцессор по-мойму даже опенсурсный, но там неочень было много лишнего функционала. Насчет совместимости с IDE -а почему бы и нет? Меняешь бинарник дефолтного препроцессора на свой, а в своем вконце обработки напускаешь еще дефолтный (по желанию разумеется)
GoldFinch да пользуюсь и весьма активно, потому что сишный препроцессор даже по сравнению с масмом это просто игрушка, а как он юзает макросы так это просто тихий ужас. классический пример #define MAX(a,b) (((a)>(b))?(a)b)) и классические лыжи типа MAX(++a, --b); короче, сишные макросы потенциальный глюкодром и их лучше вообще не использовать. штука но истина такова, что хочется много вещей делать на стадии компиляции, а препроцессор не позволяет. или задалбывает, отсутствие поддержки вложенных комментов. поэтому, иногда проще написать небольшой такой "хэлпер", работающий как препроцессор и прогонять через него программу. если хэлпер написан на ANSI C проблем с переносимостью не возникает вот, например, я таким образом делаю из строк хэши. т.е. вместо того, чтобы писать !strcmp("AAAAA", str); можно написать if (."AAAA". == .#.str) и препроцессор вычислит хэш из "AAAAA" и str, подставив в программу константу и вызов функции хэширования для str (если str не константа), в результате чего у нас повыситься скорость на этапе выполнения. а по другому (штатными средствами языка) эту задачу не решить никак. то есть, можно, конечно, написать внешний хэш-калькулятор, на котором и считать "АААА", подставляя в программу константу, но это задалбывает и к тому же совершенно ненаглядно, т.к. придется рядом еще и комментарий лепить чей это хэш. а потом следить, чтобы комментарий соответствовал хэшу, а то ведь можно изменить хэш забыв о комменте.
kaspersky Да пожалуй соглашусь, мы тут даже шутили на эту тему, прикрутить вместо макросов пхп (я перл предлагал), вот поистене мощьно будет ) (чтото вроде м4 только пхп или перл)
GoldFinch Тоже давно думаю о добовлении внеших макросов. Delphi, Asm, C. Многии вещи проще написать макросами, но не теми убогими что есть. Вот PhP и FASM мне нравяться в этом плане. Темболее есть идея использовать парсер для защиты кода. Среды разные бывают. Может можно и прекрутить.
SPA Pavia на счет перла не знаю, но есть библиотеки транслирующие регулярные выражения в си-код. с ними писать разбор текстовых файлов на сях _намного_ проще, да и работают они эффективно. про IDE я вообще не понял. препроцессор просто обрабатывает код программы и генерирует чистый Си. к любой известной мне среде он прикручивается с пол-пинка. в смысле чтобы делать билд одной кнопкой. чуть сложнее с подсветкой синтаксиса и автодополнением. ну подстветку ее можно и настроить (не уверен, что везде), автодополнение я как-то не использую, хотя, наверное, должнен быть способ настроить и его. что остается?! ага, отладка. да. отладка это лыжи. ну в своих парсерах я делал сохранение строк исходного кода путем хитрых хаков, но потом забил. отладка это действительно проблема, т.к. номера строк исходного файла уже не соответствуют отладочной инфе распрасенного файла и отладчики с ума сходят. те, которые в IDE. а Ольга очень даже ничего, хоть это и не source-level отладчик...
kaspersky А причём тут сишный препроцессор? Если развернуть это выражения целиком, то мы получим undefined behavior. Стандарт не ганартирует правильное выполнение кода в этом случае. Т.е. такие конструкции вообще писать нельзя. Никакой внешний парсер не решит эту "проблему".
W4FhLF MAX(int a, int b) { return ((a>b)?a:b); } препроцессор может заменить макрос на вызов функции, он даже может определить типы a и b, чтобы их подставить автоматом. но речь о другом. хорошо бы иметь такой механизм, который позволяет писать макросы лишенные побочных эффектов, что в частности, решается локализацией аргументов макроса. в смысле a и b препроцессор кладет во временные переменные и полностью эта конструкция разворачивается в: a_t = ++a; b_t = --b; (a_t>b_t)?a_t:b_t; кстати, это не сильно усложняет препроцессор. плюс у меня еще есть необходимость задавать строки в разных кодировках. самый простой пример: пишу в виндовом редакторе, а выводить буду в консоль кирилицу. конечно, можно вынести строки в отдельный файл, набранный в FAR'е, но как быть, если мне вот тут пришлось писать программу, в которой есть русские, английские и китайские строки, причем программа не уникодовая со всемим вытекающими отсюда из. слегка доработал свой препроцессор и теперь можно писать конструкции типа "привет"///RU866 и препроцессор перекодирует ее в DOS. удобно мелочь, а приятно.
kaspersky Мне кажется, ты на макросы возлагаешь функционал, который призваны реализовывать inline функции. Макросы вообще сложными быть недолжны, они и так достаточно сложно воспринимаются зрительно в коде программы, особенно многострочные. А функции проще сопровождать. Единственное их преимущество -- они по дефолту могут быть заменены константой в compile-time. Но нынешние компиляторы и inline функции умеют урезать и подставлять константу. Поэтому я бы не стал выполнять лишнюю работу за компилятор раньше времени. Что касается костылей со строками, которые ты придумываешь. Я не приветствую такие хаки. Я пишу на С++, там проблема интернационализации решается стандартными средствами с помощью т.н. локальных объектов контекста. В Си кстати тоже есть нечто подобное, посмотри 7.11 "Localization <locale.h>". Чем не подходит?
kaspersky Да, регулярные выражения можно юзать, очень и очень добно. Я бы даже вкрутил выражения в стандарт си ) W4FhLF ИМХО макросы всеже чтобы на уровне компиляции чтото сделать PS вместо "бы", было "ms" жуть мс захватывают разум
W4FhLF > Мне кажется, ты на макросы возлагаешь функционал, > который призваны реализовывать inline функции. ты можешь привести пример функци на си, которая ищет макс среди разнтых типов? char, int, float, etc? > Макросы вообще сложными быть недолжны, > они и так достаточно сложно воспринимаются зрительно в коде программы, благодаря кому? опять-таки препроцессору и еще сложнее отлаживаются. но шаблоны есть только в плюсах. да и у шаблонов не все идеально... местами даже хуже, чем у макросов... а на счет инлайновсти.... ну нету ее в си. реально нету. а функции воспринимаются зрительно еще сложнее макроосов... > Поэтому я бы не стал выполнять лишнюю работу за компилятор раньше времени. я выполняю свою работу. во многих случаях макросы ее упрощают. поэтому они были, если и будут. > Что касается костылей со строками, которые ты придумываешь. > Я не приветствую такие хаки. это не хак, а вполне законный прием программирования. > Я пишу на С++, твои плюсы очень большой хак на си и первые приплюснутые компиляторы работали фактически как сишиные препроцессоры
kaspersky В порядке наглости. симпатичные фичи. Эта тулзень гдето лежит? В сорцах? Или это внутреняя тулза. Нельзя-ли ее обнародовать? Или она строго комковая? Тогда сильно извиняюсь. И тулза для регексповых стрококовыряний через С код (давно хочу заполучить/написать да как-то руки не доходят, а готовые виденые в инете не особо впечатляют. Охота чтобы было просто как в перле и быстро как в С).
kaspersky Что ты имеешь ввиду? Опять не понял. Что это значит? То, что компилятор часто игнорирует inline? Есть __forceinline (для компилера от MS) Это субъективно, но я считаю наоборот. Вот взял первый пример, который нашёл в папке с проектами: Функция: Код (Text): __forceinline NTSTATUS Us_SetLength(const PUNICODE_STRING pUs, const ULONG aLength) { if (pUs->MaximumLength >= aLength) { pUs->Length = aLength; return STATUS_SUCCESS; } return STATUS_NAME_TOO_LONG; }; Макрос: Код (Text): #define _Us_SetLength(_pus, _cbLen) (((_pus)->MaximumLength >= (_cbLen)) ? \ (((_pus)->Length = (_cbLen)) & 0) : \ STATUS_NAME_TOO_LONG) Для меня первый вариант более нагляден. К тому же там происходит самодокументация кода, благодаря квалификатору const и осмысленным кодам и типу возвращения. Смотря как ты это реализовал. Ты ведь сказал: То, что не описано в стандарте, т.е. все твои собственные доработки -- это уже хаки. Иногда конечно приходится чем-то жертвовать, чтобы достичь большей технологичности процесса разработки. Всё зависит от ситуации. Это намёк на то, что СИ рулед и на нём "можно сделать всё, что угодно" (с)?
В случае с MAX макрос это хорошее решение, не спорю. Но раз уж ты спросил , то для целых знаковых типов могу предложить каст до long. Для вещественных каст к double. Далее function overloading и всё. Но, я бы выбрал макрос