Programmeren in REXX/Voorbeeld 2

Uit Wikibooks
Naar navigatie springen Naar zoeken springen

   Programmeren    in REXX


Ons tweede uitgewerkt programma is handig om na te gaan welke conversies kunnen werken en welk resultaat we mogen verwachten. We leerden de conversiefuncties kennen in Programmeren in REXX/Functies deel 2#Omzetten van formaten. Het is echter niet altijd zeer intuïtief om te weten welke functie tot het beoogde resultaat leidt.

Een alfabetisch karakter omzetten naar een decimaal getal (C2D) lukt al bijvoorbeeld niet. En, moeten we het karakter "A" naar hexadecimaal of naar decimaal omzetten om zijn plaats in de karaktertabel te kennen ? Hoe kan het karakter "A" binair worden voorgesteld ? Enzovoort. Al deze vragen worden op een overzichtelijke manier beantwoord met dit programmaatje.

REXX-code: XtoX.rex

  1 | /*****************************************************************
  2 |  Dit programma toont alle REXX conversie functies (bv. C2X)
  3 |     +-----------------------------------------------------------+
  4 |     | formaat: | XTOX waarde                                    |
  5 |     +-----------------------------------------------------------+
  6 |   Waarde kan ook in hexadecimaal formaat gegeven worden '..'X
  7 |   Probeer bijvoorbeeld XTOX 15 of XTOX 'F1'X
  8 |   18 Jul 1989: creatie
  9 |   20 Dec 2000: B2X en X2B functies toegevoegd                    
 10 | ******************************************************************/                                             
 11 | parse arg arg . 1 kar1 2                     /* Argument ophalen */
 12 | hex=0                  /* veronderstel geen hexadecimale notatie */
 13 | if kar1="'" | kar1='"' then           /* als begin een ' of " is */
 14 |    if translate(right(arg,1))='X' then        /* en rechts een X */
 15 |       parse value 1 translate(arg,"'",'"'), 
 16 |              with hex arg                   /* vertalen en hex=1 */
 16 | 
 17 | if hex then do                            /* als hexadecimaal is */
 18 |    parse var arg "'" arg "'"            /* karakters er uithalen */
 19 |    if \datatype(arg,'X') then do       /* verifiëren of geldig X */
 20 |       say '"'arg'" is geen geldige hex data' ; exit 5;end
 21 |    arg=x2c(arg)                        /* omzetten naar karakter */
 22 | end
 23 | /* Nu hebben we geldige karakters, dus alle conversies proberen  */
 24 | call  test C2D
 25 | call  test C2X
 26 | call  test D2C
 27 | call  test D2X
 28 | call  test X2C
 29 | call  test X2D
 30 | call  test X2B
 31 | call  test B2X
 32 | exit
 33 | /* Functie TEST gaat na of conversie werkt en toont resultaat    */
 34 | TEST: parse arg functie                     /* Welke conversie ? */
 35 |  signal on syntax                  /* intercepteer syntax fouten */
 36 |  interpret "val="functie"(arg)"                      /* voer uit */
 37 |  say left(functie'('arg')='val,20)left("=X'"C2X(val)"'",30)
 38 | return
 39 | /* SYNTAX procedure wordt opgeroepen als conversie mislukt       */ 
 40 | SYNTAX:
 41 |  say functie'('arg')=onmogelijk'          /* zeg dat het fout is */
 42 |  return
  • 1 tot 10: mooie inleidende commentaar voor het programma. Ook historiek van veranderingen.
  • 11: ophalen van het argument, waarbij eerste karakter in kar1 wordt gezet;
  • 13: als links een ' of een " staat kunnen we te doen hebben met een hexadecimale notatie;
  • 14: maar dan moet rechts een "X" staan;
  • 15: dan zetten we hex=1 en vertalen we een eventuele " in '. Gewoon altijd het argument vertalen mag niet, want dan zou het argument geen ' of " meer mogen zijn;
  • 17: als we nu een hexadecimale notatie hebben...
  • 18: halen we de hexadecimale karakters eruit...
  • 19: we gaan na of de karakters geldige hexadecimale karakters zijn, en...
  • 20: tonen foutbericht en stoppen de procedure met code 5 als dat niet het geval is.
  • 21: anders zetten we de hexadecimale karakters om naar gewone karakterstring;
  • 24: nu roepen we een test subroutine op, één voor één met de namen van de mogelijke conversiefuncties;
  • 34: de functie pikt de naam van de conversiefunctie op;
  • 35: dit is de voornaamste regel in deze procedure. Door een signal on syntax zetten we de detectie van syntaxis fouten aan. Indien een fout wordt ontdekt springen we naar het label syntax:;
  • 36: omdat we de naam van de functie als variabele binnenkregen moeten we een interpret bevel gebruiken om de functie op te roepen. Sommige conversies zijn echter niet toegelaten, voornamelijk als een niet numerieke string een getal zou moeten worden via de D2... functies;
  • 37: heeft de functie wél een resultaat gegeven, dan kunnen we dat afdrukken, en de functie beëindigen;
  • 40: de syntax: routine wordt dus opgeroepen bij een ongeldige conversie. We melden dit ook en keren tenslotte ook terug naar de hoofdroutine.

Meer over signal on syntax leren we in het hoofdstuk Debugging. Laten we naar een paar keer het programma uitvoeren:

C:\Users\Dmitri>rexx d:\RexxProgrammas\xtox "42"x
C2D(B)=66                               =X'3636'
C2X(B)=42                               =X'3432'
D2C(B)=onmogelijk
D2X(B)=onmogelijk
X2C(B)=♂                                =X'0B'
X2D(B)=11                               =X'3131'
X2B(B)=1011                             =X'31303131'
B2X(B)=onmogelijk

Onze hexadecimale waarde '42'x is in het begin van het programma als dusdanig herkend en omgezet naar het karakter "B". Dit karakter proberen we nu op alle mogelijke manieren om te zetten. Het is geen numeriek getal, dus dat de omzetting van decimaal mislukt was te verwachten. Merk ook op dat het nuttig is zowel de karakterwaarde van het resultaat als de hexadecimale notatie ervan te tonen. We zien inderdaad dat X2C(B) een raar karakter produceert. Hexadecimaal heeft het de waarde '0B'x, en dat ligt in de reeks controlekarakters. Als we het programma met karakter "A" als parameter uitvoeren, hebben we een mooi voorbeeld van wat er kan gebeuren:

C:\Users\Dmitri>rexx d:\RexxProgrammas\xtox A
C2D(A)=65                               =X'3635'
C2X(A)=41                               =X'3431'
D2C(A)=onmogelijk
D2X(A)=onmogelijk
X2C(A)=
                                =X'0A'
X2D(A)=10                               =X'3130'
X2B(A)=1010                             =X'31303130'
B2X(A)=onmogelijk

Bij de X2C omzetting bekomen we de waarde '0A'x en dat is een Line-Feed... dus we gaan inderdaad naar de volgende lijn om het resultaat te tonen, en het alignement van de tekst gaat verloren.

In het begin van het hoofdstuk vroegen we ons af hoe we de binaire voorstelling van het karakter "A" konden bekomen. Wel, uit deze resultaten kunnen we besluiten dat X2B() al zeker niet de goede oplossing is, we moeten een dubbele conversie hanteren, namelijk X2B(C2X(A)). Inderdaad:

C:\Users\Dmitri>rexx d:\RexxProgrammas\xtox 41
C2D(41)=13361                           =X'3133333631'
C2X(41)=3431                            =X'33343331'
D2C(41)=)                               =X'29'
D2X(41)=29                              =X'3239'
X2C(41)=A                               =X'41'
X2D(41)=65                              =X'3635'
X2B(41)=01000001                        =X'3031303030303031'
B2X(41)=onmogelijk

Die 41 is de hexadecimale voorstelling van het karakter A, dus binair bekomen we "01000001"b. Idealiter zou ons programma dus ook alle dubbele omzettingen moeten uitproberen zodat het voor ons nog gemakkelijker wordt. Maar dit laten we aan de lezer over.

In het laatste voorbeeld is enkel de B2X omzetting niet meer mogelijk omdat we geen binaire string als input hebben gegeven.

Zonder verdere uitleg geven we nog een tweede, gelijkaardig programma cadeau. Het toont alle formaten waarin een bepaalde datum kan worden gemaakt met de date() functie:

REXX-code: RexxDates.rex

/* Toon alle Rexx date() variaties
    +-----------------------------------------------------------+
    | format:  | REXXDATES <inputdatum>                         |
    +-----------------------------------------------------------+
21 Dec 2000: Accepteer een datum als input                       */
parse arg indatum '' t ; indatum=strip(indatum)
fmts='Basedate Days European Month Normal Ordered',
     'Sorted Usa Weekday'
fmtsep='European Normal Ordered Sorted Usa'
NbFm=words(fmts)
/*----------------------------------------------------------------*/
/* Geval 1: geen datum meegegeven, toon vandaag in alle formaten  */
/*----------------------------------------------------------------*/
if indatum='' then do
   say 'De DATE functie kan volgende formaten produceren:'
   do i=1 to NbFm
      call rexdate word(Fmts,i)
   end i
   exit
end
/*----------------------------------------------------------------*/
/* Geval 2: we kregen wel een datum binnen                        */
/*----------------------------------------------------------------*/
if length(indatum)=10 then 
   if substr(indatum,5,1)substr(indatum,8,1)='--'
      then indatum=left(indatum,4)substr(indatum,6,2)substr(indatum,9) 
ValidFmts=''
do i=1 to NbFm
   ValidFmts=ValidFmts CkDate(word(fmts,i))
end
If ValidFmts='' then do
   Say 'Datum' indatum 'is geen geldige REXX datum formaat.'
   exit 56
end
say 'De DATE functie kan volgende formaten produceren voor "'indatum'"'
ld=length(indatum)+19
Do while ValidFmts<>''
   out.=''
   Do 3 while ValidFmts<>''
      parse var ValidFmts fmt ValidFmts
      Out.0tit=Out.0tit left(fmt,12)
      do i=1 to NbFm
         fmto=word(Fmts,i)
         out.fmto=out.fmto GivDate(fmtO,indatum,Fmt)
      end i
   end
   Say right('? ===>',ld+5) Out.0tit
   do i=1 to NbFm
      fmto=word(Fmts,i)
      t='Date('left(fmto,8)','indatum',"?")'
      say '  'left(t,ld) '= ' Out.fmto
   end i
end
exit
 
REXDATE:
 parse arg fmt
 if wordpos(fmt,fmtSep)=0
   then say '  'left('Date('fmt')',15)'= ' date(fmt)
   else say '  'left('Date('fmt')',15)'= ' left(date(fmt),12),
            left('Date('fmt',,,"-")',20)'= '   date(fmt,,,'-')
return
 
CkDate:
 Signal on syntax name InvDate
 call date 'U',indatum,arg(1)
 return arg(1) /* Formaat is mogelijk */
InvDate: return '' /* Formaat is onmogelijk */
GivDate:
 Signal on syntax name InvDate2
 return left(date(arg(1),arg(2),arg(3)),12)
InvDate2: return '*Onmogelijk*'

Dit is een mogelijke output van het programma:

C:\Users\Dmitri>rexx d:\RexxProgrammas\rexdates
De DATE functie kan volgende formaten produceren:
  Date(Basedate) =  734470
  Date(Days)     =  334
  Date(European) =  30/11/11     Date(European,,,"-")=  30-11-11
  Date(Month)    =  November
  Date(Normal)   =  30 Nov 2011  Date(Normal,,,"-")  =  30-Nov-2011
  Date(Ordered)  =  11/11/30     Date(Ordered,,,"-") =  11-11-30
  Date(Sorted)   =  20111130     Date(Sorted,,,"-")  =  2011-11-30
  Date(Usa)      =  11/30/11     Date(Usa,,,"-")     =  11-30-11
  Date(Weekday)  =  Wednesday

en indien een datum is opgegeven:

C:\Users\Dmitri>rexx d:\RexxProgrammas\rexdates 20111216
De DATE functie kan volgende formaten produceren voor "20111216"
                          ? ===>  Basedate     Sorted
  Date(Basedate,20111216,"?") =   20111216     734486
  Date(Days    ,20111216,"?") =   235          350
  Date(European,20111216,"?") =   23/08/63     16/12/11
  Date(Month   ,20111216,"?") =   August       December
  Date(Normal  ,20111216,"?") =   23 Aug 55063 16 Dec 2011
  Date(Ordered ,20111216,"?") =   63/08/23     11/12/16
  Date(Sorted  ,20111216,"?") =   550630823    20111216
  Date(Usa     ,20111216,"?") =   08/23/63     12/16/11
  Date(Weekday ,20111216,"?") =   Sunday       Friday

Dit tweede voorbeeld hoeft misschien een extra woordje uitleg: nu geven we een datum mee als parameter. Maar we zeggen nergens welk formaat die datum heeft. In dit geval kan 20111216 zowel een geldige Base datum als een geldige Sorted datum zijn. Daarom test RexDates welke formaten het kunnen zijn. En dus bevat het antwoord die twee kolommen, de eerste voor het geval dat input een Base datum is, de tweede als het een Sorted datum zou betreffen.

Informatie afkomstig van http://nl.wikibooks.org Wikibooks NL.
Wikibooks NL is onderdeel van de wikimediafoundation.