📄 acd.c
字号:
execvp(argv[0], argv); report(argv[0]); exit(-1); } } if (fd[0] >= 0) close(fd[0]); if (fd[1] >= 0) close(fd[1]); if (i >= 0 && action >= 2) { /* Wait for the command to terminate. */ while ((r= wait(&status)) != pid && (r >= 0 || errno == EINTR)); if (status != 0) { int sig= WTERMSIG(status); if (!WIFEXITED(status) && sig != SIGINT && sig != SIGPIPE) { fprintf(stderr, "%s: %s: Signal %d%s\n", program, argv[0], sig, status & 0x80 ? " - core dumped" : ""); } action= 0; } } deallocate(argv);}/* Special read-only variables ($*) and lists. */cell_t *V_star, **pV_star;cell_t *L_files, **pL_files= &L_files;cell_t *V_in, *V_out, *V_stop, *L_args, *L_predef;typedef enum exec { DOIT, DONT } exec_t;void execute(exec_t how, unsigned indent);int equal(cell_t *p, cell_t *q)/* Two lists are equal if they contain each others elements. */{ cell_t *t, *m1, *m2; t= inc(newcell()); t->cdr= inc(newcell()); t->cdr->cdr= inc(newcell()); t->cdr->car= newcell(); t->cdr->car->type= MINUS; t->cdr->car= inc(t->cdr->car); /* Compute p - q. */ t->car= inc(p); t->cdr->cdr->car= inc(q); m1= evaluate(inc(t), IMPLODE); dec(m1); /* Compute q - p. */ t->car= q; t->cdr->cdr->car= p; m2= evaluate(t, IMPLODE); dec(m2); /* Both results must be empty. */ return m1 == nil && m2 == nil;}int wordlist(cell_t **pw, int atom)/* Check if p is a list of words, typically an imploded list. Return * the number of words seen, -1 if they are not words (INPUT/OUTPUT?). * If atom is true than a list of one word is turned into a word. */{ int n= 0; cell_t *p, **pp= pw; while (*pp != nil) { *pp= append(CELL, *pp); p= (*pp)->car; n= n >= 0 && p != nil && p->type == WORD ? n+1 : -1; pp= &(*pp)->cdr; } if (atom && n == 1) *pw= go(*pw, (*pw)->car); return n;}char *template; /* Current name of a temporary file. */char *maketemp(void)/* Return a name that can be used as a temporary filename. */{ static char *tp= nil; int i= 0; if (tp == nil) { size_t len= strlen(template); template= allocate(template, (len+20) * sizeof(*template)); sprintf(template+len, "/acd%d", getpid()); tp= template + strlen(template); } for (;;) { switch (tp[i]) { case 0: tp[i]= 'a'; tp[i+1]= 0; return template; case 'z': tp[i++]= 'a'; break; default: tp[i]++; return template; } }}cell_t *splitenv(char *env)/* Split a string from the environment into several words at whitespace * and colons. Two colons (::) become a dot. */{ cell_t *r= nil, **pr= &r; char *p; do { while (*env != 0 && isspace(*env)) env++; if (*env == 0) break; p= env; while (*p != 0 && !isspace(*p) && *p != ':') p++; *pr= cons(CELL, p == env ? findword(".") : findnword(env, p-env)); pr= &(*pr)->cdr; env= p; } while (*env++ != 0); return r;}void key_usage(char *how){ fprintf(stderr, "\"%s\", line %u: Usage: %s %s\n", descr, pc->lineno, pc->line->car->name, how); action= 0;}void inappropriate(void){ fprintf(stderr, "\"%s\", line %u: wrong execution phase for '%s'\n", descr, pc->lineno, pc->line->car->name); action= 0;}int readonly(cell_t *v){ if (v->flags & W_RDONLY) { fprintf(stderr, "\"%s\", line %u: %s is read-only\n", descr, pc->lineno, v->name); action= 0; return 1; } return 0;}void complain(cell_t *err)/* acd: err ... */{ cell_t *w; fprintf(stderr, "%s:", program); while (err != nil) { if (err->type == CELL) { w= err->car; err= err->cdr; } else { w= err; err= nil; } fprintf(stderr, " %s", w->name); } action= 0;}int keyword(char *name)/* True if the current line is headed by the given keyword. */{ cell_t *t; return (t= pc->line) != nil && t->type == CELL && (t= t->car) != nil && t->type == WORD && strcmp(t->name, name) == 0;}cell_t *getvar(cell_t *v)/* Return a word or the word referenced by a subst. */{ if (v == nil) return nil; if (v->type == WORD) return v; if (v->type == SUBST) return v->subst; return nil;}void argscan(void), compile(void);void transform(rule_t *);void exec_one(void)/* Execute one line of the program. */{ cell_t *v, *p, *q, *r, *t; unsigned n= 0; static int last_if= 1; /* Description file this line came from. */ descr= pc->file->name; for (p= pc->line; p != nil; p= p->cdr) n++; if (n == 0) return; /* Null statement. */ p= pc->line; q= p->cdr; r= q == nil ? nil : q->cdr; /* Try one by one all the different commands. */ if (n >= 2 && q->car != nil && q->car->type == EQUALS) { /* An assignment. */ int flags; if ((v= getvar(p->car)) == nil) { fprintf(stderr, "\"%s\", line %u: Usage: <var> = expr ...\n", descr, pc->lineno); action= 0; return; } if (readonly(v)) return; flags= v->flags; v->flags|= W_LOCAL|W_RDONLY; t= evaluate(inc(r), PARTIAL); dec(v->value); v->value= t; v->flags= flags | W_SET; if (talk()) { printf("%s =\b=\b= ", v->name); prin2n(t); } } else if (keyword("unset")) { /* Set a variable to "undefined". */ if (n != 2 || (v= getvar(q->car)) == nil) { key_usage("<var>"); return; } if (readonly(v)) return; if (talk()) prin2n(p); dec(v->value); v->value= nil; v->flags&= ~W_SET; } else if (keyword("import")) { /* Import a variable from the UNIX environment. */ char *env; if (n != 2 || (v= getvar(q->car)) == nil) { key_usage("<var>"); return; } if (readonly(v)) return; if ((env= getenv(v->name)) == nil) return; if (talk()) printf("import %s=%s\n", v->name, env); t= splitenv(env); dec(v->value); v->value= t; v->flags|= W_SET; } else if (keyword("mktemp")) { /* Assign a variable the name of a temporary file. */ char *tmp, *suff; r= evaluate(inc(r), IMPLODE); if (n == 3 && wordlist(&r, 1) != 1) n= 0; if ((n != 2 && n != 3) || (v= getvar(q->car)) == nil) { dec(r); key_usage("<var> [<suffix>]"); return; } if (readonly(v)) { dec(r); return; } tmp= maketemp(); suff= r == nil ? "" : r->name; t= newcell(); t->type= WORD; t->name= allocate(nil, (strlen(tmp) + strlen(suff) + 1) * sizeof(*t->name)); strcpy(t->name, tmp); strcat(t->name, suff); t= inc(t); dec(r); dec(v->value); v->value= t; v->flags|= W_SET; t->flags|= W_TEMP; if (talk()) printf("mktemp %s=%s\n", v->name, t->name); } else if (keyword("temporary")) { /* Mark a word as a temporary file. */ cell_t *tmp; tmp= evaluate(inc(q), IMPLODE); if (wordlist(&tmp, 1) < 0) { dec(tmp); key_usage("<word>"); return; } if (talk()) printf("temporary %s\n", tmp->name); tmp->flags|= W_TEMP; dec(tmp); } else if (keyword("stop")) { /* Set the suffix to stop the transformation on. */ cell_t *suff; if (phase > SCAN) { inappropriate(); return; } suff= evaluate(inc(q), IMPLODE); if (wordlist(&suff, 1) != 1) { dec(suff); key_usage("<suffix>"); return; } dec(V_stop); V_stop= suff; if (talk()) printf("stop %s\n", suff->name); } else if (keyword("numeric")) { /* Check if a string denotes a number, like $n in -O$n. */ cell_t *num; char *pn; num= evaluate(inc(q), IMPLODE); if (wordlist(&num, 1) != 1) { dec(num); key_usage("<arg>"); return; } if (talk()) printf("numeric %s\n", num->name); (void) strtoul(num->name, &pn, 10); if (*pn != 0) { complain(phase == SCAN ? V_star->value : nil); if (phase == SCAN) fputc(':', stderr); fprintf(stderr, " '%s' is not a number\n", num->name); } dec(num); } else if (keyword("error")) { /* Signal an error. */ cell_t *err; err= evaluate(inc(q), IMPLODE); if (wordlist(&err, 0) < 1) { dec(err); key_usage("expr ..."); return; } if (talk()) { printf("error "); prin2n(err); } complain(err); fputc('\n', stderr); dec(err); } else if (keyword("if")) { /* if (list) = (list) using set comparison. */ int eq; if (n != 4 || r->car == nil || r->car->type != EQUALS) { key_usage("<expr> = <expr>"); execute(DONT, pc->indent+1); last_if= 1; return; } q= q->car; r= r->cdr->car; if (talk()) { printf("if "); prin1(t= evaluate(inc(q), IMPLODE)); dec(t); printf(" = "); prin1n(t= evaluate(inc(r), IMPLODE)); dec(t); } eq= equal(q, r); execute(eq ? DOIT : DONT, pc->indent+1); last_if= eq; } else if (keyword("ifdef") || keyword("ifndef")) { /* Is a variable defined or undefined? */ int doit; if (n != 2 || (v= getvar(q->car)) == nil) { key_usage("<var>"); execute(DONT, pc->indent+1); last_if= 1; return; } if (talk()) prin2n(p); doit= ((v->flags & W_SET) != 0) ^ (p->car->name[2] == 'n'); execute(doit ? DOIT : DONT, pc->indent+1); last_if= doit; } else if (keyword("iftemp") || keyword("ifhash")) { /* Is a file a temporary file? */ /* Does a file need preprocessing? */ cell_t *file; int doit= 0; file= evaluate(inc(q), IMPLODE); if (wordlist(&file, 1) != 1) { dec(file); key_usage("<arg>"); return; } if (talk()) printf("%s %s\n", p->car->name, file->name); if (p->car->name[2] == 't') { /* iftemp file */ if (file->flags & W_TEMP) doit= 1; } else { /* ifhash file */ int fd; char hash; if ((fd= open(file->name, O_RDONLY)) >= 0) { if (read(fd, &hash, 1) == 1 && hash == '#') doit= 1; close(fd); } } dec(file); execute(doit ? DOIT : DONT, pc->indent+1); last_if= doit; } else if (keyword("else")) { /* Else clause for an if, ifdef, or ifndef. */ if (n != 1) { key_usage(""); execute(DONT, pc->indent+1); return; } if (talk()) prin2n(p); execute(!last_if ? DOIT : DONT, pc->indent+1); } else if (keyword("treat")) { /* Treat a file as having a certain suffix. */ if (phase > SCAN) { inappropriate(); return; } if (n == 3) { q= evaluate(inc(q->car), IMPLODE); r= evaluate(inc(r->car), IMPLODE); } if (n != 3 || wordlist(&q, 1) != 1 || wordlist(&r, 1) != 1) { if (n == 3) { dec(q); dec(r); } key_usage("<file> <suffix>"); return; } if (talk()) printf("treat %s %s\n", q->name, r->name); dec(q->suffix); q->suffix= r; q->flags|= W_SUFF; dec(q); } else if (keyword("apply")) { /* Apply a transformation rule to the current input file. */ rule_t *rule, *sav_path; cell_t *sav_wait, *sav_in, *sav_out; program_t *sav_next; if (phase != COMPILE) { inappropriate(); return; } if (V_star->value->cdr != nil) { fprintf(stderr, "\"%s\", line %u: $* is not one file\n", descr, pc->lineno); action= 0; return; } if (n == 3) { q= evaluate(inc(q->car), IMPLODE); r= evaluate(inc(r->car), IMPLODE); } if (n != 3 || wordlist(&q, 1) != 1 || wordlist(&r, 1) != 1) { if (n == 3) { dec(q); dec(r); } key_usage("<file> <suffix>"); return; } if (talk()) printf("apply %s %s\n", q->name, r->name); /* Find a rule */ for (rule= rules; rule != nil; rule= rule->next) { if (rule->type == TRANSFORM && rule->from == q && rule->to == r) break; } if (rule == nil) { fprintf(stderr, "\"%s\", line %u: no %s %s transformation\n", descr, pc->lineno, q->name, r->name); action= 0; } dec(q); dec(r); if (rule == nil) return; /* Save the world. */ sav_path= rule->path; sav_wait= rule->wait; sav_in= V_in->value; sav_out= V_out->value; sav_next= nextpc; /* Isolate the rule and give it new input. */ rule->path= rule; rule->wait= V_star->value; V_star->value= nil; V_in->value= nil; V_out->value= nil; transform(rule); /* Retrieve the new $* and repair. */ V_star->value= rule->wait; rule->path= sav_path; rule->wait= sav_wait; V_in->value= sav_in; V_out->value= sav_out; V_out->flags= W_SET|W_LOCAL; nextpc= sav_next; } else if (keyword("include")) { /* Include another description file into this program. */ cell_t *file; program_t *incl, *prog, **ppg= &prog; file= evaluate(inc(q), IMPLODE); if (wordlist(&file, 1) != 1) { dec(file); key_usage("<file>"); return; } if (talk()) printf("include %s\n", file->name); descr= file->name; incl= pc; prog= get_prog(); dec(file); /* Raise the program to the include's indent level. */ while (*ppg != nil) { (*ppg)->indent += incl->indent; ppg= &(*ppg)->next; } /* Kill the include and splice the included program in. */ dec(incl->line); incl->line= nil; *ppg= incl->next; incl->next= prog; pc= incl; nextpc= prog; } else if (keyword("arg")) { /* An argument scanning rule. */ if (phase > SCAN) { inappropriate(); return; } if (n < 2) { key_usage("<string> ..."); execute(DONT, pc->indent+1); return; } if (talk()) prin2n(p); newrule(ARG, inc(q), nil); /* Always skip the body, it comes later. */ execute(DONT, pc->indent+1); } else if (keyword("transform")) { /* A file transformation rule. */ if (phase > SCAN) { inappropriate(); return; } if (n == 3) { q= evaluate(inc(q->car), IMPLODE); r= evaluate(inc(r->car), IMPLODE); } if (n != 3 || wordlist(&q, 1) != 1 || wordlist(&r, 1) != 1) { if (n == 3) { dec(q); dec(r); } key_usage("<suffix1> <suffix2>"); execute(DONT, pc->indent+1); return; } if (talk()) printf("transform %s %s\n", q->name, r->name); newrule(TRANSFORM, q, r); /* Body comes later. */ execute(DONT, pc->indent+1); } else if (keyword("prefer")) { /* Prefer a transformation over others. */ if (phase > SCAN) { inappropriate(); return; } if (n == 3) { q= evaluate(inc(q->car), IMPLODE); r= evaluate(inc(r->car), IMPLODE); } if (n != 3 || wordlist(&q, 1) != 1 || wordlist(&r, 1) != 1) { if (n == 3) { dec(q); dec(r); } key_usage("<suffix1> <suffix2>"); return; } if (talk()) printf("prefer %s %s\n", q->name, r->name); newrule(PREFER, q, r); } else if (keyword("combine")) { /* A file combination (loader) rule. */ if (phase > SCAN) { inappropriate(); return; } if (n == 3) { q= evaluate(inc(q->car), IMPLODE); r= evaluate(inc(r->car), IMPLODE); } if (n != 3 || wordlist(&q, 0) < 1 || wordlist(&r, 1) != 1) { if (n == 3) { dec(q); dec(r); } key_usage("<suffix-list> <suffix>"); execute(DONT, pc->indent+1); return; } if (talk()) { printf("combine "); prin1(q); printf(" %s\n", r->name); } newrule(COMBINE, q, r); /* Body comes later. */ execute(DONT, pc->indent+1); } else if (keyword("scan") || keyword("compile")) { program_t *next= nextpc;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -