Attribuutidega lekseemide moodustamine FLEX-i abil

Sageli on soovitav/loomulik, et lekseemil oleks peale tavaliste, "klassikaliste" attribuutide (koht lähtetekstis, tüüp, võibolla viit nimede tabelisse) veel mingeid attribuute. Selline lekseem oleks näiteks - HTML-i <img> märgend - loomulik oleks, et kõik märgendi img attribuudid (src, width, height jne) tuleks ka skaneerimisel loodava lekseemi attribuutideks; sellised on ka XML-keele märgendite attribuudid.

Veel rohkem on attribuute SMIL-keele märgenditel; järgnevas vaatlemegi Flex-i abil attribuutidega lekseemide genereerimist SMIL-keele näite abil.

SMIL on keel WWW abil levitatavate multimeediaesituste kirjeldamiseks. Kui HTML on orienteeritud staatilise meedia (tekst, pildid) esitamiseks ja ajas toimuvaid meediaklippe (heli, video) saab vaid võõrkehadena sisestada, kuid peaaegu üldse mitte kontrollida, siis SMIL on loodud dünaamiliste, video- ja heliklippe sisaldavate esituste kirjeldamiseks, kusjuures korraga võib olla käivitatud mitu erinevat meediaklippi. Kogu ekraan on jagatud regioonideks ja esituse toimumist kirjeldatakse paralleelsete <par>...</par> ja järjestikuste <seq>...</seq> tegevuste abil. Iga meediaklipi jaoks kirjeldatakse nii selle käivitamise/lõpetamise aeg, koht(regioon) ekraanil, kus see käivitatakse jne, s.t. meediaklippide esitust kontrollivatel märgenditel <img>, <audio>, <text> on mitmesuguseid attribuute.

SMIL on HTML-i multimeedia-laiendus ja SMIL-dokument sarnaneb struktuurilt HTML-dokumendiga. SMIL- dokument on märgendite <smil> , </smil> vahel ja koosneb päisest (märgendite <head></headl> vahel) ja kehast (märgendite <body>...</body> vahel); need on kohustuslikud. Päises on märgendite <layout>...</layout> vahel kirjeldatud ekraani multimeediaregioonid (kohustulik osa). Regioonide kirjeldus algab kogu dokumendi regiooni kirjeldusega ( root-layout; see võib ka puududa, kuid kui on, siis ainult üks) millele järgnevad (alam)regioonid. Regiooni kirjelduse märgend algab <region ja lõpeb />; regiooni kirjelduse kohustuslik osa on regiooni nimi: id = string; regiooni kirjelduses määratakse ka selle asukoht ekraanil, kuid lihtsustamiseks on paljud SMIL-keele detailid siin ära jäetud.

Keha koosneb paralleelselt ja järjestikku täidetavate/esitetavate osade kirjeldustest. Paralleelste osade kirjeldus algab <par id= string >, lõpeb </par>; järjestikku esitatavate osade kirjeldus algab <seq id= string > ja lõpeb </seq> . Igas osas määratakse meediategevused, mis on kas heli: <audio id = string /> või pilt : <img id = string /> (stringid on failinimed). Osasid võib olla kuitahes palju (0,1,...). On lubatud osade sisestamine, st paralleelse osa sees võib olla üks või enam järjestikku täidetavatest osadest; lihtsustatud SMIL-is osasid ei sisestata, nad järgnevad üksteisele. Järgnevas on väike näide SMIL-dokumendist:

<smil>
<head>
<layout>
<root-layout id = "The Great Wall of China"/>
<region id = "image1" />

<region id = "image2" />
<region id = "text"/>
<region id = "music"/>
</layout>
</head>
<body>

<par id="Presentation">
<audio id ="audio" region="music" />
<img id = "fortress" region = "image1" />
<img id = "first_view" region = "image2" />

</par>
</body>
</smil>

Märgendite par, audio, img attribuutide id, region väärtused on loomulik kanda (laiendatud) nimede tabelisse, mis sisaldab kõiki töödeldava (skaneeritava) SMIL-esituse kirjelduse (SMIL-programmi) identifikaatoreid; skaneerimisel asendatakse identifikaatorid viitega sellesse tabelisse (sellesse tuleb ka identifikaatori tüüp ja viit mäluosale, kus salvestatakse identifikaatori väärtus).

Lekseemile attribuutide lisamiseks peab skanneril olema mälu. Kui näiteks HTML-i <img> -märgendil on attribuudid width, height (need esitatakse <img>-märgendis kujul "width=integer", "height=integer"), peab skanner pärast täisarvu (integer) lugemist mäletama, kas eespool oli "width=" või "height=", et kanda integer õige attribuudi (width, height) väärtuseks. Täpselt samuti peab SMIL-i <img>, <audio> attribuutide "regioon=string", "id=string" töötlemisel pärast stringi lugemist mäletama, kas eespool viidati regioonile või id-le, s.t. skanner töötab siin nagu lõplik automaat (tegelikult on kõik Flex-i abil genereeritud skannerid lõplikud automaadid).

"Mälu" saab skannerile anda mitmel viisil - võib kasutada kas Flex-i olekuid või C-keele muutujaid. Skanneri olekute kasutamine on väga loomulik ka nn sisestatud programmitekstide skaneerimisel - kui näiteks HTML-keelses tekstis algab PHP-keeles kirjutatud osa, on loomulik viia skanner PHP-analüüsiks teise olekusse. Järgnevas on Flex-i olekuid kasutatud SMIL-märgendite tüübi  eristamiseks.

SMIL-keele audio- ja img-märgenditesl on mitu ühesugust attribuuti, kuid nende väärtused oleks loomulik salvestada erinevates tabelites. Skaneerimisel loetakse algul märgendi tüüp: audio või img ja skanner peab seda attribuudi väärtuseni jõudes "mäletama".  Varem loetud märgijada meelespidamiseks võib  kasutada Flex-i alustamistingimusi (start-conditions).

Järgnevas on lihtne näide, kus  SMIL-keele audio- ja img-märgenditest moodustatakse järgneva struktuuriga lekseemid:

struct lexemtype
{
char type[6]; char id[10]; char region[10]; };
struct lexemtype lexem;

Kontrolliks trükitakse see struktuur alamprotseduuri tag_out abil märgendi lõppedes välja:

void tag_out(struct lexemtype lexem)
{
printf("< %s, %s, %s >\n",lexem.type,lexem.id,lexem.region); return; }

Lekseemi moodustamisel saab lekseemi tüübi määrata juba lekseemi alguse <audio või <img lugemisel, seega kui Flex-programmi definitsioonide (esimeses) osas on kirjeldus:

START_AUDIO_TAG "<audio"{WHITE_CHAR}+

siis programmi teises (reeglite) osas võib määrata vastava semantilise tegevuse:

{START_AUDIO_TAG} {
strcpy(lexem.type,"audio"); }

Kuid id- või region-attribuudi väärtuse (string) lugemise järel peab teadma, kas loetud string tuleb kirjutada lekseemi id- või region-välja, ja selle info meelespidamiseks (kas enne loetud stringi oli id = või region = ) saab kasutada Flex-i alustamistingimusi (olekuid). Kui skanner loeb sisendist mitteterminaliga ATTR_ID kirjeldatud märgijada id=, täidetakse alustamistingimus BEGIN(READ_ID), mis määrab, et skanner läheb olekusse READ_ID. Alustamistingimus määrab skanneri sees n.ö. "alamskanneri" - reeglid, mida täidetakse vaid selles olekus; analoogiliselt märgijada region= viib skanneri olekusse READ_REG; nendes olekutes stringi lugemisel teab skanner, millisesse lekseemi välja loetud string tuleb kirjutada. Alustamistingimusele vastavate reeglite ette tuleb kirjutada see tingimus nurksulgude < > vahel; kui tingimusele vastavaid reegleid on rohkem, võib nad figuursulgude { } abil kokku võtta:

ATTR_ID    "id"{WHITE_CHAR}*"="{WHITE_CHAR}*
ATTR_REG    "region"{WHITE_CHAR}*"="{WHITE_CHAR}*
...
%%
...
{ATTR_ID}    BEGIN(READ_ID);
<READ_ID>{STRING}    strcpy(lexem.id,yytext);

{REG_ID}    BEGIN(READ_REG);
<READ_REG>{STRING}    strcpy(lexem.region,yytext);

Alustamistingimusi on kahesuguseid - välistavad ja lubavad. Välistavad tingimused ei luba tingimuse kehtimise ajal kasutada tavalisi (ilma tingimusteta defineeritud) reegleid; lubavate tingimuste korral võib (kui tingimusega määratud reeglite seas sobivat pole) kasutada ka ilma tingimusteta reegelid (tingimusega reegleid võib alati kasutada vaid vastava tingimuse kehtides).

SMIL-i märgendites võib üks (või mõlemad) attribuutidest id, region ka puududa, s.t. pole teada, millal leitakse märgendi lõpp. Sellepärast on siin kasutatud lubavaid alustamistingimusi, mille korral märgendi lõpu reegli võib täita niipea kui sisendis leitakse alamjada \>:

TAG_STOP     "/>"
...
%%
...
{TAG_STOP} {
tag_out(lexem);
strcpy(lexem.id,""); strcpy(lexem.region,""); BEGIN(INITIAL);
}

Tühja stringi omistamised pärast lekseemi väljastamist on vajalikud - kuna id ja/või region-attribuudid võivad järgmisel lekseemil puududa, tuleb vastavad väljad struktuuris lexem tühjaks teha!

Alustamistingimused peab loetlema programmi esimese (definitsioonide) osa algul; välistavate tingimuste ette (esimesest positsioonist) tuleb kirjutada %x, lubavate tingimuste ette %s. Et alustamistingimusi saaks kasutada, peab Flex-programmi algusesse lisama võtme %option stack.

Järgneb kogu Flex-programm SMIL-i audio ja img-märgenditest struktuursete lekseemide moodustamiseks:

%option noyywrap
/* grammatika Smil-margenditest parametriseeritud lekseemide tegemiseks */
%option stack
/* vajalik alustamistingimuste kasutamiseks */
%{
#include <string.h> /* vajalik strcpy saamiseks */
struct lexemtype
{
char type[6];
char id[10];
char region[10];
};
struct lexemtype lexem;
void tag_out(struct lexemtype lexem)
{
printf("< %s, %s, %s >",lexem.type,lexem.id,lexem.region);
return;
}
%}

 

%s READ_ID READ_REG
NUMBER [0-9]
TAHT    [a-zA-Z]
TAHTNUM   {TAHT}|{NUMBER}|[ \t"_""-"]
WHITE_CHAR    [ \n\t]

TAG_STOP    "/>"
ATTR_ID    "id"{WHITE_CHAR}*"="{WHITE_CHAR}*
ATTR_REG    "region"{WHITE_CHAR}*"="{WHITE_CHAR}*
STRING    \"{TAHTNUM}*\"{WHITE_CHAR}*
START_AUDIO_TAG    "<audio"{WHITE_CHAR}*
START_IMG_TAG    "<img"{WHITE_CHAR}*

%%
{START_AUDIO_TAG} {
/* printf("\n audio, state %d: ",YYSTATE); */ strcpy(lexem.type, "audio"); }
{START_IMG_TAG} {
/*printf("\n image, state %d: ",YYSTATE);*/ strcpy(lexem.type, "img"); }

{ATTR_ID} BEGIN(READ_ID);/*printf("READ_ID, state: %d\n",YYSTATE);*/
<READ_ID>{STRING} strcpy(lexem.id, yytext);

{ATTR_REG} BEGIN(READ_REG);/* printf("READ_REG, state=%d\n", YYSTATE); */
<READ_REG>{STRING} strcpy(lexem.region, yytext);

{TAG_STOP} {
/*printf("tag_end, state:%d \n",YYSTATE); */ tag_out(lexem); strcpy(lexem.id, ""); strcpy(lexem.region, ""); BEGIN(INITIAL); }
%%
main()
{
yylex();
}

Testime skannerit sisendiga, kus on kasutatud kõiki võimalusi attribuutide järjekorra ja esinemise jaoks:

<img id ="image1" region ="pilt" />
<audio id="audio1" />
<img region = "ekraaninurk" id = "helikopter"/>
<audio region="left_channel"/>
<audio/>

Väljund tuleb korrektne:

< img, "image1" , "pilt" >
< audio, "audio1" , >
< img, "helikopter", "ekraaninurk" >
< audio, , "left_channel" >
< audio, , >

Et näha, milliseid reegleid ja millises järjekorras skanner kasutas, tuleb Flex-i sisendi alguses %options-osas lisada võti

%options debug

(või käivitada võtmega -d) - siis väljastab Flex ka kasutatud reeglid (reanumbrid on Flex-i sisenfailist):

--(end of buffer or a NUL)
--accepting rule at line 44 ("<img ")
--accepting rule at line 57 ("id =")
--accepting rule at line 58 (""image1" ")
--accepting rule at line 62 ("region =")
--accepting rule at line 63 (""pilt" ")
--accepting rule at line 49 ("/>")
--accepting default rule ("
")
--accepting rule at line 40 ("<audio ")
--accepting rule at line 57 ("id=")
--accepting rule at line 58 (""audio1" ")
--accepting rule at line 49 ("/>")
--accepting default rule ("
")
--accepting rule at line 44 ("<img ")
--accepting rule at line 62 ("region = ")
--accepting rule at line 63 (""ekraaninurk" ")
--accepting rule at line 57 ("id = ")
--accepting rule at line 58 (""helikopter"")
--accepting rule at line 49 ("/>")
--accepting default rule ("
")
--accepting rule at line 40 ("<audio ")
--accepting rule at line 62 ("region=")
--accepting rule at line 63 (""left_channel"")
--accepting rule at line 49 ("/>")
--accepting default rule ("
")
--accepting rule at line 40 ("<audio")
--accepting rule at line 49 ("/>")
--accepting default rule ("
")
--(end of buffer or a NUL)
--EOF (start condition 1)

Oletusreegel default rule on sisendi kopeerimine väljundisse - Flex-i sisendfailis polnud midagi reavahetuste kohta ja Flex kopeerib need selle reegli järgi otse väljundisse. Kui skanner on koostatud nii, et kõigi sisendis esineda võivate märkide/märgijadade jaoks on reegel, võib oletusreegli ära keelata, käivitades Flex-i võtmega -s. Selle kasutamine on sellise "täieliku" skanneri jaoks hea test - kui sisendis on midagi, mille jaoks reeglit pole, teatab skanner kohe veast; kui oletusreeglit võib kasutada, kopeerib skanner sellise koha otse väljundisse ja viga võib jääda märkamata.

Struktuurseid lekseeme võib moodustada ka otse C-keele muutujaid kasutades; sel juhul defineeritakse mõned abimuutujad, mis sisuliselt salvestavad lisainfot läbivaadatud osa kohta, näiteks allpooltoodud Flex-programmis muutujad image_start, audio_start on töesed (1), kui on alanud <img> või <audio> märgend, id_attr ja reg_attr taas "mäletavad", et enne praegu loetud stringi (Id või regiooniattribuudi väärtus) oli tekstis vastavalt "Id=" või "regioon=" jne

Järgnevas on näide C-keele muutujate abil kogu SMIL-programmi keha (body) analüüsiks.

%option noyywrap
/* scanner for a toy Smil-like language body part*/
%{
int num=0;
int id_rida=0;
int reg_rida=0;
int image_start=0;
int audio_start=0;
int region_attr=0;
int id_attr=0;
int reg_recorded=0;
int id_recorded=0;
int tabelisse=0;
int rida=1,veerg=1;
char c, nimed[50][10];
/* nametable; < 50 names are allowed in a program */
int i,j,k,n=0;
struct STag
{
int Tyyp; int iRida; int iVeerg; int ID_index; int Reg_index; };
struct STag slxResult;
void tag_out(struct STag slxTag)
{
printf("[ %d, %d, %d, %d, %d ]\n", slxTag.Tyyp, slxTag.iRida, slxTag.iVeerg, slxTag.ID_index, slxTag.Reg_index); return; }
%}
TYHIK [ \t]
TYHIZ {TYHIK}*
TYHIKUD {TYHIK}+
ID "id"{TYHIZ}"="{TYHIZ}
REG "region"{TYHIZ}"="{TYHIZ}
NUMBER [0-9]
TAHT [a-zA-Z]
TAHTNUM {TAHT}|{NUMBER}|"_"|"-"
ID_STRING \"{TAHTNUM}+\"
IMG_start "<img"
AUD_start "<audio"
TAG_end "/>"

%%

{IMG_start} {image_start=1;
printf("Image tag start, rida %d veerg %d:\n",rida,veerg);
slxResult.iRida=rida;slxResult.iVeerg=veerg;
slxResult.Tyyp = 1;
/*slxResult.Tyyp="Img"*/
veerg=veerg+yyleng;}
{AUD_start} {audio_start=1;
printf("Audio tag start, rida %d veerg %d:\n",rida,veerg);
slxResult.iRida=rida;slxResult.iVeerg=veerg;
slxResult.Tyyp=2; /*"AUD" */
veerg=veerg+yyleng;}
{REG} {region_attr=1;
printf("region (rida %d veerg %d):",rida,veerg);
veerg=veerg+yyleng;}
{ID} {id_attr=1;
printf("tag id (rida %d veerg %d):",rida,veerg);
veerg=veerg+yyleng;}
{ID_STRING} {/*printf("%s\n",yytext);*/
for (i=0; iyyleng-2; i++)
nimed[n][i]=yytext[i+1];
nimed[n][yyleng-2]=0x00;
if ((region_attr==1)&&(reg_recorded==0))
{slxResult.Reg_index=n;
reg_recorded=1; };
if ((id_attr==1)&&(id_recorded==0))
{slxResult.ID_index=n; id_recorded=1; }; n++;
veerg=veerg+yyleng;}
{TAG_end} {if (audio_start==1)
{printf("Audio tag end, rida %d veerg %d\n",rida,veerg);
veerg=veerg+yyleng;
audio_start=0;};
if (image_start==1)
{printf("Image tag end, rida %d veerg %d\n",rida,veerg); veerg=veerg+yyleng;
image_start=0;};
if (region_attr==1)
{region_attr=0;reg_recorded=0;}; if (id_attr==1)
{id_attr=0;id_recorded=0;}; tag_out(slxResult);
slxResult.ID_index = -1;
slxResult.Reg_index = -1; /* kui järgmisel puudub */
veerg=veerg+yyleng;
};

{TYHIKUD} veerg=veerg+yyleng;
[\n]* {rida=rida+yyleng;veerg=1;}
.
%%

main( argc, argv )
int argc;
char **argv;
{
++argv, --argc; /* skip over program name */
if ( argc > 0 )
yyin = fopen( argv[0], "r" );
else
yyin = stdin;
slxResult.ID_index = -1; /* kui järgmisel puudub */
slxResult.Reg_index = -1; /* kui järgmisel puudub */
for(i = 0; i < 50; i++) nimed[i][0] = 0x00;
yylex();
printf("Identifikaatoreid: %d\n", n);
for (i=0;i < n;i++)
{
printf("%d: ",i);
k = 0;
c = nimed[i][k];
while (c != 0x00)
{
printf ("%c", c);
k++;
c = nimed[i][k];
};
printf("\n");
} }


Ülesandeid:
1. Lisa esimesse programmi kontroll, mis teatab veast, kui märgendis on mõnda attribuuti kirjeldatud mitu korda.
2. Täienda esimest programmi nii, et see moodustaks lekseemid kõigist ülalesitatud SMIL- näidisprogrammist esinevatest märgenditest: <smil>, <head>, <layout>, <root-layout>, par- seq- jne; kui märgendil on attribuute, siis peab vastav lekseem olema struktuurne.
3. Lisa ülalesitatud programmidesse lekseemide audio, img kandmine nimede tabelisse (koos attribuutidega id, regioon).
4. Koosta (alustamistingimuste abil) skanner, mis moodustaks C-keele kommentaari (märgendite /* */ vahel olev märgijada, milles ei esine märgid /* ja */ - kommentaari sees ei või olla teist kommentaari) jaoks lekseemi COMMENT koos kommentaari asukoha (algusrida ja positsioon reas, samuti ja lõpurida ja positsioon reas) attribuutidega, kuid "neelaks alla" (ei salvestaks) kommentaari teksti; kõik muud tekstid loetakse identifikaatoriteks ja kantakse nimede tabelisse.
5. Eelmisega analoogiline ülesanne C-keele reakommentaaride jaoks; C-reakommentaar algab märkidega // ja lõpeb rea lõpus.
6. Eelmistega analoogiline ülesanne kommentaaride jaoks, mis on defineeritud kui figuursulgude { } vahel ühel real olev märgijada (s.t. jadas ei või esineda reavahetus \n); kommentaari sees võivad esineda ka figuursulud { }, kuid kommentaar lõpeb kas

- esimese sulgeva figuursuluga }, mida saab paari panna esimese avava figuursuluga { või
- reavahetusega,

seega näiteks

{eesel }\n - kommentaar
{ee{sel} }\n - kommentaar (kuni reavahetuseni \n)
{ee{ el}\n - kommentaar (reavahetus \n lõpetab)
{ee}sel } - kommentaar on vaid lõik {ee}.

7. SMIL-keeles on peale id, region palju muidki attribuute. Attribuudiga dur määratakse pildi või heli kestvus; faili päises saab layout-osas defineerida üleminekuid transitions ja siin defineeritud üleminekute nimesid saab kasutada attribuudi transl väärtusena pildi või heli märgendites. Kestvusattribuudi argument näitab kestvuse sekundites, näit dur = "5.2s" määrab, et vastava märgendiga kirjeldatud meediat (pilti, heli) peab näitama/mängima 5 sekundit.
Täienda ülalesitatud SMIL-keele skanneri kirjeldust nii, et see suudaks vastu võtta näiteks sellise näite:
<smil>
<head>
<layout>

<root-layout id = "The Great Wall of China"/>
<region id = "image1" />
<region id = "image2" />
<region id = "text"/>
<region id = "music"/>
<transition id="fade_1" dur="2s" type="fade" />
</layout>
</head>

<body>
<par id="Presentation">
<audio id ="audio" region="music" dur = "2s"/>
<img id = "fortress" region = "image1" transln="fade_1" dur = "5.0s"/>
<img id = "first_view" region = "image2" dur "3.5s" />
</par>
</body>
</smil>

Skanner peab kõik päises deklareeritud regioonid ja üleminekud kandma nimede tabelisse ja nende esinemisel img, audio märgendites kontrollima, et vastavate attribuutide väärtused on nimede tablelis olemas; kui pole, peab tulema veateade (kus real, millise sümboli juures oli viga); attribuudi dur argumendi formaati peab samuti kontrollima ja lekseemis peaks attribuudi väärtus olema arv (s.t. reaalarv 5.2 , mitte string "5.2s").  

8. Täienda peatüki "Flex-i kasutamise näiteid" ülesandes 13 esitatud Swi-Prologi esiletõstmisfaili stringi kirjeldusega:
StringBegChar		'
StringEndChar '
ja koosta Flex-i programm, mis peale lekseemide Identifier NumConst EscapeChar KeyWords1 KeyWords2 KeyWords3 leiab ka rea- ja blokikommentaarid ja stringid; kommentaaride tekst asendatakse sõnaga "comment", string - sõnaga "string" (kommentaaride ja stringide teksti  leidmisel peaks kasutama alustamistingimusi).
Kommentaare transleerimise järgmisel etapil pole vaja (kuid need peavad programmi teksti esitamise jaoks säilima), sellepärast kantakse kommentaarid tavaliselt nimede tabeli sarnasesse tabelisse, lisades programmi teksti vaid viite sellesse tabelisse, mille abil kommentaari hiljem saab leida; koos kommentaariga salvestatakse ka tema asukoht (esimese sümboli rea- ja veerunumber). Tee kommentaaride jaoks selline tabel ja kanna kommentaarid sellesse tabelisse.
9. Täienda nimede tabelit nii, et sinna kantakse muutuja deklareerimisel ka selle tüüp, seega näiteks sisendi
int a = 1;
int b=2;
float pii = 3.14;
töötlemisel on pärast yylex()-i täitmist võimalik saada (printf-käskude abil) väljatrükk
taisarv a = 1
taisarv b = 2
rarv pii = 3.14
Raskem versioon - skanner avastab ka mõned vead deklaratsiooni süntaksis (kuid jätkab tööd!), näiteks sisendi
int a = 1;
int b = ;
float pii 3.14;
järel (vigase sisendi võib trükkida juba analüüsi ajal) võib saada väljundi
int b viga
float pii viga
int a = 1
10. Täienda nimede tabelit nii, et sinna kantakse ka arvkonstandid; need asendatakse kõik lekseemiga ARV ja nende tegelik väärtus on nimede tabelis. Konstandi deklaratsiooni süntaks on nagu C-keeles, s.t. lubatud on näiteks järgnevad deklaratsioonid:
int const a = 1,b = 2;
const int a = 2, c = 3;
float const pii = 3.14;
Arvkonstantide tüübid võivad olla (vaid) int, float, lekseem const võib esineda nii enne kui ka pärast tüübikirjeldust, deklaratsioonis võib olla üks või rohkem konstantide identifikaatoreid.
Konstandi deklaratsiooni algus viib skanneri vastavasse olekusse, kus siis identifikaator(id) lisatakse  konstantide tabelisse.

Küsimused, probleemid: ©2004-2013 Jaak Henno