Программирование лексического анализатора



Лексический анализ включает в себя сканирование компилируемой программы и распознавание лексем, составляющих предложения исходного текста. Сканеры обычно строятся таким образом, чтобы они могли распознавать ключевые слова, операторы и идентификаторы так же, как целые числа, числа с плавающей точкой, строки символов и другие аналогичные конструкции, встречающиеся в исходной программе. Точный перечень лексем, которые необходимо распознавать, зависит, разумеется, от языка программирования, на который рассчитан компилятор, и от грамматики, используемой для описания этого языка. Такие объекты, как идентификаторы и целые числа обычно распознаются сканером как отдельные лексемы.

Данной программе будет дано 2 текстовых документа: в одном будет находиться исходный текст, в во втором – ключевые слова. Программа будет выбирать из исходного текста перечисленные во втором файле ключевые слова и записывать их в массив TAB_K. Аналогично в массив TAB_I будут записываться идентификаторы.

 

Текст программы:

var s,c:string;

k,kl,id,tab_i,tab_k:array [1..100] of string;

f,kluch:text;

st,i,x,n,o,j,d,d2,l,q,r,r2:integer;

begin d:=1;

d2:=1;

assign(kluch,'Kluch.txt');

reset(kluch);

i:=0;

r:=0;

r2:=0;

repeat i:=i+1;

  readln (kluch,c);

  kl[i]:=c;

until eof(kluch);

o:=i;

close(kluch);

assign(f,'Text.txt');

reset(f);

repeat

readln(f,c);

if (((c[1]>='A') and (c[1]<='Z')) or ((c[1]>='a') and (c[1]<='z'))) then

   begin

      k[1]:=c[1];

      i:=1; x:=2;

      st:=1;

    end;

repeat

case st of

1: begin if (((c[x]>='A') and (c[x]<='Z')) or ((c[x]>='a') and (c[x]<='z')) or ((c[x]>='0') and (c[x]<='9'))) then

    begin

      k[i]:=k[i]+c[x];

      inc(x); 

    end

    else begin st:=2; x:=x+1; end;

end;

2: begin if (((c[x]>='A') and (c[x]<='Z')) or ((c[x]>='a') and (c[x]<='z'))) then

    begin

      i:=i+1;

      k[i]:=c[x];

      x:=x+1;

         st:=1;

    end

     else x:=x+1;

end; end;

until length(c)=x;

n:=i;

for i:=1 to n do

begin l:=1;

for j:=1 to o do

if k[i]=kl[j] then l:=0;

if l=1 then begin for q:=1 to d do

                   if k[i]=tab_i[q] then l:=0;

                   if l=1 then begin r:=r+1; tab_i[r]:=k[i]; d:=d+1;end;

                   end;

end;

for i:=1 to n do

begin l:=0;

for j:=1 to o do

if k[i]=kl[j] then l:=1;

if l=1 then begin for q:=1 to d2 do

                   if k[i]=tab_k[q] then l:=0;

                   if l=1 then begin r2:=r2+1; tab_k[r2]:=k[i]; d2:=d2+1;end;

                   end;

end;

until eof(f);

close(f);

for i:=1 to r do

writeln (tab_i[i]);

writeln;

for i:=1 to r2 do

writeln (tab_k[i]);

end.

В файле Text.txt находится следующий текст:

var x,y:integer;

f:real;

begin x:=5+6;

y:=x^2;

readln (c);

f:=(y*x)/c

writeln (f);

end.

В файле Kluch.txt записан текст:


var

integer

begin

writeln

end

real

readln


В результате компиляции программы получится следующий результат:


x

y

f   идентификаторы

c

 

var

integer

real

begin     ключи

readln

writeln

end



Лабораторная работа №6

Лексический анализатор. Процедура, которая не смещает указатель входного потока

 

 

 


Текст программы:

var s,c:string;

k,kl,id,tab_i,tab_k:array [1..100] of string;

f,kluch:text;

st,i,x,n,o,j,d,d2,l,q,r,r2:integer;

procedure scan (c:string; var k:array [1..100] of string; i:integer);

begin if (((c[1]>='A') and (c[1]<='Z')) or ((c[1]>='a') and (c[1]<='z'))) then

begin

k[1]:=c[1];

         i:=1;

         x:=2;

         st:=1;

       end;

repeat

case st of

1: begin if (((c[x]>='A') and (c[x]<='Z')) or ((c[x]>='a') and (c[x]<='z')) or ((c[x]>='0') and (c[x]<='9'))) then

       begin

         k[i]:=k[i]+c[x];

         inc(x); 

       end

       else begin st:=2; x:=x+1; end;

end;

2: begin if (((c[x]>='A') and (c[x]<='Z')) or ((c[x]>='a') and (c[x]<='z'))) then

begin

i:=i+1;

         k[i]:=c[x];

         x:=x;

         st:=1;

       end

       else x:=x+1;

end; end;

until length(c)=x;

 

end;

begin d:=1;

d2:=1;

assign(kluch,'Kluch.txt');

reset(kluch);

i:=0;

r:=0;

r2:=0;

repeat i:=i+1;

  readln (kluch,c);

  kl[i]:=c;

until eof(kluch);

o:=i;

close(kluch);

assign(f,'Text.txt');

reset(f);

repeat

readln(f,c);

scan (c,k,i);

n:=i;

for i:=1 to n do

begin l:=1;

for j:=1 to o do

if k[i]=kl[j] then l:=0;

if l=1 then begin for q:=1 to d do

                   if k[i]=tab_i[q] then l:=0;

                   if l=1 then begin r:=r+1; tab_i[r]:=k[i]; d:=d+1;end;

                   end;

end;

for i:=1 to n do

begin l:=0;

for j:=1 to o do

if k[i]=kl[j] then l:=1;

if l=1 then begin for q:=1 to d2 do

                   if k[i]=tab_k[q] then l:=0;

                   if l=1 then begin r2:=r2+1; tab_k[r2]:=k[i]; d2:=d2+1;end;

                   end;

end;

until eof(f);

close(f);

for i:=1 to r do

writeln (tab_i[i]);

writeln;

for i:=1 to r2 do

writeln (tab_k[i]);

end.

 

В результате компиляции программы получится следующий результат:

xx

yy

iinteger

f           идентификаторы

rreal

y

cc

ff      

        

var

begin

readln       ключи

writeln

end


Лабораторная работа №7

Рекурсивный спуск

1) Цель работы: создать программу, которая осуществляет выполнение алгоритма рекурсивного спуска для следующей грамматики:


Алгоритм построения процедур.

Для построения процедур просматривается правая часть правила для каждого нетерминала.

1. Если встречается нетерминальный символ, то вызывается процедура для этого символа. Если она завершается без ошибки, то в исходном тексте фраза для этого терма закрыта, и все семантические действия тоже выполнены.

2. Если встречается терминальный символ, он сравнивается с очередным символом входной строки. Если они совпадают, этот символ просто закрывается. Указатель смещается на один шаг вправо. Если не совпадают, то это синтаксическая ошибка и трансляция прекращается.

3. Если встречается метасимвол:

3.1. Если встречается итерация {, то организуется цикл while, в который помещается все, что заключено в {}. Условием входа в цикл является то, что очередной символ не принадлежит множеству Follow для этого нетерминала.

3.2. Если встречается альтернатива ( | ), то организуется оператор if или несколько вложенных операторов if. Число ветвей должно быть на единицу больше, чем альтернатив. Условие для входа в ветвь – принадлежность текущего символа множеству First для этой альтернативы, а последняя ветвь Else соответствует синтаксической ошибке.

Содержимое файла: I+(I*I-I)#

2) Исходный текст программы:

program rs1;

var x:string; i:integer;

flag:boolean; file2:text;

 

procedure Err(a:integer);

begin

if a=1 then writeln('Ожидается конец файла');

if a=2 then writeln('Неверный символ');

if a=3 then writeln('Ожидается закрывающая скобка');

x[i]:='#';

end;

 

procedure T; forward;

procedure E;

begin

T;

while not((x[i]='#') or (x[i]=')')) do

if x[i]='+' then begin

i:=i+1;

T;

end

else if x[i]='-' then begin

i:=i+1;

T;

end

else begin Err(1); flag:=false; end;

end;

 

procedure F; forward;

procedure T;

begin

F;

while not((x[i]='#') or (x[i]=')') or (x[i]='+') or (x[i]='-')) do

begin

if x[i]='*' then begin

i:=i+1;

F;

end

else if x[i]='/' then begin

i:=i+1;

F;

end

else begin Err(1); flag:=false; end;

end;

end;

 

procedure F;

begin

if x[i]='I' then i:=i+1

else if x[i]='(' then begin

i:=i+1;

E;

if x[i]=')' then i:=i+1

else begin Err(3); flag:=false; end;

end

else begin Err(2); flag:=false; end;

end;

 

begin

flag:=true;

assign (file2,'7.txt');

reset (file2);

read (file2,x);

i:=1;

E;

if flag=true then

writeln ('Строка правильная');

close (file2);

end.

 

3) Результаты:

Исходный файл: I+(I*I-I)#

Результат: Строка правильная

 

Исходный файл: (I+(I*I-I)#

Результат: Ожидается закрывающая скобка

 

Исходный файл I+(I*I-R)#

Результат: Неверный символ

 

Исходный файл: I+(I*I-I)

Результат: Ожидается конец файла

 

 


Лабораторная работа №8


Дата добавления: 2018-04-05; просмотров: 367; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!