Generické programování

 

 

Princip generického programování

Generický program je popis algoritmu pro automatizované vytváření (generování) programů. Povětšině jeden generický program dokáže generovat jednu třídu programových modulů, vzácně jednu třídu ucelených programů.

Program je v podstatě text, návod pro práci počítače. I když každý program je jedinečný, části programu (moduly) jsou si na sebe podobné. Při respektování společných znaků lze tedy vytvořit algoritmus generující textový soubor (program) pomocí neměnného textu, popisujícího kostru modulů nebo celého programu, která je doplňována proměnnými údaji, odpovídajícími potřebám programátora.

Proměnné údaje jsou v generickém algoritmu zadávány ve tvaru výrazů libovolného (přípustného) typu a v případě potřeby jsou v závěrečné fázi automaticky převáděny na znakový typ. (Na tomto principu je založeno i generování programů prostředky třídy CASE - Low Level Case). Aby v generickém programu bylo možně snadno odlišit výraz definující proměnnou část od kostry (nejde přece o opsání výrazu) je tento obvykle uzavírán do speciálních oddělovačů. Nejčastěji jsou to zdvojené ostré závorky << >>. V případě výskytu těchto znaků v generovaném programu lze definovat jiné oddělovače.

Současně si nutno uvědomit, že výsledek spojování kostry s proměnnými údaji nutno zapsat do nějakého souboru nebo alespoň ho zobrazit (obecně do výstupního souboru). Proto nutno mít nástroj, který otevírá takový soubor, umí přesměrovat výstup do tohoto souboru a mimo něj, apod. Aby tento nástroj mohl rozeznávat řádky generovaného textu od řádků programu, používá se pro předznačení řádků generovaného textu speciálních znaků. (Nejčastěji znaků zpětné lomítko \ back slash).

Generický program se tedy velice podobá generovanému. Kromě toho, že generický program umožní generovat více programů, daleko výstižněji popisuje algoritmus než vygenerovaný program. Proto se doporučuje (ale nedodržuje) každý program psát jako generický. V originální literatuře se generickým programům říká TEMPLATE (šablony, vzory).

My si pro první přiblížení představíme situaci, že máme v databázi adresy a chceme rozeslat dopisy stejného textu (například pozvánky) na tyto adresy. Neměnnou částí bude text dopisu a položky adresy budou proměnné údaje. Při generování programů bude sice tento proces složitější, bude ho nutné programově řídít, ale v podstatě jde o stejně řešený problém.

 

 

Nastavení režimu generického programování

Režim generování se ve FoxPro nastavuje příkazem:

 

SET TEXTMERGE [TO [<soubor>] [ADDITIVE]]

[WINDOW <okno>] [SHOW | NOSHOW]

 

kde klauzule ADDITIVE přesměruje výstup do rozpracovaného textového souboru (generovaného programu). Když není zadaná fráze ADDITIVE a soubor neexistuje, pak se vytvoří a otevře, jestliže existuje, bude jeho obsah přepsán, Při otevření souboru se mu přiřadí manipulační číslo a uloží se do systémové proměnné _TEXT. Soubor se uzavírá příkazem SET TEXTMERGE TO bez parametrů. Fráze WINDOW přesměruje výstup do zadaného okna. Okno musí být předtím vytvořeno, ale nemusí být aktivní. Zadáním fráze NOSHOW se zabraňuje zobrazení výstupů na obrazovku nebo v okně. Zobrazení výstupů na obrazovku nebo v okně se opět obnovuje příkazem SET TEXTMERGE SHOW.

Jelikož bude nutno v generickém programu střídat režim výpočtů a generování, nutno mít k dispozici přepínač těchto režimů. Přepínač má tvar:

 

SET TEXTMERGE [ON | OFF]

 

SET TEXT to pr309.prg             && V praxi se klíčové slovo TEXTMERGE zkracuje na TEXT

SET TEXT on                                     && Standardně je off.

 

 

Definování nestandardních oddělovačů

Když není možné požít standardních oddělovačů výrazů vyhodnocovaných při výstupu textu (to znamená znaků << >>), pak nutno programovat příkaz:

 

SET TEXTMERGE DELIMITERS [TO] [<expC1> [, <expC2>]]

 

kde výraz <expC1> definuje levý oddělovač. Výraz <expC2> definuje pravý oddělovač. Příkaz bez výrazů nastavuje standardní oddělovače. (Není-li <expC2> zadáno, platí pro oba hodnota <expC1>.)

 

SET TEXT DELI to "$$"                && Nastavení zvolených oddělovačů

.....

SET TEXT DELI                           && Nastavení standardních oddělovačů

 

 

Výstup řádků textu (řádků generovaného programu)

Pro vyznačení začátku vystupujícího řádku textu se používá znaku

\ s významem = text bude vystupovat na novém řádku

\\ s významem = text bude vystupovat na stejném řádku

 

\Zobrazení textu                           && Na  obrazovce se zobrazí text, počínaje 0. sloupcem

Zobrazení textu

SET TEXT ON

SET DATE TO GERMAN

\Dnes je <<DATE()>>.                                   && Všimnete si tečky za datem

\\ Zítra bude <<DATE()+1>>.                 && Všimnete si mezery na začátku textu

Dnes je 11.03.92. Zítra bude 12.03.92.

 

 

Výstup větších  textu

Pro výstup větších textů, jako jsou například pozvánky nebo dopisy, by vyznačování řádků vystupujících textů pomocí speciálních znaků bylo nepraktické. Proto se používá textových závorek:

 

TEXT

<řádky textu>

ENDTEXT

 

 

Cvičení

Generování textu

Příklad tisku pozvánek podle obsahu databázového souboru ADRESY. Komentář za čárou není součástí programu.

 

SET TEXT ON                                    && Nastavení textu, výstup na obrazovku

SET ESCAPE OFF

SET DATE GERMAN

SET TALK OFF

akce = "KURS ZÁKLADŮ PROGRAMOVÁNÍ PC"             && Název akce

SET DATE TO GERMAN                                           && Naše interpretace data

denz = {2.3.92}                                                           && Datum zahájení

denu = {7.3.92}                                                           && Datum ukončení

USE adresy                                                                 && Otevření souboru adres

SCAN                                                              && Přes všechny záznamy souboru adres

CLEAR                                                                                 && Začátek textu

 osloveni=IIF(SUBSTR(rod_cis,3,2)>'12',"Vážená paní",;             && Vystupující text

"Vážený  pane")

TEXT

 

Vojenská  akademie Brno

 

<<OSLOVENI>>                                                      && Rozlišen mužský a ženský rod

<<allt(hodnost)>>.  <<allt(jmeno) + ' ' + allt(prijmeni)>>             && Výstup jména

&& Výstup prázdného řádku

VÚ<<str(utvar,4)>>                                                                && Výstup čísla útvaru

<<allt(mesto)>>                                                         && Výstup města bez nadbyt. mezer

<<repl('-',len(allt(mesto)))>>                                         && Podtržení dlouhé jako název města

 

 

Dovolujeme si Vás pozvat na

 

<<akce>>,

 

konaného  ve dnech <<denz>>    <<denu>>

Zahájení v 9.00 na učebně 8/20, Kasárna Šumavská.

 

 

<<date()>>                              ......................

vedoucí kursu

 

ENDTEXT

WAIT "Zmáčknete lib. klávesu" ;

+ ", K = konec" WINDOW  TO aa

IF aa$'kK'

RETURN                                             && Konec

ENDIF (aa$'kK')

ENDSCAN

 

 

Generování programu

Ukázka jednoduchého generátoru výstupů na obrazovku nebo do okna. Parametry příkazů jsou uloženy v databázovém souboru (SAY309.DBF a SAY309.FPT). Všimneme si, že výrazy jsou ukládány do memo položek. Důvod je jasný. Nemůžeme předem vědět a omezit délku výrazu délkou znakové položky.

 

Struktura souboru SAY309

 

    ┌─────────────────────────────────────────────────────── 
    │ Structure for database: C:\KURS.PRG\SAY309.DBF         
    │ Number of data records:       3                        
    │ Date of last update   : 04/13/92                       
    │ Memo file block size  :      64                        
    │ Field  Field Name  Type       Width    Dec    Index   
         1  RD1         Numeric        2                    
         2  SL1         Numeric        2                    
         3  OBJEKT      Character      8                    
         4  VYRAZ       Memo          10                    
         5  RD2         Numeric        2                    
         6  SL2         Numeric        2                    
    │ ** Total **                      27                    
                                                            
    └─────────────────────────────────────────────────────── 

 

Obsah souboru SAY309

 

┌───────────────────────────────────────────────────────────────────── 
│ Record#  RD1 SL1 OBJEKT   VYRAZ                          RD2 SL2     
                                                                      
       1    5   6 SAY      "Pokusný text 1., objekt SAY"    0   0     
       2    2   2 TO       double                          10  50     
       3    7   6 SAY      "Pokusný text 2., objekt SAY"    0   0     
└───────────────────────────────────────────────────────────────────── 

 

Programové řešení

 

CLEAR                                                                                   && Výmaz obrazovky

nazev="  Generování programu podle dat souboru say309"

@ 1,1 SAY nazev                                                              && Zobrazení názvu příkladu

@0,0 TO 2,LEN(nazev)+2 DOUBLE                         && Rámeček kolem názvu

?

DEFINE WINDOW pokus FROM 10,20 TO 24,78 COLOR SCHEME 12

&& Okno pro zobrazení vygenerovaného programu

SET TEXT TO pokus309_2.prg          && Název generovaného programu

SET TEXT ON                                                && Nastavení režimu TEXTMERGE

\CLEAR                                              && Začátek programu

USE say309                                        && Soubor s parametry

SCAN

DO generuj_vystup                      && Vlastní generování

ENDSCAN

SET TEXT OFF                            && Konec generování

SET TEXT TO

WAIT "Konec CTRL+ENTER" WINDOW NOWAIT

MODIFY COMM pokus309_2.prg WINDOW pokus

&& Zobrazení  programu, lze editovat

RELEASE WINDOW pokus                                      && Výmaz okna

CLEAR

CLEAR PROGRAM                                                     && Výmaz programu

 

PROCEDURE generuj_vystup

\@ <<rd1>>, <<sl1>> <<alltrim(objekt)>>                        && Řádek, sloupec objekt

IF !EMPTY(rd2)

<<rd2>>, <<sl2>>                                                 && Souřadnice ukončení jen když jsou

ENDIF (!empty(rd2))                                                 && zadány

<<vyraz>>

 

 

Výsledný program

 

┌──────────────────────POKUS309.PRG─────────────────────── 
│ CLEAR                                                    
│ @ 5, 6 SAY "Pokusný text 1., objekt SAY"                 
│ @ 2, 2 TO 10, 50 double                                  
│ @ 7, 6 SAY "Pokusný text 2., objekt SAY"                 
└─────────────────────────────────────────────────────────