Чтобы привести код в фасме к виду похожему на ЯВУ (средствами фасма), нужно каждую строчку сделать макросом, при этом строчка должна начинаться с имени (макроса), а не с символа (+-*#&|/[({). Для этого можно использовать два пути: 1) Каждое имя (переменной, функции) сделать макросом. Тогда, как в любом яву, каждая строчка будет начинаться с имени: var=exp func() if ... while ... do ... Все это замечательно, но тогда в "оператор присваивания" будет выглядеть так: mem=<выражение>, или так: reg=<выражение>, однако в асме принято записывать [mem]=<выражение>, иначе запись mov [mem],mem будет выглядеть как mem=mem. Чтобы решить эту проблему надо полностью избавляться от оператора [], и вводить оператор @ (он же offset, он же addr). Но при такой замене будут путаницы в смешаном коде - с макросами+без макросов, путаницы в исходниках и т.п., код будет писаться так: mem=@mem / mem=func(mem) -почти турбопаскаль 2) Можно сделать один хитрый макрос "?" (или @ или ! или любое другое короткое имя), который будет ставиться в начале любой строки и парсить ее. Это позволит использовать нормальную логику асма ? [mem]=mem / [mem]=func([mem]), но "лишний" символ в строке будет несколько портить общий вид кода. 3) 1 хитрый макрос LET [var]=<выражение>, только для оператора присваивания /discuss
как по мне, первый вариант удобен, но бесперспективен , потом проблематично юзать push name_macro или там сделоть какоето извращение ) да и макрос ведь - заранее известный набор действий для полученийа результата, а ведь как показывает практика одно и тоже действие можно сделоть разными командами.. поэтому лучше тогда уж сделоть один универсальный макро, которыю использовать в зависимости от ситуации п.с. радует ваш порыв к познанию макросов фасма сам иногда люблю поизврощацо, правда не до такой степени.
GoldFinch Я тут покумекал, лучше переделать код самого масма, причем достаточно просто, ввести самую последнию проверку когда уже фасм не знает что это за шняка чтобы он "вызывал" макрос ChtoEtoZaSn9ga и уже этот макрос смотрел есть ли "скобочка" после того с чем фасм не смог разобраться... ну далее все понятно )
Не легче ли перед компиляцией, запускать свой препроцессор? Или перекомпилить фасм и поставить в нём запуск перед компиляцией препроцессора внешнего.
GoldFinch Вы делайте. Не исключено, что получится интересно, хотя я-бы слегка доработал-бы сам препроцессор (ввел возможности предоставляемые тех-овским \def\..{..} с регуляр-расширениями). Возможно и как-нить напрягусь.
хорошо. кто мешает написать библиотеку макросов. к примеру Code (Text): macro proc name, [param] { common if ~param eq reverse push param common end if call name } macro func result, name, [param] { common if ~param eq reverse push param common end if call name if ~result in <al, ax, eax> if result in <ah, bl, bh, cl, ch, dl, dh> mov result, al else if result in <bx, cx, dx, si, di, bp, sp, ds, es, fs, gs> mov result, ax else if result in <ebx, ecx, edx, ebp, esp, edi, esi, cr0> mov result, eax else if result in <efl> push eax popf else if result in <stack> push eax else mov result, eax end if end if } macro if op1, cond, op2, jok { cmp op1, op2 if cond in <==> jz jok else if cond in <!=> jnz jok end if } macro while op1, con, op2, jstart, jexit { local label label: push label if op1, cond, op2, jstart jmp jexit } macro for init, op0, op1, cond, op2, cycle, op3, jstart, jexit { init#op0 jmp jstart local label label: push label cycle#op3 if op1, cond, op2, jstart jmp jexit } довести до ума, думаю, труда не составит. я ей все равно пользоваться не буду. Разве что первыми двумя макросами (они собственно из моей библиотеки, правда немного в упрощенной форме). Остальные доводить до ума Вам.
Freeman name dd 0 / macro name {push name} / name - работает нормально, метки и макросы друг на друга не влияют Переделка фасма или добавление собственного препроцессора убивает обмен исходниками. Чтобы выложить исходник на форме, мне придется рядом с ним класть свою версию фасма или свою связку препроцессор+иде. Инклуд выложить проще. По теме - все же склоняюсь к 2-3 вариантам, т.к. использование ЯВУ-образного синтаксита будет сильно мешать тогда, когда нужно будет применить чистый асм, без макросов. Обертывать же любой асм код в макросы только для сохранения читаемости плохая идея.
Так уж получилось, что я вместо macro invoke func,[arg] { reverse pushd arg common call [func] } ... invoke func,arg1,arg2,arg3 предпочитаю использовать как минимум macro invoke [line] {common match f(x),line \{irp arg,x \\{reverse pushd arg\\} call [f] \} } ... invoke func(arg1,arg2,arg3) И вообще, я стараюсь по возможности использовать в макросах осмысленные разделители, а не ниочемнеговорящие запятые. Алсо если в стандартном макросе import заменить (строки 46-50) Code (Text): if string eqtype '' label dd RVA _label else label dd 80000000h + string end if на Code (Text): if string eqtype '' p#label dd RVA _label else p#label dd 80000000h + string end if macro label [line] \{common match (arg),line \\{ invoke p#label,arg \\}\} то любое импортируемое апи можно будет вызывать по имени: Func(x,y,z) Какбэ это попроще чем рыться в сорцах фасма или кодить свой препроцессор
GoldFinch Сорцы фасма не сложные. Но не в этом дело. Ваша мысль - одни ++, доп препроцессор - другие. Скажите, а писать Code (Text): push z .... push y .... push x .... call Func после этого можно будет?
Можно будет писать push [z] / push z / call [Func] Пример: вешаем на MessageBox макрос, вызываем MessageBox двумя способами: Code (Text): macro MessageBox [line] {common match (arg),line \{ invoke MessageBox,arg \}} include '%fasminc%\win32ax.inc' .code start: MessageBox(HWND_DESKTOP,"Hi#1","Win32 Assembly",MB_OK) push MB_OK call @f db "Win32 Assembly",0 @@:call @f db "Hi#2",0 @@:push 0 call [MessageBox] ret .end start Как написано в 1м посте, главное соблюсти однородность синтаксиса, чтобы если "mov [var],var" то "LET [var]=var", а если "mov ptr var, var", то "var=@var"
GoldFinch Ну чтож, если аргументы можно предзаталкивать, то +1. А вот тут не соглашусь. 'LET' - очень длинно и в верхнем регистре и буквы далеко друг от друга. Лучше заменить каким односимвольным префиксом: '!' или '#' или еще как. Или вообще все макросы начинать с определенного символа, обычно, '\'. И символ '@', имхо, лучше заменить на '&'.
ну коль так, то однозначно кулл.. йа к тому, что есле с данными макросами можно скомпилить проэкт, использующий стондартный набор макросов, то все пучком, иначе - лень возится с переоформлением. а то, что надо будет кидать .inc рядом со всеми файлами, так это я считаю не такая уж проблема. _basmp_, + насчет LET
Лет был выбран как обозначение оператора присваивания в бейсике, исключительно для примера. @ - оператор делфи и паскаля (слава ему! ^^) & удобен тем, что & в отличие от @ "символ" а не "буква", - проще парсить. Хотя т.к. @name - тоже имя, его проще определять, типа name equ [xxx] @name equ xxx Начинать макрос с какого-то магического символа хорошо если ты к нему привык, тогда он не сильно бросается в глаза. А вот для человека который видит это в первый (второй) раз, LET понятнее, т.к. это осмысленное слово. Но вообще это очередной холивар на тему Си vs Pascal или осмысленные названия операторов против символов.
GoldFinch так в том-то и дело, что пересекаться с реальными именами может Манера выделять макросы начиная с '\' достаточно распостранена и очень удобна, тк не ухудшая читаемости полностью исключает пересечения с существующими метками, командами, регистрами итд. Сравните: eax = 1 ; константа eax == 1. даже непонятно, что выйдет из этого \ eax = 1 ; макрос mov eax,1 LET eax = 1 ; чтоб напечатать нужны две руки, не смотрится и потом, слово let да еще и с большой буквы сами васиковцы не любят, а в асме конструкций типа mov (LET) 70% кода. Кроме того и mov и LET имеют по 3 буквы, но для LET в каждой строке придется шифт держать, что неудобно. Те с функами неплохо, а в LET - ни наглядности, ни экономии и переменную/метку такую уже не создать. PS все это мое мнение. Макросы ваши, вам и решать, что вам удобнее. Мне просто не нравится васик и, в особенности оператор let (а в пасе :=). Непонятно, зачем так усложнять самую используемую операцию
GoldFinch ваши слова. А 'испорченый вид' полностью окупится исчезновением двусмысленостей и пересечений.
Продолжим... 1. Так как каждая строка должна начинаться с макроса, и соответственно каждое имя с которого может начинаться строка должно быть макросом, логично сделать эти макросы такими: macro name [line]{common HIGHLEVEL name line}, где name - имя (с которого может начинаться строка), HIGHLEVEL - макрос, который реализует ВСЕ расширения синтаксиса, при этом HIGHLEVEL equ LET equ @ equ ..., т.е. строки "HIGHLEVEL x=1", "LET x=1", "@ x=1" - идентичны. 2. Фактически, "расширенный" синтаксис можно считать новым ЯП (на базе fasm'а). Поэтому надо определиться с правилами и операторами этого ЯП. При этом с одной стороны надо помнить, что синтаксис в любой момент можно переделать под себя, с другой стороны препроцессор фасма накладывает некоторые ограничения. 2.1. Необходима реализация записи нескольких операторов в одной строке. В Си и Паскале для этого используется ";", чего мы здесь использовать не можем, в Бейсике если кто помнит - ":", что на мой взгляд не совсем удобно. Я буду использовать "/". Для этого, первой стадией парсинга строки должно быть ее разбиение на подстроки, оператором irps с последующей обработкой. 2.2. Так как операторы ЯП как правило взаимоисключают друг друга, логично построить основной макрос так: Code (Text): macro HIGHLEVEL [line] {common local flag define flag 0 match <op_pattern_1>,line \{ <op_process_1> define flag 1\} match 1* <op_pattern_2>,flag* line \{ <op_process_2> define flag 1\} match 1* <op_pattern_3>,flag* line \{ <op_process_3> define flag 1\} ... match 1* <op_pattern_N>,flag* line \{ <op_process_N> \} } (op_pattern_i, op_process_N - пары шаблон\обработчик для каждого оператора) При таком построении, 1й парой должна быть проверка "многострочности", с рекурсивным вызовом макроса для каждой "подлинии" (subline) Code (Text): ... define flag 0 match foo/bar,line \{ local ..collector ..collector equ / irps symbol, line \\{ match /,symbol \\\{ match /subline,..collector \\\\{HIGHLEVEL subline \\\\} ..collector equ \\\} ..collector equ ..collector symbol \\} match match /subline,..collector \\{HIGHLEVEL subline\\} define flag 1\} Возможен и вариант без irps, c большой вложенностью: match foo/bar,line \{ HIGHLEVEL foo HIGHLEVEL bar define flag 1\} (после "match foo/bar,line /{.../}" можно разместить код замены "div" на "/" для нормальной работы деления) 2.3. Список операторов 2.3.1. Вызов процедуры Sub(arglist). Фактически состоит из двух отдельных операторов - оператора передачи параметров (), который может видоизменяться в зависимости от соглашения вызова, - оператора вызова процедуры, который может осуществлять прямой вызов на внутреннюю процедуру, брать адрес процедуры из таблицы импорта, вызывать метод объекта или интерфейса COM. Для начала хватит того чтобы реализовать только __stdcall) 2.3.2. Оператор присваивания var=exp. Основная проблема в поддержке выражений, которые также могут быть аргументами процедур f(1+1). Также часто встречаются выражения связанные с указателями, например (x*+4)*, x^.hi_dword^ Хотя поддержка полноценных выражений дело хорошее, но для начала достаточно реализовать функции, аналоги mov\add\sub (= =+ =-), желательно операции с указателями. 2.3.3. Операторы ветвлений и циклов. Минимум - if (exp) goto label Максимум - ветвления if-elseif-else, jmptable, поддержка арифметических циклов. Продолжение (и реализация) следует.