В процессе лексического анализа определяются (назначаются) глобальные переменные. Lex - для распознанной лексемы, eval - значение лексем, nst номер строки программы, которая содержит лексему. Различаются следующие лексемы:
служебные слова if,while,return,print,read,begin,end,int, const, then, do, которые кодируются соответственно командами IFL, WHILEL, RETRL, PRITL, READL, BEGINI, ENDL,INTL, CONSTL, THENL,DOL,
знаки операций и разделители, закодированные литеральными константами ‘+’, ’-’, ’*’, ’/’, ’%’, ’=’, ‘(‘,’)’, ‘;’, ‘;’;
целые без знака с кодом NUMB и значением eval;
идентификатор с кодом IDEN и значением val, которые являются указателями таблицы идентификаторов TNM;
конец файла с кодом EOF.
Файл lexan.e с функциями лексического анализа имеет вид
/* коды лексем языка программирования SPL*/
enum {IFL=257,WHILEL,RETRL,PRITL,READL,BEGINL,ENDL,INTL,CONSTL,THENL,DOL,NUMB,IDEN};
int nst=0;
int lval,lex;
static char nch='\n';
extern FILE *PF;
/*get-ввод следующей лексемы в lex и lval из PF*/
get()
{if(nch==EOF)
{lex=EOF;return;}
while (isspace (nch))
{if (nch=='\n')nst++;nch=getc(PF);}
if(isdigit(nch))number();else if(isupper(nch))word();
else if(strchr("(),;=+-*/%",nch))
{lex=nch;nch=getc(PF);}
else if(nch==EOF)lex=EOF;
else error("%c:недопустимый символ",nch);
}
/*number-ввод лексемы число*/
number()
{
for(lval=0;isdigit(nch);nch=getc(PF))
lval=lval*10+nch-'0';
lex=NUMB;
}
/*word-ввод лексемы-идентификатора или ключевого слова */
word()
{
static char *serv[]={"IF","WHILE","RETURN","PRINT","READ",
"BEGIN","END","INT","CONST","THEN","DO"};
static int cdl[]={IFL,WHILEL,RETRL,PRITL,READL,BEGINL,ENDL,
INTL,CONSTL,THENL,DOL};
char tx[40],*p,*add();
int i=0;
for(p=tx;isupper(nch)||isdigit(nch); )
{
*(p++)=nch;
nch=getc(PF);}
*p='\0';
for(i=0;i<11;i++)
if(strcmp(serv[i],tx)==0)
{lex=cdl[i];return;}
lex=IDEN;lval=add(tx);
return;
}_
За каждым обращением к функции get ( ) из файла исходной программы последовательность литер, которая образует очередную лексему, распознается лексема и отыскиваются значения переменных lex, nst и если необходимо lval.Функция add ( ) осуществляет поиск и в случае необходимости вводит идентификатор в таблицу TNM. Массив TNM содержит цепочки литер, которые задают все разные идентификаторы, которые встречаются в исходной программе. Так массив для программ VAR.2.5 (рисунок 95) содержит 4 цепочки: «main», «a», «b», «z» и указатель ptn первого свободного элемента TNM [11] массива.
TNM:
m |
a |
i |
N |
\0 |
a |
\0 |
b |
\0 |
8 |
\0 |
× |
× |
×× |
|
|
|
|
|
|
|
|
|
|
ptn |
|
|
Рисунок 95
Описание функции add и таблицы TNM, размещенное в файле table.c имеет вид
/*add - поиск и добавление в TNM идентификатора nm* /
char TNM[400];
char *ptn=TNM;
char *add(nm)
char *nm;
{
char *p,*strcpy();
p=NULL;
for (p=TNM;p<=ptn; p+=strlen(p)+1 )
if(strcmp(nm,p)==0)return (p);
if((ptn+=strlen(nm))+1>TNM+400)error («Переполнен TNM");
return(strcpy(p,nm));
}
Тут используются функции из библиотеки языка Си для выполнения операций над строками, которые кончаются символом ‘\0’.