(fasm) расширение синтаксиса

Тема в разделе "WASM.ASSEMBLER", создана пользователем GoldFinch, 24 сен 2008.

  1. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    Чтобы привести код в фасме к виду похожему на ЯВУ (средствами фасма), нужно каждую строчку сделать макросом, при этом строчка должна начинаться с имени (макроса), а не с символа (+-*#&|/[({).
    Для этого можно использовать два пути:

    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
     
  2. max7C4

    max7C4 New Member

    Публикаций:
    0
    Регистрация:
    17 мар 2008
    Сообщения:
    1.203
    зачем поганить fasm - поставь pas и не парься
     
  3. spa

    spa Active Member

    Публикаций:
    0
    Регистрация:
    9 мар 2005
    Сообщения:
    2.240
    max7C4
    Не гони, вызов функций правда бы карал.
     
  4. Freeman

    Freeman New Member

    Публикаций:
    0
    Регистрация:
    10 фев 2005
    Сообщения:
    1.385
    Адрес:
    Ukraine
    как по мне, первый вариант удобен, но бесперспективен :), потом проблематично юзать push name_macro или там сделоть какоето извращение :)) да и макрос ведь - заранее известный набор действий для полученийа результата, а ведь как показывает практика одно и тоже действие можно сделоть разными командами.. поэтому лучше тогда уж сделоть один универсальный макро, которыю использовать в зависимости от ситуации

    п.с. радует ваш порыв к познанию макросов фасма :) сам иногда люблю поизврощацо, правда не до такой степени.
     
  5. spa

    spa Active Member

    Публикаций:
    0
    Регистрация:
    9 мар 2005
    Сообщения:
    2.240
    GoldFinch
    Я тут покумекал, лучше переделать код самого масма, причем достаточно просто, ввести самую последнию проверку когда уже фасм не знает что это за шняка чтобы он "вызывал" макрос ChtoEtoZaSn9ga и уже этот макрос смотрел есть ли "скобочка" после того с чем фасм не смог разобраться... ну далее все понятно )
     
  6. dead_body

    dead_body wasm.ru

    Публикаций:
    0
    Регистрация:
    3 сен 2004
    Сообщения:
    603
    Адрес:
    Украина;г.Харьков;г.Н.Каховка
    Не легче ли перед компиляцией, запускать свой препроцессор? Или перекомпилить фасм и поставить в нём запуск перед компиляцией препроцессора внешнего.
     
  7. _basmp_

    _basmp_ New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2005
    Сообщения:
    2.939
    GoldFinch
    Вы делайте. Не исключено, что получится интересно, хотя я-бы слегка доработал-бы сам препроцессор (ввел возможности предоставляемые тех-овским \def\..{..} с регуляр-расширениями). Возможно и как-нить напрягусь.
     
  8. max7C4

    max7C4 New Member

    Публикаций:
    0
    Регистрация:
    17 мар 2008
    Сообщения:
    1.203
    хорошо. кто мешает написать библиотеку макросов. к примеру
    Код (Text):
    1. macro proc name, [param]
    2. {
    3. common if ~param eq
    4. reverse push param
    5. common end if
    6. call name
    7. }
    8. macro func result, name, [param]
    9. {
    10. common if ~param eq
    11. reverse push param
    12. common end if
    13. call name
    14. if ~result in <al, ax, eax>
    15.   if result in <ah, bl, bh, cl, ch, dl, dh>
    16.     mov result, al
    17.   else if result in <bx, cx, dx, si, di, bp, sp, ds, es, fs, gs>
    18.     mov result, ax
    19.   else if result in <ebx, ecx, edx, ebp, esp, edi, esi, cr0>
    20.     mov result, eax
    21.   else if result in <efl>
    22.     push eax
    23.     popf
    24.   else if result in <stack>
    25.     push eax
    26.   else
    27.     mov result, eax
    28.   end if
    29. end if
    30. }
    31. macro if op1, cond, op2, jok
    32. {
    33.   cmp op1, op2
    34.   if cond in <==>
    35.   jz jok
    36.   else if cond in <!=>
    37.   jnz jok
    38.   end if
    39. }
    40. macro while op1, con, op2, jstart, jexit
    41. {
    42.   local label
    43. label:
    44.   push label
    45.   if op1, cond, op2, jstart
    46.   jmp jexit
    47. }
    48. macro for init, op0, op1, cond, op2, cycle, op3, jstart, jexit
    49. {
    50.   init#op0
    51.   jmp jstart
    52.   local label
    53. label:
    54.   push label
    55.   cycle#op3
    56.   if op1, cond, op2, jstart
    57.   jmp jexit
    58. }
    довести до ума, думаю, труда не составит. я ей все равно пользоваться не буду. Разве что первыми двумя макросами (они собственно из моей библиотеки, правда немного в упрощенной форме). Остальные доводить до ума Вам.
     
  9. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    Freeman
    name dd 0 / macro name {push name} / name - работает нормально, метки и макросы друг на друга не влияют

    Переделка фасма или добавление собственного препроцессора убивает обмен исходниками. Чтобы выложить исходник на форме, мне придется рядом с ним класть свою версию фасма или свою связку препроцессор+иде. Инклуд выложить проще.

    По теме - все же склоняюсь к 2-3 вариантам, т.к. использование ЯВУ-образного синтаксита будет сильно мешать тогда, когда нужно будет применить чистый асм, без макросов. Обертывать же любой асм код в макросы только для сохранения читаемости плохая идея.
     
  10. max7C4

    max7C4 New Member

    Публикаций:
    0
    Регистрация:
    17 мар 2008
    Сообщения:
    1.203
    повторюсь
     
  11. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    Так уж получилось, что я вместо
    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)
    Код (Text):
    1.       if string eqtype ''
    2.        label dd RVA _label
    3.       else
    4.        label dd 80000000h + string
    5.       end if
    на
    Код (Text):
    1.       if string eqtype ''
    2.        p#label dd RVA _label
    3.       else
    4.        p#label dd 80000000h + string
    5.       end if
    6.       macro label [line] \{common match (arg),line \\{ invoke p#label,arg \\}\}
    то любое импортируемое апи можно будет вызывать по имени: Func(x,y,z)
    Какбэ это попроще чем рыться в сорцах фасма или кодить свой препроцессор
     
  12. _basmp_

    _basmp_ New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2005
    Сообщения:
    2.939
    GoldFinch
    Сорцы фасма не сложные. Но не в этом дело. Ваша мысль - одни ++, доп препроцессор - другие.

    Скажите, а писать
    Код (Text):
    1. push z
    2. ....
    3. push y
    4. ....
    5. push x
    6. ....
    7. call Func
    после этого можно будет?
     
  13. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    Можно будет писать
    push [z] / push z / call [Func]
    Пример: вешаем на MessageBox макрос, вызываем MessageBox двумя способами:
    Код (Text):
    1. macro MessageBox [line] {common match (arg),line \{ invoke MessageBox,arg \}}
    2. include '%fasminc%\win32ax.inc'
    3. .code
    4. start:
    5.         MessageBox(HWND_DESKTOP,"Hi#1","Win32 Assembly",MB_OK)
    6.         push MB_OK
    7.         call @f
    8.         db "Win32 Assembly",0
    9.      @@:call @f
    10.         db "Hi#2",0
    11.      @@:push 0
    12.         call [MessageBox]
    13.         ret
    14. .end start
    Как написано в 1м посте, главное соблюсти однородность синтаксиса, чтобы если
    "mov [var],var" то "LET [var]=var", а если
    "mov ptr var, var", то "var=@var"
     
  14. zet

    zet New Member

    Публикаций:
    0
    Регистрация:
    15 окт 2007
    Сообщения:
    121
    max7C4
    +1
     
  15. _basmp_

    _basmp_ New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2005
    Сообщения:
    2.939
    GoldFinch
    Ну чтож, если аргументы можно предзаталкивать, то +1. А вот
    тут не соглашусь. 'LET' - очень длинно и в верхнем регистре и буквы далеко друг от друга. Лучше заменить каким односимвольным префиксом: '!' или '#' или еще как. Или вообще все макросы начинать с определенного символа, обычно, '\'. И символ '@', имхо, лучше заменить на '&'.
     
  16. Freeman

    Freeman New Member

    Публикаций:
    0
    Регистрация:
    10 фев 2005
    Сообщения:
    1.385
    Адрес:
    Ukraine
    ну коль так, то однозначно кулл.. йа к тому, что есле с данными макросами можно скомпилить проэкт, использующий стондартный набор макросов, то все пучком, иначе - лень возится с переоформлением.
    а то, что надо будет кидать .inc рядом со всеми файлами, так это я считаю не такая уж проблема.

    _basmp_, + насчет LET
     
  17. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    Лет был выбран как обозначение оператора присваивания в бейсике, исключительно для примера. @ - оператор делфи и паскаля (слава ему! ^^)
    & удобен тем, что & в отличие от @ "символ" а не "буква", - проще парсить. Хотя т.к. @name - тоже имя, его проще определять, типа
    name equ [xxx]
    @name equ xxx
    Начинать макрос с какого-то магического символа хорошо если ты к нему привык, тогда он не сильно бросается в глаза. А вот для человека который видит это в первый (второй) раз, LET понятнее, т.к. это осмысленное слово. Но вообще это очередной холивар на тему Си vs Pascal или осмысленные названия операторов против символов.
     
  18. _basmp_

    _basmp_ New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2005
    Сообщения:
    2.939
    GoldFinch
    так в том-то и дело, что пересекаться с реальными именами может
    Манера выделять макросы начиная с '\' достаточно распостранена и очень удобна, тк не ухудшая читаемости полностью исключает пересечения с существующими метками, командами, регистрами итд. Сравните:

    eax = 1 ; константа eax == 1. даже непонятно, что выйдет из этого
    \ eax = 1 ; макрос mov eax,1
    LET eax = 1 ; чтоб напечатать нужны две руки, не смотрится и потом, слово let да еще и с большой буквы сами васиковцы не любят, а в асме конструкций типа mov (LET) 70% кода. Кроме того и mov и LET имеют по 3 буквы, но для LET в каждой строке придется шифт держать, что неудобно. Те с функами неплохо, а в LET - ни наглядности, ни экономии и переменную/метку такую уже не создать.

    PS все это мое мнение. Макросы ваши, вам и решать, что вам удобнее. Мне просто не нравится васик и, в особенности оператор let (а в пасе :=). Непонятно, зачем так усложнять самую используемую операцию
     
  19. _basmp_

    _basmp_ New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2005
    Сообщения:
    2.939
    GoldFinch
    ваши слова. А 'испорченый вид' полностью окупится исчезновением двусмысленостей и пересечений.
     
  20. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    Продолжим...
    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. Так как операторы ЯП как правило взаимоисключают друг друга, логично построить основной макрос так:
    Код (Text):
    1. macro HIGHLEVEL [line] {common
    2.   local flag
    3.   define flag 0
    4.   match <op_pattern_1>,line \{ <op_process_1>
    5.     define flag 1\}
    6.   match 1* <op_pattern_2>,flag* line \{ <op_process_2>
    7.     define flag 1\}
    8.   match 1* <op_pattern_3>,flag* line \{ <op_process_3>
    9.     define flag 1\}
    10. ...
    11.   match 1* <op_pattern_N>,flag* line \{ <op_process_N> \}
    12. }
    (op_pattern_i, op_process_N - пары шаблон\обработчик для каждого оператора)

    При таком построении, 1й парой должна быть проверка "многострочности", с рекурсивным вызовом макроса для каждой "подлинии" (subline)
    Код (Text):
    1. ...
    2. define flag 0
    3. match foo/bar,line \{
    4.   local ..collector
    5.   ..collector equ /
    6.   irps symbol, line \\{ match /,symbol \\\{
    7.       match /subline,..collector \\\\{HIGHLEVEL subline \\\\}
    8.       ..collector equ  \\\}
    9.     ..collector equ ..collector symbol \\}
    10.   match match /subline,..collector \\{HIGHLEVEL subline\\}
    11.   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, поддержка арифметических циклов.

    Продолжение (и реализация) следует.