aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/mk/parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/mk/parse.c')
-rw-r--r--src/cmd/mk/parse.c307
1 files changed, 307 insertions, 0 deletions
diff --git a/src/cmd/mk/parse.c b/src/cmd/mk/parse.c
new file mode 100644
index 00000000..b7737ef9
--- /dev/null
+++ b/src/cmd/mk/parse.c
@@ -0,0 +1,307 @@
+#include "mk.h"
+
+char *infile;
+int mkinline;
+static int rhead(char *, Word **, Word **, int *, char **);
+static char *rbody(Biobuf*);
+extern Word *target1;
+
+void
+parse(char *f, int fd, int varoverride)
+{
+ int hline;
+ char *body;
+ Word *head, *tail;
+ int attr, set, pid;
+ char *prog, *p;
+ int newfd;
+ Biobuf in;
+ Bufblock *buf;
+
+ if(fd < 0){
+ fprint(2, "open %s: %r\n", f);
+ Exit();
+ }
+ ipush();
+ infile = strdup(f);
+ mkinline = 1;
+ Binit(&in, fd, OREAD);
+ buf = newbuf();
+ while(assline(&in, buf)){
+ hline = mkinline;
+ switch(rhead(buf->start, &head, &tail, &attr, &prog))
+ {
+ case '<':
+ p = wtos(tail, ' ');
+ if(*p == 0){
+ SYNERR(-1);
+ fprint(2, "missing include file name\n");
+ Exit();
+ }
+ newfd = open(p, OREAD);
+ if(newfd < 0){
+ fprint(2, "warning: skipping missing include file %s: %r\n", p);
+ } else
+ parse(p, newfd, 0);
+ break;
+ case '|':
+ p = wtos(tail, ' ');
+ if(*p == 0){
+ SYNERR(-1);
+ fprint(2, "missing include program name\n");
+ Exit();
+ }
+ execinit();
+ pid=pipecmd(p, envy, &newfd);
+ if(newfd < 0){
+ fprint(2, "warning: skipping missing program file %s: %r\n", p);
+ } else
+ parse(p, newfd, 0);
+ while(waitup(-3, &pid) >= 0)
+ ;
+ if(pid != 0){
+ fprint(2, "bad include program status\n");
+ Exit();
+ }
+ break;
+ case ':':
+ body = rbody(&in);
+ addrules(head, tail, body, attr, hline, prog);
+ break;
+ case '=':
+ if(head->next){
+ SYNERR(-1);
+ fprint(2, "multiple vars on left side of assignment\n");
+ Exit();
+ }
+ if(symlook(head->s, S_OVERRIDE, 0)){
+ set = varoverride;
+ } else {
+ set = 1;
+ if(varoverride)
+ symlook(head->s, S_OVERRIDE, (void *)"");
+ }
+ if(set){
+/*
+char *cp;
+dumpw("tail", tail);
+cp = wtos(tail, ' '); print("assign %s to %s\n", head->s, cp); free(cp);
+*/
+ setvar(head->s, (void *) tail);
+ symlook(head->s, S_WESET, (void *)"");
+ }
+ if(attr)
+ symlook(head->s, S_NOEXPORT, (void *)"");
+ break;
+ default:
+ SYNERR(hline);
+ fprint(2, "expected one of :<=\n");
+ Exit();
+ break;
+ }
+ }
+ close(fd);
+ freebuf(buf);
+ ipop();
+}
+
+void
+addrules(Word *head, Word *tail, char *body, int attr, int hline, char *prog)
+{
+ Word *w;
+
+ assert("addrules args", head && body);
+ /* tuck away first non-meta rule as default target*/
+ if(target1 == 0 && !(attr&REGEXP)){
+ for(w = head; w; w = w->next)
+ if(charin(w->s, "%&"))
+ break;
+ if(w == 0)
+ target1 = wdup(head);
+ }
+ for(w = head; w; w = w->next)
+ addrule(w->s, tail, body, head, attr, hline, prog);
+}
+
+static int
+rhead(char *line, Word **h, Word **t, int *attr, char **prog)
+{
+ char *p;
+ char *pp;
+ int sep;
+ Rune r;
+ int n;
+ Word *w;
+
+ p = charin(line,":=<");
+ if(p == 0)
+ return('?');
+ sep = *p;
+ *p++ = 0;
+ if(sep == '<' && *p == '|'){
+ sep = '|';
+ p++;
+ }
+ *attr = 0;
+ *prog = 0;
+ if(sep == '='){
+ pp = charin(p, termchars); /* termchars is shell-dependent */
+ if (pp && *pp == '=') {
+ while (p != pp) {
+ n = chartorune(&r, p);
+ switch(r)
+ {
+ default:
+ SYNERR(-1);
+ fprint(2, "unknown attribute '%c'\n",*p);
+ Exit();
+ case 'U':
+ *attr = 1;
+ break;
+ }
+ p += n;
+ }
+ p++; /* skip trailing '=' */
+ }
+ }
+ if((sep == ':') && *p && (*p != ' ') && (*p != '\t')){
+ while (*p) {
+ n = chartorune(&r, p);
+ if (r == ':')
+ break;
+ p += n;
+ switch(r)
+ {
+ default:
+ SYNERR(-1);
+ fprint(2, "unknown attribute '%c'\n", p[-1]);
+ Exit();
+ case 'D':
+ *attr |= DEL;
+ break;
+ case 'E':
+ *attr |= NOMINUSE;
+ break;
+ case 'n':
+ *attr |= NOVIRT;
+ break;
+ case 'N':
+ *attr |= NOREC;
+ break;
+ case 'P':
+ pp = utfrune(p, ':');
+ if (pp == 0 || *pp == 0)
+ goto eos;
+ *pp = 0;
+ *prog = strdup(p);
+ *pp = ':';
+ p = pp;
+ break;
+ case 'Q':
+ *attr |= QUIET;
+ break;
+ case 'R':
+ *attr |= REGEXP;
+ break;
+ case 'U':
+ *attr |= UPD;
+ break;
+ case 'V':
+ *attr |= VIR;
+ break;
+ }
+ }
+ if (*p++ != ':') {
+ eos:
+ SYNERR(-1);
+ fprint(2, "missing trailing :\n");
+ Exit();
+ }
+ }
+ *h = w = stow(line);
+ if(*w->s == 0 && sep != '<' && sep != '|') {
+ SYNERR(mkinline-1);
+ fprint(2, "no var on left side of assignment/rule\n");
+ Exit();
+ }
+ *t = stow(p);
+ return(sep);
+}
+
+static char *
+rbody(Biobuf *in)
+{
+ Bufblock *buf;
+ int r, lastr;
+ char *p;
+
+ lastr = '\n';
+ buf = newbuf();
+ for(;;){
+ r = Bgetrune(in);
+ if (r < 0)
+ break;
+ if (lastr == '\n') {
+ if (r == '#')
+ rinsert(buf, r);
+ else if (r != ' ' && r != '\t') {
+ Bungetrune(in);
+ break;
+ }
+ } else
+ rinsert(buf, r);
+ lastr = r;
+ if (r == '\n')
+ mkinline++;
+ }
+ insert(buf, 0);
+ p = strdup(buf->start);
+ freebuf(buf);
+ return p;
+}
+
+struct input
+{
+ char *file;
+ int line;
+ struct input *next;
+};
+static struct input *inputs = 0;
+
+void
+ipush(void)
+{
+ struct input *in, *me;
+
+ me = (struct input *)Malloc(sizeof(*me));
+ me->file = infile;
+ me->line = mkinline;
+ me->next = 0;
+ if(inputs == 0)
+ inputs = me;
+ else {
+ for(in = inputs; in->next; )
+ in = in->next;
+ in->next = me;
+ }
+}
+
+void
+ipop(void)
+{
+ struct input *in, *me;
+
+ assert("pop input list", inputs != 0);
+ if(inputs->next == 0){
+ me = inputs;
+ inputs = 0;
+ } else {
+ for(in = inputs; in->next->next; )
+ in = in->next;
+ me = in->next;
+ in->next = 0;
+ }
+ infile = me->file;
+ mkinline = me->line;
+ free((char *)me);
+}