Transcript مثال

#inlcude<iostream.h>
#inlcude<stdlib.h>
#inlcude<stdio.h>
int main(){
int state;
char ch;
state=1;
switch(state){
case 1: ch= getc(stdin);
if (ch==’a’)
state=2;
else {
cout<<"Failed";
exit(0);
}
break;
case 2: ch=getc(stdin);
if(ch=='\n')
cout<<"Accepted";
else
cout<<"Failed";
exit(0);
}
return(0);
}
1
a
2
#inlcude<iostream.h>
#inlcude<stdlib.h>
#inlcude<stdio.h>
int main(){
int state;
char ch;
state=1;
while(1){
switch(state){
case 1: ch = getc(stdin);
if (ch==’a’) state=1;
else if(ch == 'b') state=2;
else {
cout<<"Failed";
exit(0);
}
break;
case 2: ch=getc(stdin);
if(ch=='\n') cout<<"Accepted";
else
cout<<"Failed";
exit(0);
}
}
return(0);
}
a
b
1
2
#inlcude<iostream.h>
#inlcude<stdlib.h>
#inlcude<stdio.h>
int main(){
int state;
char ch;
state=1;
while(1){
[a-zA-Z0-9]
switch(state){
case 1: ch = getc(stdin);
if ((ch>=’a’ && 'z'>=ch )|| (ch>=’A’ && 'Z'>=ch) )
state=2;
else {
cout<<"Failed";
exit(0);
}
break;
[a-zA-Z]
[a-zA-Z
case 2:ch = getc(stdin);
1
if(ch=='\n'){
2
cout<<"Accepted";
exit(0);
}
else if ((ch>=’a’ && 'z'>=ch )|| (ch>=’A’ && 'Z'>=ch) || (ch>=’0’ && '9'>=ch))
state=2;
else {
cout<<"Failed";
exit(0);
}
exit(0);
break;
}
return(0);
}
[a-zA-Z0-9]
[0-9]
[a-zA-Z]
1
[1-9]
2
6
7
[0-9]
[0-9]
[ \n]
.
[1-9]
3
4
54
8
•
•
•
•
•
•
•
•
•
•
•
•
•
int fail(int start)
{
int nextstart;
switch(start){
case 1:nextstart=3; //
break;
case 3:nextstart=6; //
break;
case 6:nextstart=8; //
break;
}
return nextstart;
}
‫اعداد اعشاري‬
‫اعداد صحيح‬
‫فضاي خالي‬
int main{
int state,start,loc;
char ch;
FILE *fp;
fp=fopen("source.txt","r");
state=1;
start=1;
while(1)
switch(state){
case 1: loc=ftell(fp);
ch=getc(fp);
if((ch>='a' && ch<='z') || (ch>='A' && ch<='Z'))
state=2;
else{
start=fail(start);
state=start;
fseek(fp,loc,SEEK_SET);
}
break;
case 2:ch=getc(fp);
if((ch>='a' && ch<='z') || (ch>='A' && ch<='Z') || (ch>='0' && ch<='9'))
state=2;
else if (ch==' '|| ch=='\n'|| ch==EOF){
cout<<"ID ";
state=8;
}
else{
start=fail(start);
state=start;
fseek(fp,loc,SEEK_SET);
}
break;
case 3: loc=ftell(fp);
ch=getc(fp);
if(ch>='1' && ch<='9')
state=4;
else {
start=fail(start);
state=start;
fseek(fp,loc,SEEK_SET);
}
break;
‫اولویت ها‬
‫ممكن است بخشي از یك دنباله از كاراكترها با یك عبارت باقاعده و بخش دیگری با‬
‫عبارت باقاعده دیگري منطبق شود‪ .‬به عنوان مثال دنباله ‪ 123.65‬و دو عبارت با قاعده ذیل‬
‫را در نظر مي گيریم‪.‬‬
‫*]‪[1-9][0-9‬‬
‫*]‪[1-9][0-9]*. [0-9][1-9‬‬
‫‪.‬‬
‫پذيرش طوالني ترين دنباله است‬
‫ممكن یك دنباله از كاراكترها (نه بخشي از یكك دنبالكه) بكا دو یكا دنكد عبكارت باقاعكده‬
‫منطبق شود به عنوان مثال رشته ‪ if‬مي تواند توسط دو عبارت باقاعده ذیل توليد شود‪.‬‬
‫‪if‬‬
‫*]‪[a-zA-Z][a-zA-Z0-9‬‬
‫عبارت با قاعده اي كه اولويت بيشتري دارد‪ ،‬ابتدا مقايسه‬
‫مي شود‪.‬‬
int fail(int start){
int nextstart;
switch(start){
case 1:nextstart=6; //
break;
case 3:nextstart=8;
break;
case 6:nextstart=3; //
break;
}
return (nextstart);
}
‫اعداد صحيح‬
‫اعداد اعشاري‬
‫توليد خودكار تحليلگر لغوي‬
‫•‬
‫•‬
‫•‬
‫•‬
‫استفاده از ابزارها داراي مزايا و معايبي است كه عبارتند‬
‫از‪:‬‬
‫افزايش سرعت ايجاد تغييرات‬
‫كاهش زمان ساخت تحليلگر لغوي‬
‫افزايش محدوديتها‬
‫پياده سازي تحليلگر لغوي به وسيله توليدكننده‬
‫تحليلگر لغوي‬
‫‪ FLex‬برنامه به زبان‬
‫‪ Flex‬كامپايل بوسيله‬
‫يا پاسكال ‪ C‬برنامه به زبان‬
‫‪ C‬كامپايل بوسيله كامپايلر‬
‫تحليلگر لغوي‬
•
•
•
•
c:\> flex pascal.l scanner.c
‫بعد از کامپايل و توليد فايل اجرايی‬
c:\> scanner.exe< p1
c:\> scanner.exe <p1> result
• c:\> scanner.exe
‫رشته هاي مورد نظر‬
‫نحوه بيان عبارات با قاعده‬
‫*‪r‬‬
‫‪r+‬‬
‫?‪r‬‬
‫}‪r{m,n‬‬
‫}‪X{2,5‬‬
‫‪r1r2‬‬
‫‪r1/r2‬‬
‫(‪If/‬‬
‫‪r1|r2‬‬
‫]مجموعه كاراكترها[‬
‫]‪[afk‬‬
‫كاراكترهاي مورد نظر^[‬
‫]‪[^afk‬‬
‫‪.‬‬
‫بجز سر خط‬
‫] كاراكتر مقصد‪ -‬كاراكترمبدا[‬
‫]‪[b-f‬‬
‫ساختار برنامه به زبان ‪flex‬‬
‫تعاريف‬
‫‪%%‬‬
‫ترجمه ها‬
‫‪%%‬‬
‫توابع‬
‫•‬
‫•‬
‫•‬
‫•‬
‫•‬
‫مثال‬
digit
lower
upper
letter
var
ws
%%
ws
“if”
“else”
var
%%
[0-9]
[a-z]
[A-Z]
lower|upper
{letter}|({letter}|{digit})*
[ \n\t]+
{}
{printf(“I found ‘IF’ keyword”);}
{printf(“I found ‘ELSE’ keyword”);}
{printf(“I found variable “);}
.‫• اگر متن ذيل به عنوان ورودي به اين تحليلگر داده شود‬
• if temp else if id 34
.‫• خروجي به صورت ذيل خواهد بود‬
• I found ‘if’ keyword
• I found variable
• I found ‘ELSE’ keyword
• I found ‘if’ keyword
• I found variable
%option noyywrap
%{
int nchar,nline;
%}
%%
[\n] {nline++;}
.
{nchar++;}
}
%%
int main(void){
yylex();
printf("%d %d",nchar,nline+1);
return (0);
}
‫کلمات کليدی‬
‫روش اول‬
[a-zA-Z]([a-zA-Z0-9])*
"program"
"var"
"begin"
"end"
printf("ID ");
printf("PROGRAM ");
printf("VAR ");
printf("BEGIN ");
printf("END ");
void toupper(char k[])
{ int i;
for(i=0;i<=strlen(k);++i)
if(k[i]<='z' && k[i]>='a')
k[i]-=32;
}
int is_keyword(char id[]) {
char keyword[40][20]={"AND",
"ARRAY","BEGIN","CASE","CONST","DIV","DO","DOWNTO","ELSE","END","EXTERN
AL","EXTERN","FILE",
"FOR","FORWARD","FUNCTION","GOTO","IF","IN","LABEL","MOD","NIL","NOT","O
F","OR","OTHERWISE", "PROCEDURE",
"PROGRAM","RECORD","REPEAT","THEN","TO","TYPE","UNTIL","VAR","WHILE","W
ITH"};
int i;
for(i=0;i<40;i++)
if(strcmp(id,keyword[i])==0)
return i;
return -1;
}
%}
‫کلمات کليدی‬
‫روش دوم‬
[a-zA-Z]([a-zA-Z0-9])*
{toupper(yytext);
if (is_keyword(yytext)!=-1)
printf("keword=%s",yytext);
else
printf("ID ");
}
‫حساس به حالت‬
•
•
•
•
•
.
.
.
A [aA]
B [bB]
C [cC]
D [dD]
E [eE]
•
•
•
•
•
•
{A}{N}{D}
{A}{R}{R}{A}{Y}
{C}{A}{S}{E}
{C}{O}{N}{S}{T}
{D}{I}{V}
{D}{O}
return(AND);
return(ARRAY);
return(CASE);
return(CONST);
return(DIV);
return(DO);
‫حساس به حالت روش دوم‬
[a-zA-Z]([a-zA-Z0-9])* {toupper(yytext);
if (is_keyword(yytext)!=-1)
return (KW);
else
return(IDENTIFIER );
}
‫فاكتور گيري چپ‬
‫• براي يك غير پايانه ممكن است انتخابهاي مختلفي وجود‬
‫داشته باشد به طوريكه شروع يكسان داشته باشند‪ .‬به عنوان‬
‫مثال به گرامرهاي ذيل دقت كنيد‪.‬‬
‫‪• A a B | aD‬‬
‫و يا •‬
‫‪• A cd B | cdg D‬‬
‫حذف بازگشتی دپ‬
‫‪• A  1 | 2 | 3 ... | n‬‬
‫• ‪ :‬شروع مشترك‬
‫• ‪:i‬قسمت غير مشترك‬
‫• گرامر فوق را میتوان به صورت ذيل نشان داد كه همان‬
‫زبان را توليد میكند‪:‬‬
‫•‬
‫‪A  R‬‬
‫‪• R  1 | 2 | 3 | ..‬‬
‫مثال‬
‫‪• A cd B | cdg D‬‬
‫‪• BbB | c‬‬
‫‪• DdD | e‬‬
‫• با توجه به ‪ AcdB|cdgD‬قسمت مشترك ‪ cd‬است در نتيجه‪:‬‬
‫‪• = cd‬‬
‫‪• 1=gD‬‬
‫‪• 2=B‬‬
‫• گرامر را میتوان به صورت ذيل نشان داد‪.‬‬
‫‪• A cd R‬‬
‫‪• R B | g D‬‬
‫‪• BbB | c‬‬
‫‪• DdD | e‬‬
‫تحليلگر لغوي برنامه مبدا را به دنبالهاي از نشانهها تبديل •‬
‫كرده و به تحليلگر نحوي ارسال میكند‪ .‬اگر اين دنباله‬
‫توسط گرامر زبان مبدا قابل توليد باشد‪ ،‬برنامه مبدا از نظر‬
‫نحوي صحيح است در غير اين صورت داراي خطاي‬
‫نحوي است‪.‬‬
‫تجزیه‬
‫فرايند تجزيه نشان میدهد آيا دنبالهاي از نشانهها توسط •‬
‫گرامر قابل توليد است يا خير‪ .‬روالي كه فرايند تجزيه را‬
‫انجام میدهد‪ ،‬تجزيه كننده ناميده می شود‪.‬‬
‫انواع تجزيه كنندهها‬
‫• ‪ -‬تجزيه كنندههاي باال به پايين‬
‫• ‪ -‬تجزيه كنندههاي پايين به باال‬
‫ترتيب ساخته شدن درخت تجزیه‬
‫باال به پايين‪Preorder :‬‬
‫پايين به باال‪Postorder :‬‬
‫ترتيب ساختن درخت تجزیه در روش باال به پایين‬
‫ترتيب ساختن درخت تجزیه در روش پایين به باال‬
‫مثال‬
‫‪• E E + T | E - T | T‬‬
‫‪• T T * F | T / F | F‬‬
‫‪• F id‬‬
‫نحوه ساختن درخت تجزيه برای رشته ‪• :‬‬
‫‪• Id+id+id‬‬
‫مثال‬
‫)‪first(‬‬
‫اگر ‪ ‬دنبالهاي از پايانهها و غير پايانهها باشد‪ ،‬مجموعه ‪first‬‬
‫مربوط به ‪‬پايانههايي را مشخص ميكند كه رشتههاي مشتق‬
‫شده از ‪ ‬با آنها شروع ميشوند‪.‬‬
‫اگر ‪ ‬بتواند ‪ ‬را توليد كند‪  ،‬نيز به )‪ first(‬اضافه ميشود‪.‬‬
‫مثال‬
A BCd
B bB | e | 
C aC | 
.‫ مشتق شدهاند دقت كنيد‬BCd ‫به رشتههايي كه از‬
BCdd
BCdbBCd
bBd
bd
BCdeCd
ed
BCdCd
aCd
ad
first(BCd)={d,b,e,a}
‫• با توجه به گرامر ذيل )‪ first(aA‬و )‪ first(aB‬را محاسبه‬
‫كنيد‪.‬‬
‫‪• A→ a A|a B‬‬
‫‪• B→ b B| c‬‬
‫• با توجه به گرامر‪ ،‬رشتههاي مشتق شده از ‪ aA‬فقط با ‪ a‬و‬
‫رشتههاي مشتق شده از ‪ aB‬فقط با ‪ a‬شروع ميشوند‪،‬‬
‫بنابراين‪:‬‬
‫} ‪• first(aA) = {a‬‬
‫} ‪• first(aB) = {a‬‬
‫قوانين محاسبه ‪first‬‬
‫‪-1‬اگر ‪ ‬پايانه باشد آنگاه )‪ first(‬برابر مجموعه }‪ {‬است‪.‬‬
‫• مثال در گرامر فوق داريم‪:‬‬
‫}‪• first(a)={a‬‬
‫}‪• first(b)={b‬‬
‫•‬
‫‪-2‬اگر ‪ ‬بتواند ‪ ‬را توليد كند‪ ،‬آنگاه ‪ ‬به مجموعه‬
‫)‪ first(‬اضافه میگردد‪.‬‬
‫‪ -3‬اگر ‪ X‬غير پايانه و ‪ XY1Y2Y3...Yn‬باشد و مجموعههاي‬
‫)‪ first(Y1),first(Y2),...first(Yn‬شامل ‪ ‬باشند يعني همه‬
‫‪ Yi‬بتوانند تهي را توليد كنند‪ .‬در نتيجه ‪ X‬نيز میتواند ‪ ‬را‬
‫توليد كند كه در اين صورت ‪ ‬به مجموعه )‪ first(X‬اضافه‬
‫میگردد‪.‬‬
‫مثال‪first(X):‬‬
‫‪• S  AB‬‬
‫‪• A aA | bB | a | ‬‬
‫‪• B  bB | b | ‬‬
‫• ‪ -4‬اگر ‪ X‬غير پايانه و ‪ XY1Y2Y3...Yn‬باشد‪ ،‬مجموعه‬
‫)‪) first(Y1‬به جز ‪(‬به مجموعه )‪ first(X‬اضافه میگردد‪.‬‬
‫زيرا )‪ first(Y1‬مجموعه پايانههايي هستند كه در شروع‬
‫رشتههايي كه توسط‪ Y1‬توليد میشوند قرار دارند از‬
‫آنجاييكه ‪ X‬با ‪ Y1‬شروع میشود‪ ،‬پس ‪ X‬با پايانههاي‬
‫)‪ first(Y1‬شروع ميشوند‪ ،‬در نتيجه )‪ first(Y1‬به )‪first(X‬‬
‫اضافه میگردد‪.‬‬
‫اگر ‪ X‬غير پايانه و ‪ XY1Y2Y3...Yn‬باشد و ‪ ‬در مجموعه‬
‫)‪ first(Y1‬باشد )‪ Y1‬میتواند ‪ ‬را توليد كند( در اين‬
‫صورت عالوه بر )‪) first(Y1‬به جز‪ (‬مجموعه )‪first(Y2‬‬
‫)به جز‪ (‬نيز به )‪ first(X‬اضافه میگردد‪.‬‬
‫• به گرامر ذيل دقت كنيد‬
‫‪• A  Bab‬‬
‫‪• Bc|d|‬‬
‫‪follow(A‬‬
‫•‬
‫• مجموعه )‪follow(A‬پايانههايي را مشخص میكند كه در‬
‫اشتقاقهاي مختلف بالفاصله در سمت راست ‪ A‬قرار‬
‫میگيرند اين مجموعه را با )‪ follow(A‬نشان می دهيم‪.‬‬
X aXAad | a
A  Ac | Af | 
‫محاسبه‬
XaXAad
XaXAad aXAcad
XaXAad aXAcad aXAfcad
:‫با توجه به مراحل باال میتوان نتيجه گرفت كه‬
• follow(A)={a,c,f}
‫قوانين‬
‫ اگر ‪ S‬نماد شروع باشد ‪ $) $‬نشان دهنده آخر رشته ورودي‬‫است( به )‪ follow(S‬اضافه میشود‪.‬‬
‫• ‪ -2‬براي هر قاعده توليدي به صورت ‪ ، MN‬تمام‬
‫پايانههاي موجود در )‪ ) first(‬به جز ‪ (‬به )‪follow(N‬‬
‫اضافه میشود‪.‬‬
‫‪A AXZ | ‬‬
‫‪Z  aZ | bZ | c |‬‬
‫‪X a‬‬
‫}‪follow(X)= {a,b,c‬‬
‫• براي هر قاعده اي به صورت ‪ MN‬و يا ‪MN‬‬
‫در صورتيكه ‪ ‬عضو )‪ first(‬باشد يعني ‪ ‬بتواند رشته‬
‫تهي يا ‪ ‬را توليد كند‪ ،‬تمام پايانههاي مجموعه‬
‫)‪ follow(M‬به )‪ follow(N‬اضافه ميشود‪.‬‬
‫مثال‬
.‫ را محاسبه كنيد‬follow(B) ‫• با توجه به گرامر ذيل‬
• AAXb
• Xd|dB|eBE
• Ea|
• Bb
:‫جواب‬
follow(B)={a,b}
‫تجزيه كننده باال به پايين‬
‫انواع تجزيه کننده های باال به پايين‪:‬‬
‫ تجزيه کننده های بازگشتی‬‫‪ -‬تجزيه کننده غير بازگشتی‬
‫تجزیه کننده های بازگشتی‬
‫ در اين تجزيه کننده يک متغير پيشنگر )‪(lookahead‬‬‫همواره به نماد جاری رشته ورودی اشاره می کند‬
‫ تجزيه کننده سعی می کند نمادی که پيشنگر به آن اشاره می‬‫کند را توليد کند‪.‬‬
‫ هرگاه نماد مورد نظر پيشنگر توليد شد‪ ،‬پيشنگر به نماد‬‫بعدی اشاره می کند‪.‬‬
‫‪ -‬برای هر غير پايانه يک تابع ايجاد می شود‬
‫مثال‬
A→ aR
R→ A|B
B→ bB|c
‫تابع کمکی ‪ :match‬هرگاه نماد مورد انتظار گرامر‬
‫)‪ (symbol‬با نماد جاری رشته ورودی )‪(lookahead‬‬
‫يکسان شد‪ .‬يعنی يکی از نمادهای رشته جاری توليد شده‬
‫است و پيشنگر بايد به جلو حرکت کند‪ .‬وگرنه خطا است‪.‬‬
‫{)‪void match(char symbol‬‬
‫)‪if ( lookahead== symbol‬‬
‫;)(‪lookahead=getche‬‬
‫{‪else‬‬
‫;"‪cout<<" error‬‬
‫;)‪exit(0‬‬
‫}‬
‫}‬
A→ aR
void A(){
match('a');
R(); }
R→ A|B
B→ bB|c
first(A)={a}
first(B)={b,c}
void R(){
if(lookahead=='a') A();
else if (lookahead=='b' || lookahead=='c')
B();
else{ cout<"error";exit(0);}
}
B→ bB|c
void B(){
if(lookahead=='b'){
match('b');
B();
}
else if(lookahead=='c'){
match('c');
cout<<"Accepted";
exit(0);
}
}
int main(){
lookahead= getche();
A();
return 0;
}
‫مشکالت روش پيشگوی غير بازگشتی‬
‫• برخورد ‪first/first‬‬
‫فرض کنيد قانون زير بخشی از گرامر است‪.‬‬
‫‪B→ bB|bc‬‬
‫‪B→ α1|α2‬‬
‫‪First(α1) ∩first(α2) ≠φ‬‬
‫راه حل‪ :‬فاکتور گيری چپ‪:‬‬
‫‪B→ bB|bc‬‬
‫‪B→ bR‬‬
‫‪R→ B|c‬‬
first/follow ‫برخورد‬
A→ Bed
B → e|a| 
char lookahead;
void A(){
B();
match('e');
match('d');
}
void B(){
if (lookahead =='e'){
match('e');
else if (lookahead =='a')
match('a');
else ;
return ;
}
int main(){
lookahead=getche();
A();
return 0;
‫گرامر‬
A→ Bed
B → e|a| 
eed ‫ و‬ed ‫عملکرد تجزيه کننده برای دو رشته‬
.‫چيست‬
‫• برخورد ‪first/follow‬‬
‫•‬
‫•‬
‫•‬
‫•‬
‫در قاعده توليدي به صورت ‪ A|‬شرايط ذيل برقرار‬
‫باشد‪.‬‬
‫‪  -1‬بتواند ‪ ‬را توليد كند‪.‬‬
‫‪ -2‬حداقل يك نماد وجود دارد كه هم میتواند در شروع ‪‬‬
‫و هم بعد از ‪ A‬باشد‪ .‬يا به عبارت ديگر رابطه ذيل برقرار‬
‫باشد‪.‬‬
‫‪first()  follow(A)‬‬
A→ Bed
B→ e|a|
،‫ باشد‬= ‫ و‬=e ‫اگر‬
first(e)={e}
follow(B)={e}
:‫در نتيجه‬
first(e)  follow(B)={e}
‫تجزيه كننده پيشگوي غير بازگشتي‬
‫‪AB|C‬‬
‫‪B  bB | f‬‬
‫‪C  cC | e‬‬
expr  term rest
rest  + expr | - expr | 
term  id
‫ تمام غير پايانهها‬follow ‫ تمام سمت راستهاي قواعد توليد و‬first ‫ابتدا‬
.‫را محاسبه میكنيم‬
first(term rest)=first(term)={id}
first(+expr)=first(+)={+}
first(-expr)=first(-)={-}
first()={}
first(id)={id}
follow(expr)={$}
follow(term)={+,-,$}
follow(rest)={$}
‫ساختار تجزیه کننده پيشگوی غير بازگشتی‬
‫مراحل تجزیه ‪id+id-id‬‬
‫گرامرهای )‪LL(1‬‬
‫اگر در ساخت درخت تجزيه فقط با رويت يك نشانه بعدي از‬
‫رشته ورودي در پيمايش چپ به راست‪ ،‬بتوان غير پايانه‬
‫بعدي را براي گسترش تشخيص داد در اين صورت گرامر‬
‫مستقل از متن را )‪ LL(1‬ميناميم‪.‬‬
‫مثال‪:‬‬
‫‪• A aB | aad‬‬
‫‪• B bB | c‬‬
‫اين گرامر )‪ LL(1‬نيست‪.‬‬
‫•‬
‫•‬
‫•‬
‫•‬
‫•‬
‫گرامرهاي داراي بازگشتي چپ )‪ LL(1‬نيستند‪.‬‬‫ گرامرهاي مبهم )‪ LL(1‬نيستند‪.‬‬‫ اگر جدول تجزيه غيربازگشتي پيشگو داراي خانهاي با بيش‬‫از يك وارده باشد‪ ،‬گرامر )‪ LL(1‬نيست و به عكس اگر جدول‬
‫تجزيه پيشگوی غيربازگشتي داراي خانهاي با بيش از يك وارده‬
‫نباشد‪ ،‬گرامر )‪ LL(1‬است‪ .‬در نتيجه توليد جدول تجزيه يكي از‬
‫مهمترين روشهاي تست )‪ LL(1‬بودن گرامر است‪.‬‬
‫ گرامرهای دارای برخورد ‪ first/first‬از نوع )‪ LL(1‬نيستند‪.‬‬‫گرامرهای دارای برخورد ‪ first/follow‬از نوع )‪ LL(1‬نيستند‪.‬‬
‫• اگر در گرامر‪ ،‬قاعده توليدي به صورت ‪ A|‬وجود داشته‬
‫باشد به طوريكه ‪ ‬و‪ ‬هر دو رشته تهي را توليد كنند‪ ،‬گرامر‬
‫)‪ LL(1‬نيست‪.‬‬
‫• گرامر ذيل را در نظر بگيريد‪.‬‬
‫‪• ACB | ‬‬
‫‪• BbB | ‬‬
‫‪• C cC |‬‬
• A aCbAB | d
• B eA|
• C c
‫ استفاده از قوانين توليد خطا‪ :‬اگر خطاهايي كه در برنامه رخ میدهد را‬‫بتوان پيش بيني كرد میتوان قواعد توليدي به گرامر اضافه كرد تا اين خطا‬
‫را نيز شامل گردد‪ .‬در اين صورت تجزيه كننده با كاهش چنين گرامري‬
‫خطا را كشف میكند و میتواند به تجزيه نيز ادامه دهد‪.‬‬
‫گرامر ذيل نشان میدهد كه بعد از هر دستور سمي كالن قرار دارد‪.‬‬
‫; ‪stmtstmt ; stmt_list | stmt‬‬
‫با توجه به آمار‪ ،‬يكي از خطاهايي كه معموال در برنامه رخ میدهد عدم درج‬
‫سمي كالن است در نتيجه قاعده توليدي به صورت ذيل نيز به گرامر اضافه‬
‫میگردد‪.‬‬
‫‪stmt_errorstmt stmt_list | stmt‬‬
‫در نتيجه اگر برنامه نويس سمي كالن را درج نكند دستورات به جاي ‪ stmt‬با‬
‫‪ stmt_error‬كاهش میيابد بنابراين تجزيه كننده متوقف نمیگردد بلكه پيغام‬
‫مناسب را صادر و تجزيه ادامه میيابد‪.‬‬
‫مهمترین روشهاي تصحيح خطا عبارتند از‪:‬‬
‫• ‪ -1‬تصحيح حالت اضطراري‪ :‬در اين روش تجزيه كننده هنگام كشف يك‬
‫خطا‪ ،‬نمادهاي ورودي را تا رسيدن به يك عالمت هماهنگ كننده كه به‬
‫وسيله طراح كامپايلر معين شده است ناديده میگيرد‪ .‬به عنوان مثال عالمت‬
‫سمي كالن در زبان ‪ C‬يك عالمت هماهنگ كننده است‪.‬‬
‫مدیریت خطا‬
‫• ‪ -1‬اگر پايانهاي مانند ‪ a‬باالي پشته باشد كه با نماد جاري يكسان‬
‫نباشد‪ ،‬خطا رخ ميدهد‪ ،‬به منظور پوشش خطا‪ ،‬نماد ‪ a‬را به‬
‫ورودي اضافه میكنيم‪.‬‬
‫‪• SbcA‬‬
‫‪• AaA|c‬‬
‫رشته ‪bdcc‬‬
‫• نمادهاي )‪ first(A‬را به عنوان مجموعه هماهنگ كننده ‪A‬‬
‫در نظر میگيريم ‪ .‬بنابراين اگر يكي از نمادهاي )‪first(A‬‬
‫در ورودي ظاهر شود تجزيه بر اساس ‪ A‬ادامه میيابد‪.‬‬
‫• نمادهاي )‪ follow(A‬را به عنوان نمادهاي هماهنگ كننده‬
‫‪ A‬در نظر میگيريم‪.‬‬
‫تجزيه كننده پايين به باال‬
‫ تجزيه کننده های عملگر اولويت‬‫‪ -‬تجزيه کننده های ‪LR‬‬
:‫مثالی از نحوه عملکرد تجزيه کننده پايين به باال‬
expr expr + term | expr - term | term
term 1|2|3|4
4+1-2
term +1-2
expr + 1 -2
expr + term -2
expr - 2
expr - term
expr
•
•
•
•
•
•
•
1+2-+3
term+ 2-+3
expr + 2 -+ 3
expr + term -+3
expr -+ 3
expr -+ term
expr -+ expr
‫دستگيره‬
‫دستگيره‪ ،‬دنبالهاي است كه منطبق بر سمت راست يك •‬
‫قاعده توليد بوده و كاهش آن به سمت چپ قاعده توليد يك‬
‫مرحله از مراحل معكوس سمت راستترين اشتقاق است‪.‬‬
‫• دستگيرهها را در كاهش رشته ‪ bccdef‬با توجه به گرامر‬
‫ذيل مشخص كنيد‪.‬‬
‫‪SbBCf‬‬
‫‪BBcd|c‬‬
‫‪Ce‬‬
‫ابتدا رشته ‪ bccdef‬را بوسيله سمت راست ترين اشتقاق توليد‬
‫میكنيم‪.‬‬
‫‪S‬‬
‫‪bBCf‬‬
‫‪bBef‬‬
‫‪bBcdef‬‬
‫‪bccdef‬‬
‫عملکرد تجزیه کننده های ‪LR‬‬
‫ يافتن دستگيره‬‫‪ -‬کاهش دستگيره‬
‫ساختار تجزیه کننده های ‪LR‬‬
‫مثال‬
‫گرامر ذيل را در نظر میگيريم‪.‬‬
‫‪E→E+T | T‬‬
‫‪T→id‬‬
‫گرامر به شکل زير تغييرمی کند‪.‬‬
‫‪1- S → E‬‬
‫‪2- E→E+T‬‬
‫‪3- E→T‬‬
‫‪4- T→id‬‬
‫مراحل تجزیه رشته ‪id+id‬‬
‫مهمترين روشهاي موجود عبارتند از‪:‬‬
‫‪ : LR(0) -1‬ساده ترين و ضعيفترين روش است‪.‬‬
‫‪ SLR(1) LR) -2‬ساده(‪ :‬اين روش از )‪ LR(0‬قويتر است‪.‬‬
‫‪ LR(1) -3‬يا ‪ LR‬متعارف‪ :‬قويترين روش ساخت جدول‬
‫تجزيه ‪ LR‬است‪.‬‬
‫‪ :LALR(1) -4‬از روش )‪ SLR(1‬قويتر و از )‪ CLR(1‬ضعيفتر‬
‫است‪.‬‬
‫روش )‪LR(0‬‬
‫عنصر)‪: LR(0‬‬
‫يك قاعده توليد است كه نقطه اي در سمت راست آن قرار دارد(‬
‫مانند‪ .) S→α.β :‬مكان نقطه در عنصر ‪ LR‬ميزان پيشرفت‪ ،‬در‬
‫كاهش غير پايانه سمت چپ(مانند ‪ )S‬را نشان می‌دهد‪.‬‬
‫‪S→.XYZ‬‬
‫‪S→X.YZ‬‬
‫‪S→XY.Z‬‬
‫‪S→XYZ.‬‬
‫آخر سمت راست قاعده توليد‬
‫در ‌‬
‫عنصر كاهش ي‪ :‬عنصري‌ كه نقطه ‌‬
‫‌‬
‫•‬
‫عنصر نشان دهنده يافتن يك دستگيره است‪ .‬به‬
‫‌‬
‫قر ‌ار دارد‪ .‬اين نوع‬
‫عنوان مثال‌ عنصر ‪ S→XYZ.‬نشان می‌دهد كه ‪ XYZ‬يك دستگيره‬
‫است كه می‌توان آن را به ‪ S‬كاهش داد‪.‬‬
‫ي كه كاهش ي نباشد‪ .‬به عنوان مثال ‪S→X.YZ‬‬
‫عنصر انتقالي‪ :‬عنصر ‌‬
‫‌‬
‫•‬
‫در‬
‫عنصر انتقالي نشان دهنده فرضيهاي ‌‬
‫‌‬
‫هر‬
‫عنصر انتقالي است‪‌ .‬‬
‫‌‬
‫يك‬
‫مورد دستگيره بعدي است به عنوان مثال ‪ S→X.YZ‬نشان می‌دهد‬
‫كه دستگيره ممكن است از‪ Y‬به دست آيد‪.‬‬
‫ساخت ماشين متناهی‬
E→E+T|T
T→id
E→E+T
E→T
T→id
S→E
E→E+T
E→T
T→id
S→.E
S→.E
E→.E+T
E→.T
S→.E
E→.E+T
E→.T
T→.id
E→E+T|T
T→id
‫برخورد انتقال ‪/‬کاهش‬
‫‪S→E‬‬
‫‪E→E+T‬‬
‫‪E→T‬‬
‫‪T→id‬‬
‫] ‪T→id [ E‬‬
‫کاهش‬/ ‫برخورد کاهش‬
S→E
E→E+T
E→T
E→X
T→id
X→ id