parse.c revision 3f54fd611f536639ec30dd53c48e5ec1897cc7d9
/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1984-2012 AT&T Intellectual Property *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* Glenn Fowler <gsf@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
/*
* Glenn Fowler
* AT&T Research
*
* makefile lexical scanner and parser
*
* interleaved recursive parse() and expand() nesting supported
*
* NOTE: readline() from file does double copy to pp->ip and sp
* it should be possible to go directly to sp
*/
#include "make.h"
#include "options.h"
#include <sig.h>
#define PUSHLOCAL(p) do{for(p=pp->local;p;p=p->next)if(!(p->newv.property&V_scope))p->bucket->value=(char*)p->oldv;}while(0)
#define POPLOCAL(p) do{for(p=pp->local;p;p=p->next)if(!(p->newv.property&V_scope))p->bucket->value=(char*)&p->newv;}while(0)
struct Local_s /* local variable state */
{
int line; /* declaration line number */
};
typedef struct Control_s /* flow control block stack */
{
int flags; /* block flags */
union
{
char* buffer; /* loop body buffer */
} body;
int line; /* loop line number */
union
{
struct
{
char* test; /* while loop test */
int free; /* free test */
} w;
struct
{
char** args; /* for loop arg vector */
} f;
} loop;
} Control_t;
typedef struct Parseinfo_s /* recursive parse state stack */
{
/* the rest are implicitly initialized */
int argc; /* local argc */
char* name; /* current level input name */
char* here; /* <<? termination string */
char* bp; /* input buffer pointer */
char* stashget; /* loop body stash get */
char* pushback; /* line pushback pointer */
int checkhere; /* <<? offset */
int line; /* prev level input line number */
int splice; /* splice line */
short indent; /* active indentation level */
unsigned char eval; /* eval block level */
unsigned char status; /* action return status */
} Parseinfo_t;
/*
* WARNING: getline() uses the first keyword char
*/
{
"break", CON_break,
"continue", CON_continue,
"elif", CON_elif,
"else", CON_else,
"end", CON_end,
"error", CON_error,
"eval", CON_eval,
"exit", CON_exit,
"for", CON_for,
"if", CON_if,
"let", CON_let,
"local", CON_local,
"print", CON_print,
"read", CON_read,
"return", CON_return,
"rules", CON_rules,
"set", CON_set,
"while", CON_while,
};
static Local_t* freelocals;
/*
* unwind the parse stack to level on errors
*/
void
{
register Rule_t* r;
{
{
}
{
}
{
while (lcl)
{
}
}
{
{
}
}
{
}
pp--;
}
}
/*
* declare a single local variable t
* redefinitions on same line>0 get value 1
* if (flags & V_append) then old value is retained
*/
static void
{
register Var_t* v;
register Local_t* p;
register char* s;
register char* d;
if (d = strchr(t, '='))
*d = 0;
if (!(v = getvar(t)))
{
for (s = t; *s; s++)
if (istype(*s, C_TERMINAL))
}
{
/*
* check for duplicate declarations
*/
{
if (d)
*d++ = '=';
d = "1";
else
d = null;
return;
}
}
newlocal(p);
p->oldv = v;
{
}
if (d)
{
*d++ = '=';
}
else
}
/*
* declare local variables using tmp string xp
* v is first expanded
* 2 funtion argument styles supported
* (formal ...) actual ...
* -[n] actual
*/
static void
{
register char* t;
register char* a;
long top;
int argn;
Local_t* p;
int argc = 0;
int optional = 0;
char* argv = 0;
char* formal = 0;
{
p->line = 0;
break;
}
if (t = strchr(v, '\n'))
*t = 0;
if (t)
*t = '\n';
{
if (!ap && *t == '-')
{
if (!argc)
argc = 1;
}
else if (!ap && *t == '(')
{
if (*argv != ')')
*argv = 0;
argv = t + 1;
argc = 1;
argn = 0;
}
else
{
if (argv)
{
if (!formal)
{
optional = 1;
if (*v)
*(v - 1) = ' ';
v = null;
}
argc++;
formal = a;
}
else if (argc)
{
}
}
}
if (argc)
{
if (formal)
{
if (!optional)
{
if (!a || !streq(a, "..."))
}
while (formal)
{
}
}
{
}
sfstrclose(ap);
}
}
/*
* copy the local argc into internal.val
*/
void
argcount(void)
{
}
/*
* compute next for loop iteration variable
*/
static int
iterate(void)
{
register char* p;
return 0;
/*
* NOTE: this may bypass checks in setvar()
*/
else
{
{
}
v->value = p;
}
return 1;
}
/*
* check for pp directives
*/
static void
directive(register char* s)
{
register char* t;
register int n;
Rule_t* r;
while (isspace(*++s));
if (isdigit(*s))
{
n = 0;
while (isdigit(*s))
n = n * 10 + *s++ - '0';
while (isspace(*s))
s++;
if (*s++ == '"')
{
if (!file)
while (*s && *s != '"')
if (*s == '"')
{
if (!*t)
else
{
r = makerule(t);
{
r->property |= P_dontcare;
else
{
compref(r, COMP_INCLUDE);
}
}
}
}
}
}
else
{
for (t = s; *s && !isspace(*s); s++);
if (*s)
*s++ = 0;
if (streq(t, "rules"))
rules(s);
else if (!state.preprocess && strmatch(t, "assert|define|elif|else|endif|endmac|error|if|ifdef|ifndef|include|line|macdef|pragma|unassert|undef|warning"))
{
punt(0);
}
}
}
/*
* read line from file or buffer
*
* `\<newline>' splices the current and next lead line
* `#...<newline>' comments (preceded by space) are stripped from files
*
* return value for file input placed in pp->ip
*/
static char*
{
register char* s;
register char* t;
register char* f;
register int c;
register int n;
register int q;
Rule_t* r;
int start;
int here;
int m;
long line;
trap();
{
{
{
goto pushback;
}
return s;
}
{
*(t - 1) = *t = ' ';
else
{
return s;
}
}
else
return s;
}
else
{
{
*s++ = '\n';
if (t = strchr(s, '\n'))
else
return s;
}
{
}
else
do
{
trap();
break;
continue;
while (block(1));
n = q = 0;
for (;;)
{
{
case EOF:
eof:
if (q == COMMENT)
else if (q)
{
}
return 0;
case '\r':
{
if (c != EOF)
c = '\r';
break;
}
/*FALLTHROUGH*/
case '\n':
error_info.line++;
if (!q || q == COMMENT)
{
while (t > s && (*(t - 1) == ' ' || *(t - 1) == '\t'))
t--;
if (*s == COMMENT)
{
directive(s);
*s = 0;
}
return s;
}
break;
case '\\':
{
case EOF:
goto eof;
case '\r':
{
if (c != EOF)
c = '\r';
break;
}
/*FALLTHROUGH*/
case '\n':
if (lead > 0)
{
error_info.line++;
continue;
}
c = '\\';
break;
default:
break;
}
break;
case '"':
case '\'':
if (c == q)
q = 0;
else if (!q)
{
q = c;
}
break;
case '/':
{
case EOF:
goto eof;
case '*':
mid:
{
case EOF:
goto end;
case '\n':
error_info.line++;
break;
case '/':
{
case EOF:
goto comeof;
case '*':
break;
case '/':
break;
default:
goto mid;
}
case '*':
{
case EOF:
goto comeof;
case '*':
break;
case '/':
goto end;
default:
goto mid;
}
}
end:
error_info.line--;
c = ' ';
break;
default:
c = '/';
break;
}
break;
case COMMENT:
for (;;)
{
case EOF:
goto eof;
case '\\':
{
case EOF:
goto eof;
case '\\':
break;
case '\n':
if (!lead)
goto newline;
error_info.line++;
break;
}
continue;
case '\n':
goto newline;
}
break;
case '(':
case '[':
case '{':
if (!q)
n++;
break;
case ')':
case ']':
case '}':
if (!q && n)
n--;
break;
case '<':
{
if (m == here)
else
here = m + 1;
}
break;
}
}
}
else if (s)
{
error_info.line++;
{
*s++ = '\n';
}
if (f = strchr(s, '\n'))
{
{
/*
* NOTE: `\\n' are permanently eliminated *each pass*
* line counts are preserved by adding newlines
* after sliding the spliced segment(s)
*/
n = 1;
t = f - 1;
for (;;)
{
if (!(c = *++f))
{
f = 0;
*t = 0;
break;
}
else if (c != '\n')
*t++ = c;
else if (*(f - 1) != '\\')
{
f = t + 1;
while (n--)
{
*t++ = ' ';
*t++ = '\n';
}
break;
}
else
{
n++;
t--;
}
}
}
}
{
*f = 0;
}
return s;
}
else
return 0;
}
/*
* structured flow control line input into sp
*
* lead identifies a lead line (as opposed to an action line)
* term is the line terminator char placed in sp
* 0 return on EOF
*/
static int
{
register int c;
register char* s;
register char* t;
register int indent;
long n;
int i;
char* e;
char* lin;
char* tok;
{
if (!s)
free(t);
}
{
indent = 0;
{
if (*s == '\t')
{
s++;
}
else if (*s == ' ')
{
static int warned;
for (t = s; isspace(*t); t++);
if (!*t)
goto again;
if (!warned)
{
warned = 1;
}
while (*s == ' ')
{
s++;
indent++;
}
}
else
break;
}
{
if (c == 'b' || c == 'c' || c == 'e' || c == 'f' || c == 'i' || c == 'l' || c == 'p' || c == 'r' || c == 's' || c == 'w')
{
for (t = s; istype(*t, C_VARIABLE2); t++);
{
*t = 0;
i = (nv = (Namval_t*)strsearch(controls, elementsof(controls), sizeof(*controls), stracmp, s, NiL)) ? nv->value : 0;
for (*t = c; isspace(*t); t++);
/*UNDENT*/
if (i)
{
switch (i)
{
case CON_if:
if (c & CON_skip)
else
continue;
case CON_else:
if (!(c & CON_if))
{
if (c & CON_else)
if (*t)
if (c & CON_kept)
else
{
}
continue;
}
t++;
while (isspace(*++t));
/*FALLTHROUGH*/
case CON_elif:
if (!(c & CON_if))
if (c & CON_else)
else
{
}
continue;
case CON_end:
if (*t)
if (c & CON_eval)
{
{
{
}
{
}
else
continue;
}
}
if (c & CON_for)
{
{
}
}
if (c & CON_while)
{
}
if (c & CON_stash)
continue;
case CON_for:
if (c & CON_skip)
else
{
{
if (!iterate())
else
{
{
{
}
}
else
}
}
else
}
continue;
case CON_while:
else
{
{
{
}
}
else
}
continue;
case CON_break:
case CON_continue:
{
{
{
if (i == CON_continue)
break;
}
}
}
continue;
case CON_return:
{
{
while (t > s && isspace(*(t - 1)))
t--;
}
else if (*t)
{
{
tm = TMX_NOTIME;
else
}
if (tm == TMX_NOTIME)
{
}
else if (tm)
{
}
else
{
}
}
else
}
continue;
case CON_eval:
continue;
case CON_rules:
rules(t);
continue;
case CON_let:
continue;
case CON_local:
continue;
case CON_error:
{
c = error_info.line;
if (i > 0 && !(i & 040))
error_info.line = 0;
error(i, "%s", t);
error_info.line = c;
}
continue;
case CON_exit:
{
finish(i);
}
continue;
case CON_print:
case CON_read:
{
int d;
int m;
int x;
char* a;
char* f;
d = i == CON_print;
f = 0;
n = '\n';
/*UNDENT...*/
for (;;)
{
for (t = a; *t == ' '; t++);
if ((x = *t) != '-' && x != '+')
break;
a = t;
if (*(t - 1) == *t && !*(t + 1))
{
for (t = a; *t == ' '; t++);
break;
}
for (;;)
{
switch (m = *t++)
{
case 0:
break;
case 'f':
if (*t)
f = t;
break;
case 'i':
case 'o':
case 'p':
{
t = "-";
}
{
}
if (!streq(t, "-"))
switch (m)
{
case 'i':
break;
case 'o':
break;
case 'p':
else
break;
}
switch (d)
{
case 0:
break;
case 1:
break;
case 2:
break;
}
else if (m != 'p')
break;
case 'n':
n = -1;
continue;
case 'u':
switch (c = *t++)
{
case 'm':
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
d = c - '0';
break;
default:
break;
}
continue;
default:
continue;
}
break;
}
}
/*...INDENT*/
if (i == CON_print)
{
{
if (f)
else
}
else if (*t || n != -1)
}
else if (n != -1 || *t)
{
{
else
{
if (f)
f = null;
setvar(t, f, 0);
}
}
else
}
}
continue;
case CON_set:
{
}
continue;
}
}
/*INDENT*/
}
}
}
#if DEBUG
else
#endif
{
for (t = s; isspace(*t); t++);
if (*t)
{
{
{
}
return 0;
}
break;
}
return 0;
break;
else if (!lead)
{
return 1;
}
}
}
if (!s)
return 0;
{
case 0:
break;
case 1:
break;
default:
{
for (;;)
{
if (--i <= 0)
break;
}
sfstrclose(tp);
}
break;
}
return 1;
}
/*
* makefile statement parser
*
* the statement grammar is
*
* <lhs> <op> <rhs> <act>
*
* <lhs>, <rhs> and <act> are placed in sp
* <op> determines which components are expanded when read
*
* <op> <lhs> <rhs> <act>
* -----------------------------
* = 0 0 -
* := 1 1 -
* += 1 1 -
* : 1 1 0
* :op: 0 0 0
*
* an action <act> is not expanded when read
* actions are indented by a number of <tab> chars
* the indent tabs are stripped from each line in the action
* the first line not indented by this amount terminates the action
* ideally only '\t' should be used although ' ' are ok using state.tabstops
* the statement operator flags OP_* are returned
*/
static int
{
register int c;
register char* s;
register char* t;
char* b;
char* p;
char* brace = 0;
char* ecarb = 0;
int item = 0;
int op = 0;
int nest = 0;
int paren = 0;
int quote = 0;
long rhs_pos = -1;
long act_pos = -1;
long lin_pos;
return op;
*opr = 0;
while (c = *s++)
{
if (c == '\\')
{
if (*s)
s++;
}
else if (c == quote)
quote = 0;
else if (c == '"' || c == '\'')
quote = c;
else if (!quote)
{
if (brace)
{
if (c == '{')
nest++;
else if (c == '}' && !--nest)
{
for (p = s; isspace(*p); p++);
{
brace = 0;
continue;
}
ecarb = s - 1;
}
}
else if (c == '(')
paren++;
else if (c == ')' && !paren--)
else if (!paren)
{
if (c == '{')
{
brace = s - 1;
nest++;
}
else if (c == '}')
else if (c == ':')
{
{
t = s + 1;
break;
}
t = s;
if (*t++ == ':')
{
c = *t;
*t = 0;
{
*(t - 1) = 0;
*(t - 1) = ':';
{
}
}
*t = c;
break;
}
t = s;
break;
}
else if (item < 2)
{
if (isspace(c))
{
item++;
while (isspace(*s))
s++;
if ((c = *s) != ':' && c != '+' && c != '&' && c != '=')
item++;
}
else if (c == '+')
{
if (*s == '=')
{
t = s + 1;
break;
}
}
else if (c == '&')
{
if (*s == '=')
{
t = s + 1;
break;
}
}
else if (c == '=')
{
if (*s == '=')
{
t = s + 1;
break;
}
t = s;
break;
}
}
}
}
}
if (quote)
else if (paren)
if (op)
{
{
*(s - 1) = 0;
}
else
p = t + strlen(t);
while (p > t && isspace(*(p - 1)))
p--;
*p = 0;
while (isspace(*t))
t++;
for (s--; s > t && isspace(*(s - 1)); s--);
*s = 0;
}
else
{
p = s - 1;
while (p > s && isspace(*(p - 1)))
p--;
*p = 0;
}
if (brace)
{
*t = 0;
if (ecarb)
{
*ecarb = 0;
nest = 0;
}
if (p > ++brace)
*p++ = '\n';
for (;;)
{
if (!*brace)
{
*brace = ' ';
*(brace + 1) = 0;
break;
}
break;
brace++;
}
quote = 0;
while (nest)
{
{
break;
}
while (s < t)
{
if ((c = *s++) == '\\')
{
if (s < t)
s++;
}
else if (c == quote)
quote = 0;
else if (c == '"' || c == '\'')
quote = c;
else if (!quote)
{
if (c == '{')
nest++;
else if (c == '}' && !--nest)
{
p = s - 1;
while (s < t && isspace(*s))
s++;
if (s < t)
while (p > t && isspace(*(p - 1)))
p--;
*p = 0;
if (!*t)
act_pos = -1;
break;
}
}
}
}
}
{
{
for (;;)
{
switch (*t++)
{
case 0:
break;
case '"':
case '\'':
if (*(t - 1) == quote)
quote = 0;
else if (!quote)
quote = *(t - 1);
continue;
case '(':
case '[':
case '{':
if (!quote)
nest++;
continue;
case ')':
case ']':
case '}':
if (!quote)
nest--;
continue;
case '<':
{
s = t - 1;
while (isspace(*++t));
if (*t)
{
p = t;
while (*++t)
if (isspace(*t))
{
*t = 0;
break;
}
while (--s >= b && isspace(*s));
*(s + 1) = 0;
}
break;
}
continue;
default:
continue;
}
break;
}
if (!*b)
rhs_pos = -1;
}
for (;;)
{
if (s <= t)
{
act_pos = -1;
break;
}
if (*--s != '\n')
{
*(s + 1) = 0;
break;
}
}
}
return op;
}
{
"altstate", NAME_altstate,
"assignment", NAME_assignment,
"context", NAME_context,
"dynamic", NAME_dynamic,
"glob", NAME_glob,
"identifier", NAME_identifier,
"intvar", NAME_intvar,
"option", NAME_option,
"path", NAME_path,
"staterule", NAME_staterule,
"statevar", NAME_statevar,
"variable", NAME_variable,
};
#if DEBUG
static void
{
char* m;
char* s;
char* x;
int i;
int flags;
int open_max;
for (i = 0; i <= open_max; i++)
{
{
/* not open */
continue;
}
if (!details)
{
continue;
}
m = "--";
else
{
case O_RDONLY:
m = "r-";
break;
case O_WRONLY:
m = "-w";
break;
case O_RDWR:
m = "rw";
break;
default:
m = "??";
break;
}
{
continue;
}
#if defined(S_IFSOCK) && 0
{
type = 0;
prot = 0;
#ifdef SO_TYPE
type = -1;
#endif
#ifdef SO_PROTOTYPE
prot = -1;
#endif
s = 0;
switch (type)
{
case SOCK_DGRAM:
switch (addr.sin_family)
{
case AF_INET:
#ifdef AF_INET6
case AF_INET6:
#endif
s = "udp";
break;
}
break;
case SOCK_STREAM:
switch (addr.sin_family)
{
case AF_INET:
#ifdef AF_INET6
case AF_INET6:
#endif
#ifdef IPPROTO_SCTP
if (prot == IPPROTO_SCTP)
s = "sctp";
else
#endif
s = "tcp";
break;
}
break;
#ifdef SOCK_RAW
case SOCK_RAW:
s = "raw";
break;
#endif
#ifdef SOCK_RDM
case SOCK_RDM:
s = "rdm";
break;
#endif
#ifdef SOCK_SEQPACKET
case SOCK_SEQPACKET:
s = "seqpacket";
break;
#endif
}
if (!s)
{
}
port = 0;
#ifdef INET6_ADDRSTRLEN
else
#endif
{
}
else
{
a = fam;
}
if (port)
else
continue;
}
#endif
sfprintf(sfstdout, "%02d %s%s %s /dev/inode/%u/%u\n", i, m, x, fmtmode(st.st_mode, 0), st.st_dev, st.st_ino);
}
}
#endif
/*
* parse a basic assertion statement
*/
static void
{
register char* s;
register Rule_t* r;
register List_t* p;
register List_t* q;
int c;
int i;
int n;
int isactive;
Rule_t* x;
Var_t* v;
char* name;
struct /* prereq attributes */
{
int op; /* assertion op */
if (opr)
{
return;
}
if (internal.assert_p->prereqs && (opr = associate(internal.assert_p, NiL, lhs, NiL)) && opr->prereqs && (opr = opr->prereqs->rule) && (opr->property & P_operator) && !opr->uname)
{
return;
}
/*
* special check for internal.query
*/
{
c = 0;
else if (*s == '-' && !*(s + 1))
{
if (streq(s, "blocked"))
{
#if DEBUG
c = 1;
#else
#endif
}
else if (streq(s, "buckets"))
{
c = 0;
}
else if (streq(s, "fds"))
{
#if DEBUG
fds(1);
c = 0;
#else
#endif
}
else if (streq(s, "hash"))
{
c = 0;
}
else if (streq(s, "jobs"))
{
#if DEBUG
c = 1;
#else
#endif
}
else if (streq(s, "nametype"))
{
{
for (i = 0; i < elementsof(nametypes); i++)
}
break;
}
else if (streq(s, "rules"))
{
c = 1;
}
else if (streq(s, "stack"))
{
c = 1;
while (--sp > &parsestack[0])
{
}
}
else if (streq(s, "variables"))
{
c = 1;
}
else if (streq(s, "view"))
{
{
c = 1;
}
}
else
}
else
while (s)
{
if (r = getrule(s))
{
c = 1;
}
if (v = getvar(s))
{
c = 1;
}
}
if (c)
return;
}
/*
* construct the prerequsite list and attributes
*/
x = 0;
if (!*rhs)
p = q = 0;
{
/*
* <ATTRNAME><attribute> names (and sets) the attribute
* <ATTRSET><attribute> sets the attribute
* <ATTRCLEAR><attribute> clears the attribute
*/
{
*s = ATTRNAME;
r = getrule(s);
*s = c;
if (!r)
r = getrule(s + 1);
if (!r || !(r->property & P_attribute))
{
if (r)
{
Flags_t m = 0;
/*
* user controlled dynamic
* staterule attributes
*/
m = D_entries;
m = D_member;
m = D_regular;
m = D_scanned;
if (m)
{
if (c == ATTRCLEAR)
{
}
else
continue;
}
}
r = makerule(s);
}
}
else
r = makerule(s);
if (r->property & P_attribute)
{
if (c == ATTRCLEAR)
{
}
else
/*
* assertion attributes
*/
/*
* attributes not propagated by merge()
*
* NOTE: internal.make->make is cleared in immediate()
*/
{
else
}
/*
* merge() handles the rest
*/
else
}
else
{
{
if (!x)
x = r;
else if (!*s)
else
{
while (c = *s++)
{
if (c == '%')
else
}
}
}
{
if (state.user <= 1 && state.reading && state.makefile && (s = strchr(r->name, '=')) && *(s + 1) == '=')
{
*s = 0;
*s = '=';
}
}
if (!p)
else
}
}
prereqs = p;
if (*act || (set.op & (A_null|A_target)) || (set.rule.property & (P_make|P_local)) == (P_make|P_local))
jointproperty = 0;
/*
* assert each target
*/
while (name)
{
if (joint)
{
{
continue;
}
{
}
else
r->property |= jointproperty;
}
{
in = 0;
{
{
*s = 0;
*s = c;
}
}
if (in)
{
/*
* pattern association rule
*/
x = makerule(s);
addprereq(in, x, ((set.op & A_insert) || *(s + strlen(s) - 1) != '%') ? PREREQ_INSERT : PREREQ_APPEND);
{
}
}
else
{
/*
* metarule assertion
*/
{
if (p->rule == x)
{
/*
* rhs pattern
*/
if (q)
}
else if (!prereqs)
prereqs = p;
}
/*
* update the metarule intermediate prerequisite graph
*/
if (in)
{
if (out)
{
{
do
{
}
}
else
}
else
{
if (out && c != PREREQ_DELETE)
}
}
}
else
{
if (!internal.main->prereqs && !state.global && !(set.rule.property & P_operator) && !(set.op & A_special) && !special(r) && !special(&set.rule))
{
}
}
{
continue; /* drop this in 2000 */
{
error(2, "%s: %s atom cannot appear as target", r->name, (r->property & P_readonly) ? "readonly" : "staterule");
continue;
}
else if (r->property & P_readonly)
}
if (!((r->property|set.rule.property) & P_immediate) && (r->status == UPDATE || r->status == MAKING))
{
{
continue;
}
{
continue;
}
isactive = 1;
}
else
isactive = 0;
{
int dynamic;
int property;
if (r->property & P_attribute)
{
continue;
}
if (!(x = (r->property & P_state) ? rulestate(r, 0) : staterule(RULE, r, NiL, 0)) || r->prereqs != x->prereqs)
{
{
continue;
}
*r = *x;
r->name = s;
r->uname = 0;
continue;
}
zero(*r);
r->name = s;
}
{
continue;
}
if (prereqs)
{
else
{
{
q = r->prereqs;
r->prereqs = p;
dynamic(r);
p = r->prereqs;
r->prereqs = q;
}
}
}
/*
* check action
*/
if (*act)
{
if (s && r->action != s && !state.user && !(set.rule.property & P_operator) && !(set.op & A_special) && !special(r) && !special(&set.rule))
}
/*
* assign attributes
*/
/*
* attributes not handled by merge()
*/
if (((set.rule.property|clr.rule.property) & P_functional) && !(r->property & P_state) && ((v = getvar(r->name)) || (v = setvar(r->name, null, 0))))
{
v->property |= V_functional;
else
v->property &= ~V_functional;
}
{
s = r->name;
if (*s == ':' && !*++s)
r->property |= P_operator;
else
}
r->property |= P_readonly;
{
}
/*
* user controlled dynamic staterule attributes
*/
{
{
}
{
}
}
/*
* these are done after attributes have been assigned
*/
{
r->property |= P_attribute;
{
{
}
else
}
}
if (joint)
{
else
{
r->property |= P_attribute;
}
}
r->dynamic &= ~D_compiled;
/*
* do immediate actions right away
*/
if (r->property & P_immediate)
immediate(r);
}
}
/*
* parse an assignment statement
*/
static void
{
register Rule_t* r;
register char* s;
register int n;
Var_t* v;
if (internal.assign_p->prereqs && (r = associate(internal.assign_p, NiL, lhs, NiL)) && r->prereqs && (r = r->prereqs->rule) && (r->property & P_operator) && !r->uname)
{
r->name = s;
r->uname = 0;
return;
}
debug((-6, "assignment: lhs=`%s' %s%srhs=`%-.1024s'", lhs, (op & OP_APPEND) ? "[append] " : null, (op & OP_STATE) ? "[state] " : null, rhs));
else
{
n = 0;
n |= V_append;
if (op & OP_AUXILIARY)
n |= V_auxiliary;
n |= V_scan;
{
{
}
}
else
}
}
/*
* invoke or verify rules s
*/
void
rules(char* s)
{
register char* t;
register char* e;
if (e = strchr(s, '\n'))
*e = 0;
if (e)
*e = '\n';
t = null;
{
}
else if (t == null)
else
}
/*
* external PUSHLOCAL()
*/
void*
pushlocal(void)
{
register Local_t* p;
PUSHLOCAL(p);
}
/*
* external POPLOCAL()
* pos is return value of previous pushlocal()
*/
void
{
register Local_t* p;
register Local_t* t;
{
freelocal(t);
}
POPLOCAL(p);
}
static long makeexpr(const char*, char**, void*);
/*
* <var>
* <var> = <expression>
* [ <var> = ] <quote> ... <quote>
*/
static char*
{
register char* arg;
register int c;
char* var;
char* varend;
char buf[10];
long n;
if ((c = *s) && c != MARK_QUOTE && c != '"')
{
if (!istype(*s, C_VARIABLE1))
varend = s;
while (isspace(*s))
s++;
if (*s != '=' || *(s + 1) == '=')
{
c = *varend;
*varend = 0;
*varend = c;
*p = s;
/*
* determine if in string or numeric context
*/
if ((*s == '!' || *s == '=') && *(s + 1) == '=')
{
s++;
while (isspace(*++s));
if (*s == MARK_QUOTE)
{
*end = s;
return arg;
}
}
if (!*arg)
*val = 0;
else
{
if (*s)
*val = 1;
}
return 0;
}
while (isspace(*++s));
}
else
var = 0;
if ((c = *s) == MARK_QUOTE)
{
for (arg = ++s; *s && *s != c; s++);
*end = s;
if (*s)
while (isspace(*++s));
}
else if (c == '"')
{
for (arg = ++s; *s && *s != c; s++)
if (*s == '\\' && *(s + 1))
s++;
*end = s;
if (*s)
while (isspace(*++s));
}
else if (var)
{
end = 0;
}
else
if (var)
{
c = *varend;
*varend = 0;
if (end)
{
n = **end;
**end = 0;
/*
* XXX: this handles the symptom but not the bug
*/
arg++;
}
*varend = c;
if (end)
**end = n;
}
*p = s;
}
/*
* supplementary make expression evaluator for strexpr()
*
* "..." == "..." strmatch()
* "..." != "..." strmatch()
* "..." < "..." strcoll()
* "..." <= "..." strcoll()
* "..." > "..." strcoll()
* "..." >= "..." strcoll()
* <var> "<value>"
* <var> = "..." "..."
* ( <var> = "..." ) "..."
* <var> = <expression> <expression> ? "1" : ""
*
* NOTE: '"' translated to MARK_QUOTE by expr()
*/
static long
{
char* s = (char*)cs;
int c;
int q;
int c1;
int c2;
int m1;
int m2;
char* paren;
char* s1;
char* s2;
char* e1;
char* e2;
long n;
if (!s)
/* n == expression value */;
else
{
if ((c = *s) == ')')
{
paren = s;
e2 = s;
while (isspace(*++s));
}
else
paren = 0;
if (!(c = *s) || c != '<' && c != '>' && (*(s + 1) != '=' || c != '!' && c != '='))
{
if (paren)
s = paren;
}
else
{
q = *++s != '=';
while (isspace(*++s));
n = 0;
else
{
*e1 = 0;
*e2 = 0;
{
{
*(e1 - 1) = 0;
m1 = 1;
}
else
m1 = 0;
{
*(e2 - 1) = 0;
m2 = 1;
}
else
m2 = 0;
}
switch (c)
{
case '>':
break;
case '<':
break;
case '!':
break;
default:
break;
}
{
if (m1)
if (m2)
}
}
}
if (paren)
{
if (!*s)
s--;
*s = ')';
}
}
*p = s;
return n;
}
/*
* expression evaluation on s using temporary string xp
* '"' temporarily converted to MARK_QUOTE
* s is first expanded
*/
long
{
register char* t;
register int p;
register char** v;
int c;
long top;
char* restore[PARSEDEPTH];
v = restore;
t = s;
p = 0;
for (;;)
switch (*t++)
{
case '(':
if (p)
p++;
break;
case ')':
if (p)
p--;
break;
case '"':
if (p <= 1)
{
p = !p;
*(*v++ = t - 1) = MARK_QUOTE;
}
break;
case '\\':
if (*t++)
break;
/*FALLTHROUGH*/
case 0:
case '\n':
c = *--t;
*t = 0;
while (v > restore)
**--v = '"';
*t = c;
}
}
/*
* error exit during interpreter()
*/
static void
exit_interpreter(int code)
{
}
/*
* interactive query loop
*/
void
interpreter(char* msg)
{
int level;
void (*errexit)(int);
if (msg)
{
}
else
state.interpreter++;
state.interpreter--;
if (msg)
error(0, "\n");
}
/*
* read and parse file fp or line buffer bp
* non-zero returned if target to be updated
*/
int
{
register int op;
char* lhs;
char* rhs;
char* act;
char* alt;
{
return 0;
}
#if DEBUG
#else
if (fp)
#endif
/*
* push the parse stack
*/
{
}
else
{
}
error_info.line = 0;
/*
* statement parse loop
*/
for (;;)
{
continue;
if (!op)
break;
switch (op & OP_STATEMENT)
{
case OP_ASSERT:
break;
case OP_ASSIGN:
break;
case OP_EMPTY:
{
if (*lhs)
{
rhs--;
}
else
{
}
{
{
{
rhs++;
break;
}
{
if (*rhs)
goto quit;
}
}
else if (!*act)
if (*act)
{
if (*rhs)
{
*rhs++ = 0;
rhs++;
}
opr = 0;
}
else
{
}
}
if (opr)
{
{
rhs++;
break;
}
else
{
}
}
}
break;
#if DEBUG
default:
#endif
}
}
quit:
/*
* pop the parse stack
*/
error(3, "missing %d closing end statement%s", pp->cp - pp->block, pp->cp - pp->block == 1 ? null : "s");
if (scoped)
{
}
{
while (lcl)
{
}
}
pp--;
#if DEBUG
#else
if (fp)
#endif
}
char*
parsefile(void)
{
register Parseinfo_t* pi;
return error_info.file;
}