void param( )
{
exam (‘(‘);
if (lex!=’)’ )
{
exan (IDEN);
while (lex = =’,’)
{
get( );
exam (IDEN);
}
}
exam (‘)’);
return;
}
В соответствии с синтаксической диаграммой вначале проверяется, является ли прочитанная лексема левой скобкой ‘(‘. При совпадении в функции (‘)’). При совпадении в функции exam( ), как уже не раз подчеркивалось, вызывается get( ) и поставляет новую лексему. И если это не ’)’, то должна быть IDEN. И вновь-таки, если после проверки лексемы IDEN была прочитана лексема ‘,’, то в цикле идет exam (IDEN). После выхода из цикла лексема должна быть ‘)’, и никакая другая.
7 BODY → beginl (DCONST |DVARB) * STML endl

Функция bоdy( ) вызывается из dfunc( ) после param( ). Функция param( ) заканчивается вызовом exam(‘)’). Следовательно, в случае успешной проверки будет вызвана get( ) и появится новая лексема. Она должна быть BEGINL.
void body( )
{
exam (BEGINL);
while(lex = = INTL || lex = = CONSTL)
if (lex = = INTL) dvarb( );
else
dconst( );
stml( );
exam(ENDL);
return;
}
8 STML → STAT (‘;’ STAT)*

Перед вызовом stml( ) выполнялось dconst( ). В начале этой функции есть exam(‘;’). При успешной проверке вызывается get( ), и она возвращает новую лексему.
void stml( )
{
stat( );
while (lex = = ‘;’)
{
get( );
stat( );
}
return;
}
9 STAT → iden ‘=’ EXPR |readl iden |pritl EXPR |retrl EXPR |ifl EXPR thenl STML endl |whilel EXPR dol STML endl

Перед вызовом stat( ) “свежая” лексема есть. В зависимости от ее значения идет разветвление по witch (lex).
void stat( )
{
switch (lex)
{
case IDEN: get( ); exam (‘=’); expr( ); break;
case READL: get( ); exam (IDEN); break;
case PRITL: get( ); expr( ); break;
case RETRL: get( ); expr( ); break;
case IFL: get( ); expr( ); exam(THENL); stml( ); exam(ENDL); break;
case WHILEL: get( ); expr( ); exam(DOL); stml( ); exam(ENDL); break;
default: printf(“stat nst=%i \n”, nst);
}
return;
}
10 EXPR → [‘+’|’-’] TERM ((‘+’|’-’)TERM)*

//“Свежая” лексема есть
void expr( )
{
if (lex = = ‘+’ || lex = = ‘-‘)
get( ); term( );
while (lex = = ‘+’ || lex = = ‘-‘)
{
get( );
term( );
}
return;
}
6 Пояснения к выполнению курсовой работы
Постановка задачи. Составить программу на Си для лексического анализа программы на модифицированном языке SPL. Вывести в файл "getrez. dan" и на экран таблицу идентификаторов и их адресов.
Программа на модифицированном языке SPL (вычисляет xy)
exp(a, b)
begin int z;
z=1;
while b do
if b%2 then z=z*a end;
a=a*a;b=b/2
end;
return z
end
main()
begin int x, y;
read x;
read y;
print exp(x, y)
end
#include<stdio. h>
#include<stdlib. h>
#include<ctype. h>
#include<conio. h>
#include<alloc. h>
#include<string. h>
/*Коды лексем языка SPL*/
enum{BEGINL=257,ENDL, IFL, THENL, WHILEL, DOL, RETRL, READL, PRITL, INTL, CONSTL, IDEN, NUMB};
int nst=0;
int lval, lex;
static char nch='\n';
FILE*PF,*padres;
void get(void);
void number(void);
void word(void);
char*add(char*nm);
void main(int ac, char*av[])
{
clrscr();
if(!ac)
puts("Hет исходного файла");
PF=fopen(av[1],"r");
padres=fopen("getrez. dan","w");
if(!PF)
puts("Файл не открывается");
else
get();
}
void get()
{
while(nch!=EOF)
{
while(isspace(nch))
{
if(nch=='\n')
nst++;
nch=getc(PF);
}
if(isdigit(nch))
number();
else
if(isalpha(nch))
word();
else
if(nch=='('||nch==')'||nch==','||nch==';'||nch=='='||nch=='+'||nch=='-'||nch=='*'||nch=='/'||nch=='%')
{
lex=nch;
nch=getc(PF);
}
}
if(nch==EOF)
lex=EOF;
else
puts("Hедопустимый символ");
return;
}
void number()
{
for(lval=0;isdigit(nch);nch=getc(PF))
lval=lval*10+nch-'0';
lex=NUMB;
return;
}
void word()
{
static int cdl[]={BEGINL, ENDL, IFL, THENL, WHILEL, DOL, RETRL, READL,
PRITL, INTL, CONSTL, IDEN, NUMB};
static char*serv[]={"begin","end","if","then","while","do","return","read",
"print","int","const"};
int i;
char tx[40];
char*p,*add();
for(p=tx;isdigit(nch)||isalpha(nch);nch=getc(PF))
*(p++)=nch;
*p='\0';
for(i=0;i<11;i++)
if(strcmp(tx, serv[i])==0)
{
lex=cdl[i];
return;
}
lex=IDEN;
lval=(int)add(tx);
printf("Адрес для %s =%p\n",tx, lval);
fprintf(padres,"Адрес для %s =%p\n",tx, lval);
return;
}
char TNM[400];
char*ptn=TNM;
char*add(char*nm)
{
char*p,*strcpy();
for(p=TNM;p<ptn;p+=strlen(p)+1)
if(strcmp(p, nm)==0)
return p;
if((ptn+=strlen(nm)+1)>TNM+400)
{
puts("Переполнение таблицы");
exit(0);
}
return(strcpy(p, nm));
}
Образец результата работы программы
Адрес для exp =0586
Адрес для a =058B
Адрес для b =058D
Адрес для z =058F
Адрес для z =058F
Адрес для b =058D
и т. д.
6. 1 Пример выполнения курсовой работы
Вариант задания курсовой работы
Составить программу на Си для лексического анализа программы на модифицированном языке SPL, в котором все ключевые слова переведены на русский язык и вместо begin и end используются соответственно левая и правая фигурные скобки. Вывести в файл и на экран таблицу идентификаторов и их адресов.
Вариант программы на модифицированном языке SPL (вычисляет xy), где по условию задачи все ключевые слова заменены на соответствующие на русском языке, а вместо begin и end используются соответственно { и }
exp(a, b)
{
целый z;
z=1;
пока b делать
если b%2 тогда z=z*a };
a=a*a;b=b/2
};
возврат z
}
main()
{
целый x, y;
читать x;
читать y;
печатать exp(x, y) }
Замечание: жирным шрифтом выделены изменения, которые необходимо внести в предыдущую программу, согласно варианту задания.
#include<stdio. h>
#include<stdlib. h>
#include<ctype. h>
#include<conio. h>
#include<alloc. h>
#include<string. h>
/*Коды лексем языка SPL*/
enum{BEGINL=257,ENDL, IFL, THENL, WHILEL, DOL, RETRL, READL, PRITL, INTL, CONSTL, IDEN, NUMB};
int nst=0;
int lval, lex;
static char nch='\n';
FILE*PF,*padres;
void get(void);
void number(void);
void word(void);
char*add(char*nm);
int isalpharus(char c);
int isspace1(char c);
int isdigit1(char c);
void main(int ac, char*av[])
{
clrscr();
if(!ac)
puts("Hет исходного файла");
PF=fopen(av[1],"r");
padres=fopen("getrez. dan","w");
if(!PF)
puts("Файл не открывается");
else
get();
}
void get()
{
while(nch!=EOF)
{
while(isspace1(nch))
{
if(nch=='\n')
nst++;
nch=getc(PF);
}
if(isdigit1(nch))
number();
else
if(isalpharus(nch))
word();
else
if(nch=='('||nch==')'||nch==','||nch==';'||nch=='='||nch=='+'||nch=='-'||nch=='*'||nch=='/'||nch=='%'||nch=='{'||nch=='}')
{
lex=nch;
nch=getc(PF);
}
}
if(nch==EOF)
lex=EOF;
else
puts("Hедопустимый символ");
return;
}
void number()
{
for(lval=0;isdigit1(nch);nch=getc(PF))
lval=lval*10+nch-'0';
lex=NUMB;
return;
}
void word()
{
static int cdl[]={BEGINL, ENDL, IFL, THENL, WHILEL, DOL, RETRL, READL,
PRITL, INTL, CONSTL, IDEN, NUMB};
static char*serv[]={"{","}","если","тогда","пока","делать","возврат","читать","печатать","целый","const"};
int i;
char tx[40];
char*p,*add();
for(p=tx;isdigit1(nch)||isalpharus(nch);nch=getc(PF))
*(p++)=nch;
*p='\0';
for(i=0;i<11;i++)
if(strcmp(tx, serv[i])==0)
{
lex=cdl[i];
return;
}
lex=IDEN;
lval=(int)add(tx);
printf("Адрес для %s =%p\n",tx, lval);
fprintf(padres,"Адрес для %s =%p\n",tx, lval);
return;
}
char TNM[400];
char*ptn=TNM;
char*add(char*nm)
{
char*p,*strcpy();
for(p=TNM;p<ptn;p+=strlen(p)+1)
if(strcmp(p, nm)==0)
return p;
if((ptn+=strlen(nm)+1)>TNM+400)
{
puts("Переполнение таблицы");
exit(0);
}
return(strcpy(p, nm));
}
/* Добавляем к исходной программе функции пользователя для распознавания букв, специальных знаков и цифр */
int isalpharus(char c)
{
int v;
if(isalpha(c)||c=='а'||c=='б'||c=='в'||c=='г'||c=='д'||c=='е'
||c=='ж'||c=='з'||c=='д'||c=='е'||c=='ж'||c=='з'||c=='и'|| c=='й'||c=='к'||c=='л'||c=='м'||c=='н'||c=='о'||c=='п'|| c=='р'||c=='с'||c=='т'||c=='у'||c=='ф'||c=='х'||c=='ц'||c=='ч'||c=='ш'||c=='щ'||c=='ы'||c=='э'||c=='ю'||c=='я'||c== 'ь')
|
Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5 6 7 |


