|
|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 11557 (0x2d25)
Types: TextFile
Notes: UNIX file
Names: »expr.y«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
└─⟦f4b8d8c84⟧ UNIX Filesystem
└─⟦this⟧ »cmd/expr/expr.y«
%{
/*
* Expr.y, yacc grammar for expr. Designed so no stdio is called, which
* makes the final object code about 1/3 smaller. To make, say
* yacc expr.y; cc -O -o expr y.tab.c;
*/
#include <ctype.h>
#include <stdio.h>
#define TRUE (0 == 0)
#define FALSE (0 != 0)
#define true(e) (*(e) == '\0' || (isnum(e) && atol(e) == 0) ? FALSE : TRUE)
int exstat; /* exit status returned by main() */
char *result; /* final expr printed by main */
char s0[] = "0"; /* `0' integer - `false' expr */
char s1[] = "1"; /* `1' integer - `true' expr */
char *regexp(),
*arithop(),
*relop(),
*realloc(),
*ltoa();
long atol();
/*
* The following names are used by the regular expression operator.
*/
#define BRSIZE 10 /* Length of brace list */
typedef struct {
char *b_bp; /* Ptr to start of string matched */
char *b_ep; /* Ptr to end of string matched */
} BRACE;
#define CSNUL 000 /* End of expression */
#define CSSOL 001 /* Match start of line */
#define CSEOL 002 /* End of line */
#define CSOPR 003 /* \( */
#define CSCPR 004 /* \) */
#define CSBRN 005 /* Match nth brace */
#define CSDOT 006 /* Any character */
#define CMDOT 007 /* Stream of any characters */
#define CSCHR 010 /* Match given character */
#define CMCHR 011 /* Match stream of given characters */
#define CSCCL 014 /* Character class */
#define CMCCL 015 /* Stream of character class */
#define CSNCL 016 /* Not character class */
#define CMNCL 017 /* Stream of not char class */
#define getx(c) *e++
#define ungetx(c) --e
BRACE brlist[BRSIZE]; /* brace list */
int brcount; /* # of braces in reg_expr */
char *codebuf; /* Ptr to a compiled regular expr */
int cbsiz = 512; /* Initial size of codebuf */
char *match();
char *overflow();
%}
%union {
char *str;
}
%token <str> STR
%type <str> expr
%left '|'
%left '&'
%left '<' '>' LE GE EQ NEQ /* relop tokens */
%left '+' '-' /* arithop tokens */
%left '*' '/' '%' /* arithop tokens */
%left ':' /* regexp token */
%right UMINUS '!' LEN /* uop tokens */
%%
start:
expr { result = $1; exstat = true(result) ? 0 : 1; }
;
expr:
'(' expr ')' { $$ = $2; }
| LEN expr { $$ = ltoa((long)strlen($2)); }
| '!' expr { $$ = true($2) ? s0 : s1; }
| '-' expr %prec UMINUS
{ if (isnum($2))
$$ = ltoa(-atol($2));
else {
--avx;
yyerror();
}
}
| expr ':' expr { $$ = regexp($1, $3); }
| expr '*' expr { $$ = arithop('*', $1, $3); }
| expr '/' expr { $$ = arithop('/', $1, $3); }
| expr '%' expr { $$ = arithop('%', $1, $3); }
| expr '+' expr { $$ = arithop('+', $1, $3); }
| expr '-' expr { $$ = arithop('-', $1, $3); }
| expr '<' expr { $$ = relop('<', $1, $3); }
| expr '>' expr { $$ = relop('>', $1, $3); }
| expr LE expr { $$ = relop(LE, $1, $3); }
| expr GE expr { $$ = relop(GE, $1, $3); }
| expr EQ expr { $$ = relop(EQ, $1, $3); }
| expr NEQ expr { $$ = relop(NEQ, $1, $3); }
| expr '&' expr { $$ = true($3) ? $1 : s0; }
| expr '|' expr { $$ = true($1) ? $1 : $3; }
| '{' expr ',' expr '}' { $$ = true($2) ? $4 : s0; }
| '{' expr ',' expr ',' expr '}' { $$ = true($2) ? $4 : $6; }
| STR { $$ = $1; }
| error { yyerror(); }
;
%%
char **av; /* Global version of argv[] in main() */
int avx; /* Index into av[] */
main(argc, argv)
int argc;
char **argv;
{
if (argc == 1)
return (2);
av = argv;
yyparse();
output(result, 1);
output("\n", 1);
return (exstat);
}
char *
arithop(op, e1, e2)
register int op;
register char *e1, *e2;
{
register long v1, v2;
if (!isnum(e1)) {
avx -= 3;
yyerror();
}
if (!isnum(e2)) {
--avx;
yyerror();
}
v1 = atol(e1);
v2 = atol(e2);
switch (op) {
case '+':
v1 += v2;
break;
case '-':
v1 -= v2;
break;
case '*':
v1 *= v2;
break;
case '/':
v1 /= v2;
break;
case '%':
v1 %= v2;
break;
}
return (ltoa(v1));
}
char *
relop(op, e1, e2)
register int op;
register char *e1, *e2;
{
register int cmp;
register long v1, v2;
if (!isnum(e1) || !isnum(e2))
cmp = strcmp(e1, e2);
else {
v1 = atol(e1);
v2 = atol(e2);
cmp = (v1 > v2) ? 1 : (v1 == v2) ? 0 : -1;
}
switch (op) {
case '<':
return ((cmp < 0) ? s1 : s0);
case '>':
return ((cmp > 0) ? s1 : s0);
case LE:
return ((cmp <= 0) ? s1 : s0);
case GE:
return ((cmp >= 0) ? s1 : s0);
case EQ:
return ((cmp == 0) ? s1 : s0);
case NEQ:
return ((cmp != 0) ? s1 : s0);
}
}
char *
regexp(e1, e2)
char *e1, *e2;
{
register char *a = e1;
register char *b;
register BRACE *brp;
codebuf = malloc(512);
compile(e2);
if (brcount > 0) /* brcount is now the number of braces in e2 */
brlist[brcount].b_bp = brlist[brcount].b_ep = NULL;
if (codebuf[0] == CSSOL)
b = match(a, codebuf + 1);
else
for ( ; *a != '\0'; ++a)
if ((b = match(a, codebuf)) != NULL)
break;
if (b == NULL)
return ("0");
if (brcount == 0)
return (ltoa((long)(b - a)));
/* Remaining case is extraction of fields */
for (a = e1, brp = brlist; (b = brp->b_bp) != NULL; ++brp)
while (b < brp->b_ep)
*a++ = *b++;
*a = '\0';
free (codebuf);
return (e1);
}
isnum(e)
register char *e;
{
register int c;
if ((c = *e) == '-' || c == '+')
++e;
while ((c = *e++) != '\0')
if (!isdigit(c))
return (FALSE);
return (TRUE);
}
/*
* Convert long to ascii. Return pointer to the necessary malloced storage.
*/
char *
ltoa(n)
register long n;
{
char buf[12];
register char *bp = buf;
register char *ep;
register char *e;
e = ep = malloc(12);
if (n < 0) {
*ep++ = '-';
n = -n;
}
do {
*bp++ = (n % 10) + '0';
n /= 10;
} while (n > 0);
while (bp > buf)
*ep++ = *--bp;
*ep = '\0';
return (e);
}
/*
* Compile the regular expression e into codebuf.
* Invoke regerror() on a regular expression syntax error.
*/
compile(e)
register char *e;
{
register int c;
register char *cp, *lcp;
int blevel, n, notflag, bstack[BRSIZE + 1];
brcount = 0;
blevel = 0;
cp = &codebuf[0];
if ((c = getx(c)) == '^') {
*cp++ = CSSOL;
c = getx(c);
}
while (c != '\0') {
if (cp > &codebuf[cbsiz-4])
cp = overflow(cp);
switch (c) {
case '*':
regerror();
case '.':
if ((c = getx(c)) != '*') {
*cp++ = CSDOT;
continue;
}
*cp++ = CMDOT;
c = getx(c);
continue;
case '$':
if ((c = getx(c)) != '\0') {
ungetx(c);
c = '$';
goto character;
}
*cp++ = CSEOL;
continue;
case '[':
/*
* lcp[0] will contain C<S|M><C|N>CL. lcp[1] will be
* the number of chars in the class. These are followed
* by the members of the class singly enumerated.
* ']' is valid only at the start of the member list.
* '-' is valid only at the end of the member list.
*/
lcp = cp;
if ((c = getx(c)) == '^')
notflag = TRUE;
else {
notflag = FALSE;
ungetx(c);
}
cp += 2;
if ((c = getx(c)) == ']')
*cp++ = c;
else
ungetx(c);
while ((c = getx(c)) != ']') {
if (c == '\0')
regerror();
if (c!='-' || cp==lcp+2) {
if (cp >= &codebuf[cbsiz-4])
cp = overflow(cp);
*cp++ = c;
continue;
}
/* c = '-' now. Lookahead at the next char */
if ((c = getx(c)) == '\0')
regerror();
if (c == ']') {
*cp++ = '-';
ungetx(c);
continue;
}
if ((n=cp[-1]) > c)
regerror();
while (++n <= c) {
if (cp >= &codebuf[cbsiz-4])
cp = overflow(cp);
*cp++ = n;
}
}
if ((c = getx(c)) == '*') {
lcp[0] = (notflag) ? CMNCL : CMCCL;
c = getx(c);
}
else
lcp[0] = (notflag) ? CSNCL : CSCCL;
if ((n=cp-(lcp+2)) > 255)
regerror();
*++lcp = n;
continue;
case '\\':
switch (c = getx(c)) {
case '\0':
regerror();
case '(':
*cp++ = CSOPR;
*cp++ = bstack[blevel++] = brcount++;
c = getx(c);
continue;
case ')':
if (blevel == 0)
regerror();
*cp++ = CSCPR;
*cp++ = bstack[--blevel];
c = getx(c);
continue;
default:
if (isascii(c) && isdigit(c)) {
*cp++ = CSBRN;
*cp++ = c-'0' - 1;
c = getx(c);
continue;
}
}
default:
character:
*cp++ = CSCHR;
*cp++ = c;
if ((c = getx(c)) == '*') {
cp[-2] = CMCHR;
c = getx(c);
}
}
}
*cp++ = CSNUL;
return;
}
/*
* Given a pointer to a compiled expression `cp' and a pointer to a line `lp',
* return a ptr to the char following the last char of the match
* if successful, NULL otherwise.
*/
char *
match(lp, cp)
register char *lp, *cp;
{
register int n;
char *llp, *lcp;
for (;;) {
switch (*cp++) {
case CSNUL:
return (lp);
case CSEOL:
if (*lp)
return (NULL);
return (lp);
case CSOPR:
brlist[*cp++].b_bp = lp;
continue;
case CSCPR:
brlist[*cp++].b_ep = lp;
continue;
case CSBRN:
n = *cp++;
lcp = cp;
cp = brlist[n].b_bp;
n = brlist[n].b_ep - cp;
if (n > strlen(lp))
return (NULL);
while (n-- > 0)
if (*lp++ != *cp++)
return (NULL);
cp = lcp;
continue;
case CSDOT:
if (*lp++ == '\0')
return (NULL);
continue;
case CMDOT:
llp = lp;
while (*lp)
lp++;
goto star;
case CSCHR:
if (*cp++ != *lp++)
return (NULL);
continue;
case CMCHR:
llp = lp;
while (*cp == *lp)
lp++;
cp++;
goto star;
case CSCCL:
n = *cp++;
while (*cp++ != *lp)
if (--n == 0)
return (NULL);
lp++;
cp += n-1;
continue;
case CMCCL:
llp = lp;
lcp = cp;
while (*lp) {
cp = lcp;
n = *cp++;
while (*cp++ != *lp)
if (--n == 0)
goto star;
lp++;
}
cp = lcp + *lcp + 1;
goto star;
case CSNCL:
if (*lp == '\0')
return (NULL);
n = *cp++;
while (n--)
if (*cp++ == *lp)
return (NULL);
lp++;
continue;
case CMNCL:
llp = lp;
lcp = cp;
while (*lp) {
cp = lcp;
n = *cp++;
while (n--) {
if (*cp++ == *lp) {
cp = lcp + *lcp + 1;
goto star;
}
}
lp++;
}
cp = lcp + *lcp + 1;
star:
do {
if (lcp=match(lp, cp))
return (lcp);
} while (--lp >= llp);
return (NULL);
}
}
}
/*
* overflow enlarges codebuf by 128 bytes. The argument is a pointer
* to a position in codebuf - the function returns a pointer with the same
* relative position in the new buffer.
*/
char *
overflow(pc)
register char *pc;
{
register int posn = pc - codebuf;
if ((codebuf = realloc(codebuf, cbsiz += 128)) == NULL)
regerror();
return (codebuf + posn);
}
/*
* An output function to avoid having to include stdio.
*/
output(s, fildes)
register char *s;
int fildes;
{
register int len;
len = strlen(s);
if ((write(fildes, s, len)) != len)
exit(3);
}
yylex()
{
register int c;
if ((yylval.str = av[++avx]) == NULL)
return (EOF);
if (av[avx][1] == '\0')
switch (c = av[avx][0]) {
case '{':
case '}':
case ',':
case '|':
case '&':
case '<':
case '>':
case '+':
case '-':
case '*':
case '/':
case '%':
case ':':
case '!':
case '(':
case ')':
return (c);
default:
return (STR);
}
if (av[avx][1] == '=' && av[avx][2] == '\0')
switch (c = av[avx][0]) {
case '<':
return (LE);
case '>':
return (GE);
case '=':
return (EQ);
case '!':
return (NEQ);
default:
return (STR);
}
if (strcmp(yylval.str, "len") == 0)
return (LEN);
return (STR);
}
/*
* The common code between yyerror() and regerror() (in regexp.c) is split
* off into errexit().
*/
yyerror()
{
output("expr: ", 2);
errexit();
}
regerror()
{
output("expr: regular expression ", 2);
--avx;
errexit();
}
errexit()
{
output("syntax error at argument # ", 2);
output(ltoa((long) avx), 2);
output("\n", 2);
exit(2);
}