تجزیهکننده بازگشتی دنباله
در علوم کامپیوتر، تجزیهکنندهٔ بازگشتی دنباله یک اشتقاق از تجزیهکنندههای شایعتر بازگشتی تنزلی است. تجزیهکنندههای بازگشتی دنباله بیشتر برای تجزیه کردن دستور زبانهای چپگرد استفاده میشوند. آنها نسبت به تجزیهکنندههای بازگشتی تنزلی از فضای پشتهای کمتری استفاده میکنند. پیادهسازی آنها نیز ساده است. تجزیهکنندههای بازگشتی تنزلی نمیتوانند دستور زبانهای چپگرد را تجزیه کنند (چون در حلقهٔ بینهایت گیر میکنند). تجزیهکنندههای بازگشتی دنباله به وسیله روش بازپدری(reparenting) این کار را میسر کردهاند.[1]
مثال
یک دستور زبان EBNF مانند زیر را در اختیار داریم:
E: T
T: T { '+' F } | F
F: F { '*' I } | I
I: <identifier>
یک تجزیهکنندهٔ بازگشتی دنباله ساده میتواند بسیار شبیه به یک تجزیهکنندهٔ بازگشتی تنزلی نوشته شود. الگوریتم معمول برای تجزیهٔ یک دستور زبان مانند دستور زبان بالا با استفاده از یک درخت نحو انتزاعی(AST) بدین شکل است:
- سطح بعدی دستور زبان را تجزیه کن و درخت خروجیاش را به دست آور، به عنوان اولین درخت F تعیینش کن.
- زمانی که یک برچسب پایانی T وجود دارد، میتواند به عنوان گره پدر این گره گذاشته شود:
- یک گره جدید اختصاص بده به نام N
- عملگر کنونی N را به عنوان برچسب ورودی کنونی قرار بده.
- ورودی را به اندازه یک برچسب جلو ببر.
- درختچه سمت چپ N را F قرار بده.
- سطح بعدی دستور زبان را تجزیه کن و به عنوان درخت بعدی X ذخیرهاش کن.
- درختچه سمت چپ N را X قرار بده.
- بعد F را برابر N قرار بده.
- و N را به عنوان خروجی برگردان.
در زیر میتوان یک برنامه پیادهسازی شده این تجزیهکننده را در زبان برنامهنویسی سی دید:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
enum node_type
{
NODE_NUMBER,
NODE_OPERATOR,
NODE_IDENTIFIER,
NODE_MUL,
NODE_ADD
};
typedef struct _exptree exptree;
struct _exptree {
int val;
char* token;
int line_number;
exptree *left;
exptree *right;
};
struct _lexval {
int ival;
char *sval;
int line;
enum node_type typ;
} lexval;
int line_number = 0;
FILE *fs,*fd;
exptree *parse_e(void);
exptree *parse_t(void);
exptree *parse_f(void);
exptree *parse_i(void);
void next_token(){
while (1){
int t;
char *buff;
t = fgetc(fs);
//printf("after getchar = %d\n",t);
if (t == ' ' || t == '\t' || t=='\n'){
//printf("white space\n"); /* ignore whitespace */
}
else if (t == '\n')
{
line_number++;
//printf("line = %i\n",line_number);
return;
}
else if(t == EOF){
return;
}
else if(isdigit(t))
{
//ungetc (t, stdin);
fseek(fs,ftell(fs)-1,SEEK_SET);
fscanf (fs,"%d", &lexval.ival);
//printf("in lexer ival = %d\n",lexval.ival);
lexval.sval = "";
lexval.line = line_number;
lexval.typ = NODE_NUMBER;
return;
} else if (t == '*'){
//printf("lexer mul\n");
//ungetc (t, stdin);
//scanf ("%s", buff);
lexval.sval = "*";
//printf("in lexer ival = %s\n",lexval.sval);
lexval.line = line_number;
lexval.typ = NODE_MUL;
return;
} else if (t == '+'){
//printf("lexer add\n");
//ungetc (t, stdin);
//scanf ("%s0", buff);
lexval.sval = "+";
//printf("in lexer ival = %s\n",lexval.sval);
lexval.line = line_number;
lexval.typ = NODE_ADD;
return;
}
}
}
exptree* alloc_tree(){
return (exptree *) malloc(sizeof(exptree));
}
exptree *parse_e(void)
{
//printf("in e ival = %d\n",lexval.ival);
return parse_t();
}
exptree *parse_t(void)
{
//printf("in t\n");
//printf("in t ival = %d\n",lexval.ival);
exptree *first_f = parse_f();
while(lexval.typ == NODE_ADD) {
//printf("in t loop\n");
exptree *replace_tree = alloc_tree();
replace_tree->token = lexval.sval;
replace_tree->left = first_f;
//printf("in t loop begin next_token\n");
next_token();
//printf("parse_t = %c\n",replace_tree->token);
replace_tree->right = parse_f();
replace_tree->val = replace_tree->left->val + replace_tree->right->val;
printf("hasil t = %d\n",replace_tree->val);
first_f = replace_tree;
}
return first_f;
}
exptree *parse_f(void)
{
//printf("in f\n");
//printf("in f ival = %d\n",lexval.ival);
exptree *first_i = parse_i();
//printf("before f loop\n");
while(lexval.typ == NODE_MUL) {
//printf("in f loop\n");
exptree *replace_tree = alloc_tree();
replace_tree->token = lexval.sval;
replace_tree->left = first_i;
//printf("in f loop begin next_token\n");
next_token();
//printf("parse_f = %c\n",replace_tree->token);
replace_tree->right = parse_i();
replace_tree->val = replace_tree->left->val * replace_tree->right->val;
printf("hasil f = %d\n",replace_tree->val);
first_i = replace_tree;
}
//printf("about to exit from f\n");
return first_i;
}
exptree *parse_i(void)
{
//printf("in i\n");
exptree *i = alloc_tree();
i->left = i->right = NULL;
i->val = lexval.ival;
//printf("in i ival = %d\n",lexval.ival);
//printf("in i = %d\n",i->val);
next_token();
//printf("parse_i = %c\n",i->token);
return i;
}
int main( int argc, char** argv){
if(argc != 2) return 1;
fs = fopen(argv[1], "r");
if (fs == NULL) {
perror("Failed to open file ");
}
//char * = strcat(
fd = fopen (strcat(argv[1],".c"),"w");
if (fd == NULL) {
perror("Failed to open file ");
}
char *template = "#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <ctype.h>\n#include <sys/types.h>\nvoid main(){\n";
fputs(template,fd);
char *buffer = malloc(35);
next_token();
exptree *temp = parse_e();
printf("hasil akhir = %d\n",temp->val);
snprintf(buffer, 30, "printf(\"hasil = %d\\n\");\n", temp->val);
fputs(buffer,fd);
fputs("}",fd);
fclose(fs);
fclose(fd);
char *substr = strdup(argv[1]);
char * pch;
pch = strstr(substr,".lol");
strncpy(pch,"\0",1);
snprintf(buffer, 30, "gcc -o %s %s", substr,argv[1]);
system(buffer);
return 0;
}
جستارهای وابسته
- متا دوم
برای مطالعهٔ بیشتر
منابع
- «نسخه آرشیو شده». بایگانیشده از اصلی در ۸ دسامبر ۲۰۱۷. دریافتشده در ۷ دسامبر ۲۰۱۷.