📄 acd.c
字号:
/* acd 1.9 - A compiler driver Author: Kees J. Bot * 7 Jan 1993 * Needs about 25kw heap + stack. * * Copyright 1994 Kees J. Bot, All rights reserved. * This program and documentation may be freely used under the following * restrictions: Changes that do not increase the functionality or that are * incompatible with the original may not be released to the public without * permission from the author. Use of so called "C beautifiers" is explicitly * prohibited. */char version[] = "1.9";#define nil 0#define _POSIX_SOURCE 1#include <sys/types.h>#include <stdio.h>#include <stddef.h>#include <stdlib.h>#include <unistd.h>#include <fcntl.h>#include <string.h>#include <signal.h>#include <errno.h>#include <ctype.h>#include <assert.h>#include <sys/stat.h>#include <sys/wait.h>#ifndef LIB#define LIB "/usr/lib" /* Default library directory. */#endif#define arraysize(a) (sizeof(a) / sizeof((a)[0]))#define arraylimit(a) ((a) + arraysize(a))char *program; /* Call name. */int verbose= 0; /* -v0: Silent. * -v1: Show abbreviated pass names. * -v2: Show executed UNIX commands. * -v3: Show executed ACD commands. * -v4: Show descr file as it is read. */int action= 2; /* 0: An error occured, don't do anything anymore. * 1: (-vn) Do not execute, play-act. * 2: Execute UNIX commands. */void report(char *label){ if (label == nil || label[0] == 0) { fprintf(stderr, "%s: %s\n", program, strerror(errno)); } else { fprintf(stderr, "%s: %s: %s\n", program, label, strerror(errno)); } action= 0;}void quit(int exit_code);void fatal(char *label){ report(label); quit(-1);}size_t heap_chunks= 0;void *allocate(void *mem, size_t size)/* Safe malloc/realloc. (I have heard that one can call realloc with a * null first argument with the effect below, but that is of course to * ridiculous to believe.) */{ assert(size > 0); if (mem != nil) { mem= realloc(mem, size); } else { mem= malloc(size); heap_chunks++; } if (mem == nil) fatal(nil); return mem;}void deallocate(void *mem){ if (mem != nil) { free(mem); heap_chunks--; }}char *copystr(const char *s){ char *c; c= allocate(nil, (strlen(s)+1) * sizeof(*c)); strcpy(c, s); return c;}/* Every object, list, letter, or variable, is made with cells. */typedef struct cell { unsigned short refc; /* Reference count. */ char type; /* Type of object. */ unsigned char letter; /* Simply a letter. */ char *name; /* Name of a word. */ struct cell *hash; /* Hash chain. */ struct cell *car, *cdr; /* To form lists. *//* For a word: */# define value car /* Value of a variable. */# define base cdr /* Base-name in transformations. */# define suffix cdr /* Suffix in a treat-as. */# define flags letter /* Special flags. *//* A substitution: */# define subst car} cell_t;typedef enum type { CELL, /* A list cell. */ STRING, /* To make a list of characters and substs. */ SUBST, /* Variable to substitute. */ /* Unique objects. */ LETTER, /* A letter. */ WORD, /* A string collapses to a word. */ EQUALS, /* = operator, etc. */ OPEN, CLOSE, PLUS, MINUS, STAR, INPUT, OUTPUT, WHITE, COMMENT, SEMI, EOLN, N_TYPES /* number of different types */} type_t;#define is_unique(type) ((type) >= LETTER)/* Flags on a word. */#define W_SET 0x01 /* Not undefined, e.g. assigned to. */#define W_RDONLY 0x02 /* Read only. */#define W_LOCAL 0x04 /* Local variable, immediate substitution. */#define W_TEMP 0x08 /* Name of a temporary file, delete on quit. */#define W_SUFF 0x10 /* Has a suffix set on it. */void princhar(int c)/* Print a character, escaped if important to the shell *within* quotes. */{ if (strchr("\\'\"<>();~$^&*|{}[]?", c) != nil) fputc('\\', stdout); putchar(c);}void prinstr(char *s)/* Print a string, in quotes if the shell might not like it. */{ int q= 0; char *s2= s; while (*s2 != 0) if (strchr("~`$^&*()=\\|[]{};'\"<>?", *s2++) != nil) q= 1; if (q) fputc('"', stdout); while (*s != 0) princhar(*s++); if (q) fputc('"', stdout);}void prin2(cell_t *p);void prin1(cell_t *p)/* Print a cell structure for debugging purposes. */{ if (p == nil) { printf("(\b(\b()\b)\b)"); return; } switch (p->type) { case CELL: printf("(\b(\b("); prin2(p); printf(")\b)\b)"); break; case STRING: printf("\"\b\"\b\""); prin2(p); printf("\"\b\"\b\""); break; case SUBST: printf("$\b$\b${%s}", p->subst->name); break; case LETTER: princhar(p->letter); break; case WORD: prinstr(p->name); break; case EQUALS: printf("=\b=\b="); break; case PLUS: printf("+\b+\b+"); break; case MINUS: printf("-\b-\b-"); break; case STAR: printf("*\b*\b*"); break; case INPUT: printf(verbose >= 3 ? "<\b<\b<" : "<"); break; case OUTPUT: printf(verbose >= 3 ? ">\b>\b>" : ">"); break; default: assert(0); }}void prin2(cell_t *p)/* Print a list for debugging purposes. */{ while (p != nil && p->type <= STRING) { prin1(p->car); if (p->type == CELL && p->cdr != nil) fputc(' ', stdout); p= p->cdr; } if (p != nil) prin1(p); /* Dotted pair? */}void prin1n(cell_t *p) { prin1(p); fputc('\n', stdout); }void prin2n(cell_t *p) { prin2(p); fputc('\n', stdout); }/* A program is consists of a series of lists at a certain indentation level. */typedef struct program { struct program *next; cell_t *file; /* Associated description file. */ unsigned indent; /* Line indentation level. */ unsigned lineno; /* Line number where this is found. */ cell_t *line; /* One line of tokens. */} program_t;program_t *pc; /* Program Counter (what else?) */program_t *nextpc; /* Next line to execute. */cell_t *oldcells; /* Keep a list of old cells, don't deallocate. */cell_t *newcell(void)/* Make a new empty cell. */{ cell_t *p; if (oldcells != nil) { p= oldcells; oldcells= p->cdr; heap_chunks++; } else { p= allocate(nil, sizeof(*p)); } p->refc= 0; p->type= CELL; p->letter= 0; p->name= nil; p->car= nil; p->cdr= nil; return p;}#define N_CHARS (1 + (unsigned char) -1)#define HASHDENSE 0x400cell_t *oblist[HASHDENSE + N_CHARS + N_TYPES];unsigned hashfun(cell_t *p)/* Use a blender on a cell. */{ unsigned h; char *name; switch (p->type) { case WORD: h= 0; name= p->name; while (*name != 0) h= (h * 0x1111) + *name++; return h % HASHDENSE; case LETTER: return HASHDENSE + p->letter; default: return HASHDENSE + N_CHARS + p->type; }}cell_t *search(cell_t *p, cell_t ***hook)/* Search for *p, return the one found. *hook may be used to insert or * delete. */{ cell_t *sp; sp= *(*hook= &oblist[hashfun(p)]); if (p->type == WORD) { /* More than one name per hash slot. */ int cmp= 0; while (sp != nil && (cmp= strcmp(p->name, sp->name)) > 0) sp= *(*hook= &sp->hash); if (cmp != 0) sp= nil; } return sp;}void dec(cell_t *p)/* Decrease the number of references to p, if zero delete and recurse. */{ if (p == nil || --p->refc > 0) return; if (is_unique(p->type)) { /* Remove p from the oblist. */ cell_t *o, **hook; o= search(p, &hook); if (o == p) { /* It's there, remove it. */ *hook= p->hash; p->hash= nil; } if (p->type == WORD && (p->flags & W_TEMP)) { /* A filename to remove. */ if (verbose >= 2) { printf("rm -f "); prinstr(p->name); fputc('\n', stdout); } if (unlink(p->name) < 0 && errno != ENOENT) report(p->name); } } deallocate(p->name); dec(p->car); dec(p->cdr); p->cdr= oldcells; oldcells= p; heap_chunks--;}cell_t *inc(cell_t *p)/* Increase the number of references to p. */{ cell_t *o, **hook; if (p == nil) return nil; if (++p->refc > 1 || !is_unique(p->type)) return p; /* First appearance, put p on the oblist. */ o= search(p, &hook); if (o == nil) { /* Not there yet, add it. */ p->hash= *hook; *hook= p; } else { /* There is another object already there with the same info. */ o->refc++; dec(p); p= o; } return p;}cell_t *go(cell_t *p, cell_t *field)/* Often happening: You've got p, you want p->field. */{ field= inc(field); dec(p); return field;}cell_t *cons(type_t type, cell_t *p)/* P is to be added to a list (or a string). */{ cell_t *l= newcell(); l->type= type; l->refc++; l->car= p; return l;}cell_t *append(type_t type, cell_t *p)/* P is to be appended to a list (or a string). */{ return p == nil || p->type == type ? p : cons(type, p);}cell_t *findnword(char *name, size_t n)/* Find the word with the given name of length n. */{ cell_t *w= newcell(); w->type= WORD; w->name= allocate(nil, (n+1) * sizeof(*w->name)); memcpy(w->name, name, n); w->name[n]= 0; return inc(w);}cell_t *findword(char *name)/* Find the word with the given null-terminated name. */{ return findnword(name, strlen(name));}void quit(int exstat)/* Remove all temporary names, then exit. */{ cell_t **op, *p, *v, *b; size_t chunks; /* Remove cycles, like X = X. */ for (op= oblist; op < oblist + HASHDENSE; op++) { p= *op; while (p != nil) { if (p->value != nil || p->base != nil) { v= p->value; b= p->base; p->value= nil; p->base= nil; p= *op; dec(v); dec(b); } else { p= p->hash; } } } chunks= heap_chunks; /* Something may remain on an early quit: tempfiles. */ for (op= oblist; op < oblist + HASHDENSE; op++) { while (*op != nil) { (*op)->refc= 1; dec(*op); } } if (exstat != -1 && chunks > 0) { fprintf(stderr, "%s: internal fault: %d chunks still on the heap\n", program, chunks); } exit(exstat);}void interrupt(int sig){ signal(sig, interrupt); if (verbose >= 2) write(1, "# interrupt\n", 12); action= 0;}int extalnum(int c)/* Uppercase, lowercase, digit, underscore or anything non-American. */{ return isalnum(c) || c == '_' || c >= 0200;}char *descr; /* Name of current description file. */FILE *dfp; /* Open description file. */int dch; /* Input character. */unsigned lineno; /* Line number in file. */unsigned indent; /* Indentation level. */void getdesc(void){ if (dch == EOF) return; if (dch == '\n') { lineno++; indent= 0; } if ((dch = getc(dfp)) == EOF && ferror(dfp)) fatal(descr); if (dch == 0) { fprintf(stderr, "%s: %s is a binary file.\n", program, descr); quit(-1); }}#define E_BASH 0x01 /* Escaped by backslash. */#define E_QUOTE 0x02 /* Escaped by double quote. */#define E_SIMPLE 0x04 /* More simple characters? */cell_t *get_token(void)/* Read one token from the description file. */{ int whitetype= 0; static int escape= 0; cell_t *tok; char *name; int n, i; if (escape & E_SIMPLE) { /* More simple characters? (Note: performance hack.) */ if (isalnum(dch)) { tok= newcell(); tok->type= LETTER; tok->letter= dch; getdesc(); return inc(tok); } escape&= ~E_SIMPLE; } /* Gather whitespace. */ for (;;) { if (dch == '\\' && whitetype == 0) { getdesc(); if (isspace(dch)) { /* \ whitespace: remove. */ do { getdesc(); if (dch == '#' && !(escape & E_QUOTE)) { /* \ # comment */ do getdesc(); while (dch != '\n' && dch != EOF); } } while (isspace(dch)); continue; } escape|= E_BASH; /* Escaped character. */ } if (escape != 0) break; if (dch == '#' && (indent == 0 || whitetype != 0)) { /* # Comment. */ do getdesc(); while (dch != '\n' && dch != EOF); whitetype= COMMENT; break; } if (!isspace(dch) || dch == '\n' || dch == EOF) break; whitetype= WHITE; indent++; if (dch == '\t') indent= (indent + 7) & ~7; getdesc(); } if (dch == EOF) return nil; /* Make a token. */ tok= newcell(); if (whitetype != 0) { tok->type= whitetype; return inc(tok); } if (!(escape & E_BASH) && dch == '"') { getdesc(); if (!(escape & E_QUOTE)) { /* Start of a string, signal this with a string cell. */ escape|= E_QUOTE; tok->type= STRING; return inc(tok); } else { /* End of a string, back to normal mode. */ escape&= ~E_QUOTE; deallocate(tok); return get_token(); } } if (escape & E_BASH || strchr(escape & E_QUOTE ? "$" : "$=()+-*<>;\n", dch) == nil ) { if (dch == '\n') { fprintf(stderr, "\"%s\", line %u: missing closing quote\n", descr, lineno); escape&= ~E_QUOTE; action= 0; } if (escape & E_BASH && dch == 'n') dch= '\n'; escape&= ~E_BASH; /* A simple character. */ tok->type= LETTER; tok->letter= dch; getdesc(); escape|= E_SIMPLE; return inc(tok); } if (dch != '$') { /* Single character token. */ switch (dch) { case '=': tok->type= EQUALS; break; case '(': tok->type= OPEN; break; case ')': tok->type= CLOSE; break; case '+': tok->type= PLUS; break; case '-': tok->type= MINUS; break; case '*': tok->type= STAR; break; case '<': tok->type= INPUT; break; case '>': tok->type= OUTPUT; break; case ';': tok->type= SEMI; break; case '\n': tok->type= EOLN; break; } getdesc(); return inc(tok); } /* Substitution. */ getdesc(); if (dch == EOF || isspace(dch)) { fprintf(stderr, "\"%s\", line %u: Word expected after '$'\n", descr, lineno); action= 0; deallocate(tok); return get_token(); } name= allocate(nil, (n= 16) * sizeof(*name)); i= 0; if (dch == '{' || dch == '(' /* )} */ ) { /* $(X), ${X} */ int lpar= dch; /* ( */ int rpar= lpar == '{' ? '}' : ')'; for (;;) { getdesc(); if (dch == rpar) { getdesc(); break; } if (isspace(dch) || dch == EOF) { fprintf(stderr, "\"%s\", line %u: $%c unmatched, no '%c'\n", descr, lineno, lpar, rpar); action= 0; break; } name[i++]= dch; if (i == n) name= allocate(name, (n*= 2) * sizeof(char)); } } else if (extalnum(dch)) { /* $X */ do { name[i++]= dch; if (i == n)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -