Оператор Switch для QPILE

Опубликовано в M4

Продолжение статьи Расширение синтаксиса QPILE


В синтаксисе QPILE отсутствует оператор Switch. Иногда такое отсутствие неприятно и приходится создавать списки из операторов If, которые могут занимать целый экран, а то и не один. Тем не менее, используя имеющиеся конструкции языка QPILE и препроцессор, не составляет особого труда создать этот оператор.


Определяем макросы:

define(`Switch',`ifelse($1,,`err'print(Error __file__ line __line__: Missing SWITCH argument
),pushdef(`m4_switch',$1) pushdef(`m4_first_switch',0) pushdef(`m4_was_default',0) Loop)')
define(`m4_close_choice',`ifelse(m4_first_switch,0,popdef(`m4_first_switch') pushdef(`m4_first_switch',1),break
end if)')
define(`Case',`ifelse($1,,`err'print(Error __file__ line __line__: Missing CASE argument
),m4_close_choice
if m4_switch == $1)')
define(`Default',`ifelse($1,,m4_close_choice popdef(`m4_was_default') pushdef(`m4_was_default',1),`err'print(Error __file__ line __line__: Excess parameter(s) in DEFAULT
))')
define(`EndSwitch',`ifelse(m4_was_default,0,break
end if)
break
EndLoop
popdef(`m4_was_default')
popdef(`m4_switch')')

Макросы Loop и EndLoop описаны здесь. Проверяем, как это работает. Пишем исходный текст

Switch(a) 
Case(1)
.. операторы если а ==1..
Case(2)
.. операторы если а ==2..
Default
.. операторы для всех остальных случаев..
EndSwitch

Получаем:

for m4_loop_counter from 0 to m4_loop_counter

if a == 1
.. операторы если а ==1..
break
end if
if a == 2
.. операторы если а ==2..
break
end if
.. операторы для всех остальных случаев..
break
end for

Все честно, как и должно быть. Проверим вложенные операторы Switch:

Switch(a) 
Case(1)
.. операторы если а ==1..
         Switch(aaaaaaa)
         Case(100)
                  .. операторы если aaaaaaа ==100..
         Case(200)
                  .. операторы если аaaaaaa ==200..
         EndSwitch
Case(2)
.. операторы если а ==2..
Default
.. операторы для всех остальных случаев..
EndSwitch

Результат:

for m4_loop_counter from 0 to m4_loop_counter
  if a == 1
     .. операторы если а ==1..
     for m4_loop_counter from 0 to m4_loop_counter 
              if aaaaaaa == 100
                   .. операторы если aaaaaaа ==100..
                   break
              end if
              if aaaaaaa == 200
                  .. операторы если аaaaaaa ==200..
                  break
              end if
break      end for
    break
  end if
  if a == 2
        .. операторы если а ==2..
        break
  end if
  .. операторы для всех остальных случаев..
  break end for

И здесь все нормально. Можно пользоваться.

Если внимательно присмотреться к макросам, то станет видно, что между операторам Switch и первым Casе можно вставить произвольные операторы и результат все равно будет допустимым. Я не вижу смысла запрещать эту возможность.

P.S. Осталось только проверить, чтобы выбор Default был последним в списке возможных значений. Это нетрудно, оставляю это заинтересованному читателю.

См. также:

Комментарии   

# admin 21.08.2012 17:10
Развивать тему можно долго. Например, сделать вариант case для проверки попадания в диапазон:

define(`CaseIn',`ifelse($#,2,m4_close_choice
if m4_switch > = $1 and m4_switch < = $2,`err'print(I nvalid number of parameters in CASEIN choice))')
# admin 29.08.2012 17:52
Или вариант CaseList

define(`CaseList',`indir(`m4_close_choice')
pushdef(`m4_list_num')foreach(`X',`ifelse(indir(`m4_list_num'),,if,or) popdef(`m4_list _num')pushdef(` m4_list_num',1) indir(`m4_switc h') == X',$*)')

итого вот как может выглядеть оператор Switch в тексте на qpile

Switch(a)
Case(1)
.. операторы если а ==1..
CaseIn(2,15)
.. операторы если а между 2 и 15..
CaseList(33,44, 55,66)
.. операторы если a==33 или a=44 или a==55 или a==66
Default
.. операторы для всех остальных случаев..
EndSwitch

Что характерно, Case есть вариант Caselist с одним параметром. Но пусть остается как есть, для читабельности

Недостаточно прав для комментирования

Библиотека