35. Rozšírenia jazyka: CONST, ENUM, CASE, hodnoty z porovnaní, pretypovanie

Na čo to je

Jazyk Action! je z roku 1983 a niektoré veci, ktoré sú dnes bežné, v ňom chýbajú. action26 ich vie doplniť. Sú vypnuté, kým si o ne nepovieš – starý program sa tak nikdy nepokazí tým, že má napríklad premennú menom CASE.

Rozšírenia zapneš riadkom na začiatku zdrojáka:

Action!
;@modern

alebo voľbou --modern na príkazovom riadku. Program s rozšíreniami pôvodný Action! nepreloží. Ak má tvoj program bežať aj v ňom, túto a ďalšie kapitoly nepoužívaj.

Každé rozšírenie má v tejto kapitole vlastný krátky program. Všetky sa prekladajú rovnako – ;@modern si nesú v sebe:

action26 m-const.act --sim

CONST: pomenované konštanty

Na čo to je

DEFINE z kapitoly 17 nahrádza text a má pascu: DEFINE SIZE="5+5" a SIZE*2 dá 15. CONST je pomenovaná hodnota: prekladač ju vypočíta raz a ďalej s ňou narába ako s číslom.

Ako sa to píše

Action!
CONST MENO=výraz
CONST MENO1=výraz, MENO2=výraz
CONST TYP MENO=výraz

Výraz môže obsahovať čísla, znaky, skoršie konštanty a operátory. Hodnota sa píše bez úvodzoviek.

Celý program

Súbor examples/m-const.act:

Action!
;@modern
; CONST: named values worked out by the compiler

CONST WIDTH=20, HEIGHT=3
CONST CELLS=WIDTH*HEIGHT     ; a constant may use earlier ones
CONST SIZE=5+5
CONST CHAR FRAME='#

PROC Main()
  BYTE x, y

  FOR y=1 TO HEIGHT
  DO
    FOR x=1 TO WIDTH
    DO
      Put(FRAME)
    OD
    PutE()
  OD

  Print("Cells: ")
  PrintBE(CELLS)
  Print("SIZE*2: ")
  PrintBE(SIZE*2)            ; 20 - with DEFINE it would be 15
RETURN
####################
####################
####################
Cells: 60
SIZE*2: 20

Ako to funguje

CELLS je 60 už pri preklade – v programe sa nič nenásobí. SIZE*2 je 20, lebo SIZE je hodnota 10, nie text 5+5. Konštanta nezaberá pamäť a nedá sa do nej priradiť.


ENUM: vlastný typ s pomenovanými hodnotami

Na čo to je

Stav semaforu, smer pohybu, druh nepriateľa – veci, ktoré majú niekoľko pevných možností. S číslami (0 = červená, 1 = zelená) sa ľahko pomýliš. ENUM dá možnostiam mená a prekladač stráži, aby sa nepomiešali s obyčajnými číslami.

Ako sa to píše

Action!
TYPE Meno=ENUM [PRVA, DRUHA, TRETIA]

Meno premenna
premenna=Meno.PRVA

Hodnota sa píše s menom typu a bodkou: Light.RED. Členy dostanú čísla 0, 1, 2 …

Celý program

Súbor examples/m-enum.act:

Action!
;@modern
; ENUM: a type of your own with named values

TYPE Light=ENUM [RED, GREEN, YELLOW]

Light FUNC Next(Light now)
  IF now=Light.RED THEN
    RETURN(Light.GREEN)
  FI
  IF now=Light.GREEN THEN
    RETURN(Light.YELLOW)
  FI
RETURN(Light.RED)

PROC Show(Light l)
  CASE l OF
  WHEN Light.RED THEN
    PrintE("red - stop")
  WHEN Light.GREEN THEN
    PrintE("green - go")
  WHEN Light.YELLOW THEN
    PrintE("yellow - wait")
  ESAC
RETURN

PROC Main()
  Light l=[Light.RED]
  BYTE i

  FOR i=1 TO 5
  DO
    Show(l)
    l=Next(l)
  OD

  Print("The last value as a number: ")
  PrintBE(BYTE(l))
RETURN
red - stop
green - go
yellow - wait
red - stop
green - go
The last value as a number: 2

Ako to funguje

Light sa používa ako každý typ: pre premennú, parameter aj výsledok funkcie. Prekladač nedovolí l=1 ani PrintB(l) – hodnota typu Light nie je číslo. Keď číslo naozaj potrebuješ, povieš to výslovne: BYTE(l). Opačne Light(2) spraví z čísla člen.


CASE: výber z viacerých možností

Na čo to je

Dlhá reťaz IF … ELSEIF … ELSEIF …, ktorá skúša stále tú istú premennú, sa číta ťažko. CASE ju zapíše prehľadne.

Ako sa to píše

Action!
CASE výraz OF
WHEN hodnota THEN
  príkazy
WHEN hodnota1, hodnota2 THEN          ; viac hodnôt
  príkazy
WHEN od TO do THEN                    ; rozsah vrátane hraníc
  príkazy
WHEN od TO do IF podmienka THEN       ; rozsah a navyše podmienka
  príkazy
ELSE
  príkazy                             ; keď nesedelo nič
ESAC

Vykoná sa prvá vetva, ktorá sedí, a žiadna ďalšia. ELSE je nepovinné. ESAC (CASE odzadu) príkaz končí.

Celý program

Súbor examples/m-case.act:

Action!
;@modern
; CASE: choose one branch by a value

PROC Describe(BYTE n)
  PrintB(n)
  Print(": ")
  CASE n OF
  WHEN 0 THEN
    PrintE("zero")
  WHEN 1 TO 9 THEN
    PrintE("one digit")
  WHEN 10, 100 THEN
    PrintE("ten or a hundred")
  WHEN 11 TO 99 IF n MOD 11=0 THEN
    PrintE("two digits, both the same")
  WHEN 11 TO 99 THEN
    PrintE("two digits")
  ELSE
    PrintE("a big number")
  ESAC
RETURN

PROC Main()
  Describe(0)
  Describe(7)
  Describe(10)
  Describe(33)
  Describe(42)
  Describe(100)
  Describe(200)
RETURN
0: zero
7: one digit
10: ten or a hundred
33: two digits, both the same
42: two digits
100: ten or a hundred
200: a big number

Ako to funguje

Číslo 33 sedí do rozsahu 11 TO 99 a spĺňa aj podmienku za IF (je deliteľné jedenástimi), takže sa vykoná prvá z dvoch vetiev. Číslo 42 do rozsahu sedí, ale podmienku nespĺňa – ide sa na ďalšiu vetvu. Podmienke pri WHEN sa hovorí stráž.

Prekladač stráži aj teba: keby sa tá istá hodnota vyskytla v dvoch vetvách bez stráže, druhá by sa nikdy nevykonala – a to je chyba prekladu (ACT234).


Porovnanie, IF a CASE ako hodnota; pretypovanie

Na čo to je

V pôvodnom Action! patrí porovnanie len do podmienky. S rozšíreniami je porovnanie aj hodnota – 1, keď platí, 0, keď neplatí. Hodnotou môže byť aj celý IF a CASE. A pretypovanie povie, v akom type sa má počítať.

Ako sa to píše

ZápisHodnota
(a>b)1 alebo 0
IF podm THEN x ELSE y FIx alebo y; ELSE je povinné
CASE v OF WHEN … THEN x … ELSE y ESAChodnota zvolenej vetvy
BYTE(x), CARD(x), INT(x), CHAR(x)x čítané ako daný typ

Celý program

Súbor examples/m-value.act:

Action!
;@modern
; Comparisons, IF and CASE as values, and casts

PROC Main()
  CHAR ARRAY text="one, two, three, four"
  BYTE a, b, bigger, commas, i
  CHAR grade
  CARD sum

  a=7
  b=12

  bigger=IF a>b THEN a ELSE b FI          ; IF as a value
  Print("The bigger one: ")
  PrintBE(bigger)

  commas=0
  FOR i=1 TO text(0)
  DO
    commas==+(text(i)=',)                 ; a comparison is 1 or 0
  OD
  Print("Commas in the text: ")
  PrintBE(commas)

  grade=CASE b OF                         ; CASE as a value
        WHEN 0 TO 4 THEN 'C
        WHEN 5 TO 9 THEN 'B
        ELSE 'A
        ESAC
  Print("Grade: ")
  Put(grade)
  PutE()

  a=200
  b=100
  sum=a+b                                 ; BYTE + BYTE overflows
  Print("200 + 100 as BYTE: ")
  PrintCE(sum)
  sum=CARD(a)+b                           ; the cast makes it a CARD sum
  Print("200 + 100 with CARD(a): ")
  PrintCE(sum)
RETURN
The bigger one: 12
Commas in the text: 3
Grade: A
200 + 100 as BYTE: 44
200 + 100 with CARD(a): 300

Ako to funguje


Časté chyby

Čo sa staloČo povie prekladač
chýba ;@modernchyby na prvom rozšírení – napr. error ACT011: unexpected '*' pri CONST
priradenie do konštantychyba – konštanta nie je premenná
číslo do premennej typu ENUM (l=1)error ACT237
tá istá hodnota v dvoch vetvách CASEerror ACT234
IF ako hodnota bez ELSEerror ACT235
;@modern spolu s ;@quirkserror ACT231

Vyskúšaj si

  1. Prepíš define.act z kapitoly 17 pomocou CONST.
  2. Pridaj semaforu štvrtý stav RED_YELLOW medzi červenú a zelenú.
  3. Napíš CASE, ktorý podľa čísla mesiaca vypíše ročné obdobie.

Zhrnutie

Podrobnejšie lekcie ku každému rozšíreniu sú v priečinku examples/modern/ (lekcie 6 až 11).

Späť: 34. Disky · Ďalej: 36. Rozšírenia pre dáta