/* * syn0 * syn1 * syn1 & syntax */ static struct command * syn0(struct wordent *p1, struct wordent *p2, int flags) { struct wordent *p; struct command *t, *t1; int l; l = 0; for (p = p1; p != p2; p = p->next) switch (p->word[0]) { case '(': l++; continue; case ')': l--; if (l < 0) seterror(ERR_TOOMANYRP); continue; case '|': if (p->word[1] == '|') continue; /* fall into ... */ case '>': if (p->next != p2 && eq(p->next->word, STRand)) p = p->next; continue; case '&': if (l != 0) break; if (p->word[1] == '&') continue; t1 = syn1(p1, p, flags); if (t1->t_dtyp == NODE_LIST || t1->t_dtyp == NODE_AND || t1->t_dtyp == NODE_OR) { t = (struct command *) xcalloc(1, sizeof(*t)); t->t_dtyp = NODE_PAREN; t->t_dflg = F_AMPERSAND | F_NOINTERRUPT; t->t_dspr = t1; t1 = t; } else t1->t_dflg |= F_AMPERSAND | F_NOINTERRUPT; t = (struct command *) xcalloc(1, sizeof(*t)); t->t_dtyp = NODE_LIST; t->t_dflg = 0; t->t_dcar = t1; t->t_dcdr = syntax(p, p2, flags); return (t); } if (l == 0) return (syn1(p1, p2, flags)); seterror(ERR_TOOMANYLP); return (0); }
/* * syntax * empty * syn1 * * 从这里开始构建语法树,遍历之前扫描生成的token列表 * p1指向token列表头部,p2指向token列表末尾的下一个 * 自顶向下三级结构: syn1、syn2、syn3,函数调用关系如下 * 1.左子树:左边列表递进一层 * 2.右子树:右边列表回溯或者递归 * 3.找不到符号:所有列表递进一层 * 4.生成节点:直接返回 */ int *syntax(char **p1, char **p2) { while(p1 != p2) { if(any(**p1, ";&\n")) /* 列表前缀为命令序列分隔字符,过滤掉该token,对syntax回溯中碰到*/ p1++; else return(syn1(p1, p2)); /* 所有列表递进一层至syn1 */ } return(0); }
/* * syntax: * empty * syn1 */ static struct tnode * syntax(char **p1, char **p2) { while (p1 < p2) if (any(**p1, EOC)) p1++; else return syn1(p1, p2); return NULL; }
/* * syn3 * ( syn1 ) [ < in ] [ > out ] * word word* [ < in ] [ > out ] * * syn3负责构建复合命令和简单命令节点,前者以圆括号标记,括号内所有token列表回溯至syn1构建子命令节点; * 简单命令是语法树叶子,其左右子树节点为I/O重定向文件,并存储命令参数字符串,生成节点后直接返回。 * p1指向token列表头部,p2指向token列表末尾的下一个。 */ int *syn3(char **p1, char **p2) { char **p; char **lp, **rp; int *t; int n, l, i, o, c, flg; flg = 0; if(**p2 == ')') flg |= FPAR; /* 复合命令中最后一个子命令不需要fork子进程*/ lp = 0; /* 子命令开头*/ rp = 0; /* 子命令末尾*/ i = 0; /* 输入文件路径*/ o = 0; /* 输出文件路径*/ n = 0; /* 字符计数*/ l = 0; /* 嵌套层数*/ for(p=p1; p!=p2; p++) switch(c = **p) { case '(': if(l == 0) { if(lp != 0) error++; lp = p+1; /* 当前嵌套最外层,lp指向子命令第一个字符*/ } l++; continue; /* 同break */ case ')': l--; if(l == 0) rp = p; /* 当前嵌套最外层,rp指向子命令后面的')' */ continue; case '>': p++; if(p!=p2 && **p=='>') /* 追加模式FCAT标识*/ flg |= FCAT; else p--; /* 注意这里没有break,继续往下走*/ case '<': if(l == 0) { p++; if(p == p2) { error++; /* 后面没有字符,发生错误 */ p--; } if(any(**p, "<>(")) /* 非法字符 */ error++; if(c == '<') { if(i != 0) error++; i = (int)*p; /* 重定向到输入文件,只对简单命令有效*/ continue; } if(o != 0) error++; o = (int)*p; /* 重定向到输出文件,只对简单命令有效*/ } continue; default: if(l == 0) p1[n++] = *p; /* 命令参数前移清除以往记录,并用n计数*/ } if(lp != 0) { if(n != 0) error++; /* 复合命令,n必须为0 */ t = tree(5); t[DTYP] = TPAR; /* 分配复合命令类型节点*/ t[DSPR] = (int)syn1(lp, rp); /* 括号内所有token列表回溯至syn1构建子命令节点 */ goto out; } if(n == 0) error++; /* 简单命令,n必须不为0 */ p1[n++] = 0; /* 字符串结束*/ t = tree(n+5); /* 分配简单命令节点,大小为5个字段(DSPR字段为空)加上命令字符数*/ t[DTYP] = TCOM; for(l=0; l<n; l++) t[l+DCOM] = (int)p1[l]; out: t[DFLG] = flg; /* 固有属性或者继承自上层节点属性*/ t[DLEF] = i; /* 对于简单命令,左右子树是重定向的I/O文件*/ t[DRIT] = o; /* 对于复合命令,左右子树为空*/ return(t); }
/* * syn3: * command [arg ...] [< in] [> [>] out] * ( syn1 ) [< in] [> [>] out] */ static struct tnode * syn3(char **p1, char **p2) { struct tnode *t; enum tnflags flags; int ac, c, n, subcnt; char **p, **lp, **rp; char *fin, *fout; flags = 0; if (**p2 == RPARENTHESIS) flags |= FNOFORK; fin = NULL; fout = NULL; lp = NULL; rp = NULL; n = 0; subcnt = 0; for (p = p1; p < p2; p++) switch (c = **p) { case LPARENTHESIS: if (subcnt == 0) { if (lp != NULL) goto syn3err; lp = p + 1; } subcnt++; continue; case RPARENTHESIS: subcnt--; if (subcnt == 0) rp = p; continue; case GREATERTHAN: p++; if (p < p2 && **p == GREATERTHAN) flags |= FCAT; else p--; /*FALLTHROUGH*/ case LESSTHAN: if (subcnt == 0) { p++; if (p == p2 || any(**p, REDIRERR)) goto syn3err; if (c == LESSTHAN) { if (fin != NULL) goto syn3err; fin = *p; } else { if (fout != NULL) goto syn3err; fout = *p; } } continue; default: if (subcnt == 0) p1[n++] = *p; } if (lp == NULL) { if (n == 0) goto syn3err; if ((t = talloc()) == NULL) goto syn3err; t->ntype = TCOMMAND; t->nav = xmalloc((n + 1) * sizeof(char *)); for (ac = 0; ac < n; ac++) t->nav[ac] = p1[ac]; t->nav[ac] = NULL; } else { if (n != 0) goto syn3err; if ((t = talloc()) == NULL) goto syn3err; t->ntype = TSUBSHELL; t->nsub = syn1(lp, rp); } t->nfin = fin; t->nfout = fout; t->nflags = flags; return t; syn3err: if (error_message == NULL) error_message = ERR_SYNTAX; return NULL; }