cparen - C expression parenthesizer
bradn at tekecs.UUCP
bradn at tekecs.UUCP
Thu Jul 21 04:15:12 AEST 1983
This is the source for Cparen (mail programs willing), imbedded in
a shell script.
To extract the source:
make a directory called "cparen";
save this letter under the name "sharch" in that directory;
edit this letter(vi sharch), removing all lines up to and
including the line beginning with "===== remove this line"
execute the resulting shell script (sh sharch).
Notes on the make:
during the make, yacc should print the message:
conflicts: 7 shift/reduce
that message is normal -- it is not an error.
If you have any problems building cparen, write me at
...decvax!tektronix!tekecs!bradn
Brad Needham
===== remove this line and those above =====
cat >cparen.1 <<\EOF
.TH CPAREN "4/12/83" "Tek local"
.SH NAME
cparen - add parentheses to C expressions
.SH SYNOPSIS
.B cparen
[
.B \-t
.I types
]
.SH DESCRIPTION
Written for those of us who can never remember the precedence and
associativity of operators in C,
.B cparen
reads lines of C code from standard-in,
adds parentheses to indicate operator binding in expressions,
then writes the resultant code to standard-out.
.PP
The input code fragment need not contain complete statements.
For example, the following line is a valid input to
.B cparen:
.br
} else if (x->d_prep > 56 && x->d_assoc == LEFT)
.br
.PP
Normally,
.B cparen
considers identifiers in expressions to be variable names.
The
.B \-t
option allows you to specify a whitespace-separated list of types.
For example,
.br
cparen -t 'amap anop'
.br
Declares "amap" and "anop" as type names rather than variable names.
.SH DIAGNOSTICS
Exit status is 2 if
.B cparen
was invoked improperly,
1 if some other error occurred,
0 if all went well.
.SH AUTHOR
Brad Needham, bradn
.SH BUGS
.B Cparen
assumes that the input code fragment came from a syntactically correct
C program -- it does not attempt to give reasonable syntax-error messages.
.PP
Because
.B cparen
focuses on C statments it does not recognize other constructs e.g.
variable or function declarations.
.PP
The input is not filtered through the C preprocessor.
EOF
cat >Makefile <<\EOF
CFLAGS = -g
announce: cparen
: cparen is built
cparen.cat: cparen.1
nroff -man cparen.1 >cparen.cat
cparen: cparen.o parse.o lex.o hid.o
cc -o cparen cparen.o lex.o parse.o hid.o -ll
cparen.o: cparen.c cparen.h parse.c
parse.o: parse.c cparen.h
lex.o: lex.c cparen.h parse.c
hid.o: hid.c cparen.h
parse.c: parse.y
-rm -f parse.c
yacc -d parse.y
mv y.tab.c parse.c
chmod a-w parse.c
lex.c: lex.l
-rm -f lex.c
lex lex.l
mv lex.yy.c lex.c
chmod a-w lex.c
clean:
-rm -f parse.c lex.c y.tab.h hid.o lex.o parse.o cparen.o
EOF
cat >cparen.c <<\EOF
/*
* Copyright (c) 1983 by
* Tektronix, Incorporated Beaverton, Oregon 97077
* All rights reserved.
*/
#include <stdio.h>
#include "cparen.h"
#include "y.tab.h"
static char *rcsid = "$Header: /da/bradn/.bin/src/cparen/RCS/cparen.c,v 1.8 83/04/17 11:53:19 bradn Exp $";
main(argc,argv)
int argc;
char **argv;
{
char *tp, *ep, *cp;
struct lexed *lp; /* lex token pointer */
int atend; /* a temp */
char *rindex();
if ((cmd = rindex(argv[0], '/'))) {
cmd++;
} else {
cmd = argv[0];
}
/* scan the command line */
tp = (char *) 0;
while (++argv, --argc > 0) {
cp = *argv;
if (*cp == '-') {
while (*++cp) {
switch(*cp) {
case 't':
if (tp) {
fprintf(stderr, "%s: option -%c used more than once\n", cmd, *cp);
goto baduse;
}
if (++argv, --argc <= 0) {
fprintf(stderr, "%s: missing type list\n", cmd);
goto baduse;
}
tp = *argv;
break;
default:
fprintf(stderr, "%s: unknown option -%c\n", cmd, *cp);
goto baduse;
}
}
} else {
fprintf(stderr, "%s: extra string `%s'\n", cmd, cp);
baduse:
fprintf(stderr, "Usage:\n %s [-t types]\n", cmd);
exit(2);
}
}
if (tp) {
/* install whitespace-separated type names */
atend = 0;
while (!atend && *tp) {
for (ep = tp;
*ep && *ep != ' ' && *ep != '\t' && *ep != '\n';
ep++)
;
atend = *ep == '\0';
*ep = '\0';
if (ep - tp > 0) {
newtype(tp);
}
tp = ++ep;
}
}
/* init the lexed token list */
firsttok.l_text = "";
firsttok.l_prev = (struct lexed *) 0;
firsttok.l_next = &lasttok;
firsttok.l_val = 0;
lasttok.l_text = "";
lasttok.l_prev = &firsttok;
lasttok.l_next = (struct lexed *) 0;
lasttok.l_val = 0;
nonode.n_op = LIT;
nonode.n_flags = 0;
nonode.n_ledge = (struct lexed *) 0;
nonode.n_redge = (struct lexed *) 0;
if (yyparse() == 1) {
exit(1);
}
for (lp = firsttok.l_next; lp != &lasttok; lp = lp->l_next) {
fputs(lp->l_text, stdout);
}
exit(0);
}
consider(op, lc, rc) /* consider putting parens around the children */
int op; /* the parent operator */
struct node *lc; /* the left child (or NIL) */
struct node *rc; /* the right child (or NIL) */
{
struct node **cpp; /* child pointer-pointer (a temp) */
struct node *cp; /* child pointer */
/* ignore children of the 'literal' operator */
if (op == LIT) {
return;
}
/* for each child ... */
cpp = &lc;
do {
/* consider only non-null, non-dummy children */
cp = *cpp;
if (cp && cp != NOP) {
if (haspar(cp)
|| op == CAST && cpp == &lc
|| cp->n_op == LIT
|| cp->n_op == CAST && !hasr(cp)
|| op == CM
|| op == BRACK && cpp == &rc
|| op == CALL && cpp == &rc
|| op == QUEST && cpp == &rc
|| op == cp->n_op && (
/*
* don't parenthesize things which
* might be rearranged in spite of it.
*/
op == MUL
|| op == PLUS
|| op == AND
|| op == ER
|| op == OR
)
) {
/* do nothing */
} else {
/* add parentheses */
cp->n_ledge =
instok(LP, "(", cp->n_ledge->l_prev);
cp->n_redge =
instok(RP, ")", cp->n_redge);
cp->n_flags |= HASPAR;
}
}
/* move on to the next child */
if (cpp == &lc) {
cpp = &rc;
} else {
cpp = (struct node **) 0;
}
} while (cpp);
}
EOF
cat >cparen.h <<\EOF
/*
* Copyright (c) 1983 by
* Tektronix, Incorporated Beaverton, Oregon 97077
* All rights reserved.
*/
#ifdef RCSNAME
static char *RCSNAME = "$Header: /da/bradn/.bin/src/cparen/RCS/cparen.h,v 1.8 83/04/17 11:53:05 bradn Exp $";
#else
#define TRUE 1
#define FALSE 0
char *cmd; /* the name of this command (for error msgs) */
struct lexed { /* one unit of the lex'ed input list */
char *l_text; /* text associated with this token */
struct lexed *l_prev; /* previous token in the list */
struct lexed *l_next; /* next token in the list */
int l_val; /* this token's value (yylval'ish) */
};
struct lexed *nxttok(); /* used by lex to add a token to the list */
struct lexed *instok(); /* used by everybody to insert tokens */
struct node { /* a node of an expression subtree */
int n_op;
int n_flags;
#define HASL 1 /* 'has a left child' */
#define HASR 2 /* 'has a right child' */
#define BINARY (HASL | HASR)
#define HASPAR 4 /* 'has enclosing parens' */
#define hasl(np) ((np)->n_flags & HASL)
#define hasr(np) ((np)->n_flags & HASR)
#define haspar(np) ((np)->n_flags & HASPAR)
/*
* n_ledge and n_redge are the left and right
* edges of the sublist of tokens associated
* with this node.
* If haspar() is true, these pointers refer
* to the left and right paren tokens in the
* input token list.
*/
struct lexed *n_ledge;
struct lexed *n_redge;
};
struct node *bld(); /* used by yacc rules to return node info */
typedef union {
int intval;
struct lexed *lexval;
struct node *nodep;
} YYSTYPE;
YYSTYPE yylval;
#define NIL ((struct node *) 0)
struct node nonode;
#define NOP (&nonode) /* a no-op node pointer */
struct lexed firsttok; /* the left edge of the token list */
struct lexed lasttok; /* the right edge of the token list */
#endif
EOF
cat >hid.c <<\EOF
/*
* Copyright (c) 1983 by
* Tektronix, Incorporated Beaverton, Oregon 97077
* All rights reserved.
*/
static char *rcsid = "$Header: /da/bradn/.bin/src/cparen/RCS/hid.c,v 1.6 83/04/17 11:53:26 bradn Exp $";
#define RCSNAME cparen
#include "cparen.h"
#undef RCSNAME
EOF
tr @ '\134' >lex.l <<\EOF
%{
/*
* Copyright (c) 1983 by
* Tektronix, Incorporated Beaverton, Oregon 97077
* All rights reserved.
*/
# include "stdio.h"
# include "cparen.h"
# include "y.tab.h"
static char *rcsid = "$Header: /da/bradn/.bin/src/cparen/RCS/lex.l,v 1.9 83/04/17 11:53:32 bradn Exp $";
#define MAXTYPES 100
char *typnam[MAXTYPES] = { /* 'type' identifiers */
"char",
"double",
"float",
"int",
"long",
"short",
"unsigned",
"void",
0 /* command-line types go here */
};
char **typend; /* first free spot in typnam[] */
struct spec { /* special keywords */
char *s_name; /* keyword text */
int s_tok; /* token to return */
int s_val; /* value to return */
};
struct spec specnam[] = {
{"sizeof", SIZEOF, SIZEOF},
{"struct", STRUCT, ISSTRUCT},
{"union", STRUCT, ISUNION},
{"enum", ENUM, ENUM},
{"goto", KEYWORD, KEYWORD},
{"return", KEYWORD, KEYWORD},
{"if", KEYWORD, KEYWORD},
{"else", KEYWORD, KEYWORD},
{"while", KEYWORD, KEYWORD},
{"do", KEYWORD, KEYWORD},
{"for", KEYWORD, KEYWORD},
{"switch", KEYWORD, KEYWORD},
{"case", KEYWORD, KEYWORD},
{0,0,0}
};
int tok; /* a temp */
%}
%%
"<" {yylval.lexval = nxttok(LT); return(RELOP);}
"<=" {yylval.lexval = nxttok(LE); return(RELOP);}
">" {yylval.lexval = nxttok(GT); return(RELOP);}
">=" {yylval.lexval = nxttok(GE); return(RELOP);}
"," {yylval.lexval = nxttok(CM); return(CM);}
"/" {yylval.lexval = nxttok(DIV); return(DIVOP);}
"%" {yylval.lexval = nxttok(MOD); return(DIVOP);}
"+" {yylval.lexval = nxttok(PLUS); return(PLUS);}
"-" {yylval.lexval = nxttok(MINUS); return(MINUS);}
"<<" {yylval.lexval = nxttok(LS); return(SHIFTOP);}
">>" {yylval.lexval = nxttok(RS); return(SHIFTOP);}
"*" {yylval.lexval = nxttok(MUL); return(MUL);}
"==" {yylval.lexval = nxttok(EQ); return(EQUOP);}
"!=" {yylval.lexval = nxttok(NE); return(EQUOP);}
"&" {yylval.lexval = nxttok(AND); return(AND);}
"|" {yylval.lexval = nxttok(OR); return(OR);}
"^" {yylval.lexval = nxttok(ER); return(ER);}
"&&" {yylval.lexval = nxttok(ANDAND); return(ANDAND);}
"||" {yylval.lexval = nxttok(OROR); return(OROR);}
"=" {yylval.lexval = nxttok(ASSIGN); return(ASSIGN);}
"?" {yylval.lexval = nxttok(QUEST); return(QUEST);}
":" {yylval.lexval = nxttok(COLON); return(COLON);}
"=/" {yylval.lexval = nxttok(DIV); return(ASOP);}
"=%" {yylval.lexval = nxttok(MOD); return(ASOP);}
"=+" {yylval.lexval = nxttok(PLUS); return(ASOP);}
"=-" {yylval.lexval = nxttok(MINUS); return(ASOP);}
"=<<" {yylval.lexval = nxttok(LS); return(ASOP);}
"=>>" {yylval.lexval = nxttok(RS); return(ASOP);}
"=*" {yylval.lexval = nxttok(MUL); return(ASOP);}
"=&" {yylval.lexval = nxttok(AND); return(ASOP);}
"=|" {yylval.lexval = nxttok(OR); return(ASOP);}
"=^" {yylval.lexval = nxttok(ER); return(ASOP);}
"++" {yylval.lexval = nxttok(INCR); return(INCOP);}
"--" {yylval.lexval = nxttok(DECR); return(INCOP);}
"!" {yylval.lexval = nxttok(NOT); return(UNOP);}
"~" {yylval.lexval = nxttok(COMPL); return(UNOP);}
"(" {yylval.lexval = nxttok(LP); return(LP);}
")" {yylval.lexval = nxttok(RP); return(RP);}
"[" {yylval.lexval = nxttok(LB); return(LB);}
"]" {yylval.lexval = nxttok(RB); return(RB);}
"->" {yylval.lexval = nxttok(STREF); return(STROP);}
"." {yylval.lexval = nxttok(DOT); return(STROP);}
";" {yylval.lexval = nxttok(SM); return(SM);}
"{" {/* ignore curly-braces */ (void) nxttok(LC);}
"}" {/* ignore curly-braces */ (void) nxttok(RC);}
0x[0-9a-zA-Z]+[Ll]? {/* hex constant */
yylval.lexval = nxttok(NAME); return(NAME);
}
[0-9]+[Ll]? {/* decimal or octal constant */
yylval.lexval = nxttok(NAME); return(NAME);
}
[0-9]+[Ee]([+-][0-9])?[0-9]* |
@.[0-9]+([Ee]([+-][0-9])?[0-9]*)? |
[0-9]+ at .[0-9]*([Ee]([+-][0-9])?[0-9]*)? {/* floating constant */
yylval.lexval = nxttok(NAME); return(NAME);
}
@'([^'@n]|(@@@'))+@' {/* char constant */
yylval.lexval = nxttok(NAME); return(NAME);
}
@"([^"@n]|(@@@"))*@" {/* string constant */
yylval.lexval = nxttok(NAME); return(NAME);
}
[a-zA-Z_][a-zA-Z0-9_]* {/* identifier, type, or keyword */
yylval.lexval = nxttok(NAME);
/* take care of magic keywords */
if ((tok =
specof(yytext, &yylval.lexval->l_val))) {
return(tok);
}
/* take care of types and identifiers */
if (istype(yytext)) {
return(TYPE);
} else {
return(NAME);
}
}
[ @t at n]+ {/* whitespace */ (void) nxttok(FLUFF);}
@/@*([^@*]|(@*[^@/]))*@*?@*@/ {/* comment */ (void) nxttok(FLUFF);}
. {fprintf(stderr, "%s: unknown character `%c'@n", cmd, yytext[0]);}
%%
static
initype() /* init the type list */
{
if (typend) {
return;
}
for (typend = &typnam[0]; *typend; typend++)
;
}
newtype(s) /* insert this string into the list of type strings */
char *s;
{
char **t;
initype();
for (t = &typnam[0]; t < typend && strcmp(s, *t) != 0; t++)
;
if (t <typend) {
/* this type already exists - no need to insert it again */
return;
}
if (typend >= &typnam[MAXTYPES]) {
fprintf(stderr, "%s: out of memory at n", cmd);
exit(1);
}
*typend++ = s;
}
static int
istype(s) /* returns 'this string is a TYPE name' */
char *s;
{
char **t;
initype();
for (t = &typnam[0]; t < typend && strcmp(s, *t) != 0; t++)
;
return(t < typend);
}
static int /* token to return (or zero, if not a special keyword) */
specof(t, vp)
char *t; /* possible keyword text */
int *vp; /* where to put value */
{
struct spec *sp;
for (sp = &specnam[0]; sp->s_name && strcmp(t, sp->s_name) != 0;
sp++)
;
if (sp->s_name) {
*vp = sp->s_val;
return(sp->s_tok);
}
return(0);
}
struct lexed *
nxttok(val) /* insert the val at the end of the list */
int val;
{
/* curtok: current token in the input list */
static struct lexed *curtok = &firsttok;
curtok = instok(val, yytext, curtok);
return(curtok);
}
struct lexed *
instok(val, text, after) /* insert token into input list */
int val; /* token value (yylval'ish) */
char *text; /* associated text (to be copied) */
struct lexed *after; /* node to insert after */
{
char *malloc();
struct lexed *node;
if (!(node = (struct lexed *) malloc(sizeof(struct lexed)))) {
fprintf(stderr, "%s: out of memory. at n", cmd);
exit(1);
}
if (!(node->l_text = malloc(strlen(text) + 1))) {
fprintf(stderr, "%s: out of memory. at n", cmd);
exit(1);
}
(void) strcpy(node->l_text, text);
node->l_val = val;
/* insert into the list after the node 'after' */
after->l_next->l_prev = node;
node->l_next = after->l_next;
node->l_prev = after;
after->l_next = node;
return(node);
}
EOF
cat >parse.y <<\EOF
/*
* Copyright (c) 1983 by
* Tektronix, Incorporated Beaverton, Oregon 97077
* All rights reserved.
*/
%term MUL 1 /* start of assignable ops (e.g. + vs +=) */
%term DIV 2
%term MOD 3
%term PLUS 4
%term MINUS 5
%term LS 6 /* left-shift << */
%term RS 7 /* right-shift >> */
%term AND 8
%term OR 9
%term ER 10 /* exclusive-or ^ */
%term ASSIGN 11 /* end of assignable ops (e.g. + vs +=) */
%term MULASG 12 /* assign version of assignable ops */
%term DIVASG 13
%term MODASG 14
%term PLUSASG 15
%term MINUSASG 16
%term LSASG 17
%term RSASG 18
%term ANDASG 19
%term ORASG 20
%term ERASG 21 /* end of assign version of ops */
%term LT 22 /* less-than < */
%term LE 23
%term GT 24
%term GE 25
%term EQ 26
%term NE 27
%term ANDAND 28
%term OROR 29
%term CM 30 /* comma , */
%term COMOP 31 /* comma operator , */
%term QUEST 32 /* ? */
%term COLON 33
%term UMINUS 34 /* unary minus - */
%term INCR 35 /* (post- or pre-) increment ++ */
%term DECR 36 /* (post- or pre-) decrement -- */
%term INDR 37 /* indirect * */
%term ADDR 38 /* address-of & */
%term NOT 39
%term COMPL 40 /* complement ~ */
%term SIZEOF 41
%term CAST 42
%term BRACK 43 /* brackets [] */
%term ISSTRUCT 44
%term ISUNION 45
%term ENUM 46
%term STREF 47 /* structure reference (-> or .) */
%term DOT 48 /* subfield . */
%term CALL 49
%term LIT 51 /* literal. A dummy operator */
%term KEYWORD 52 /* a statement keyword */
%term SM 53 /* semi-colon ; */
%term LC 54 /* left curly-brace { */
%term RC 55 /* right curly-brace } */
%term FLUFF 56 /* syntactic fluff: comments and whitespace */
%left CM
%right ASOP ASSIGN
%right QUEST COLON
%left OROR
%left ANDAND
%left OR
%left ER
%left AND
%left EQUOP
%left RELOP
%left SHIFTOP
%left PLUS MINUS
%left MUL DIVOP
%right UNOP
%right INCOP SIZEOF
%left LB LP STROP
%{
#include <stdio.h>
#include "cparen.h"
static char *rcsid = "$Header: /da/bradn/.bin/src/cparen/RCS/parse.y,v 1.12 83/04/17 11:53:40 bradn Exp $";
struct node *bld();
%}
%start unit_list
%type <nodep> e term elist cast_type null_decl funct_idn atype struct_dcl
enum_dcl unit unit_list
%token <lexval> RELOP CM DIVOP PLUS MINUS SHIFTOP MUL EQUOP AND OR ER
ANDAND OROR ASSIGN QUEST COLON ASOP INCOP UNOP SIZEOF
LP RP LB RB STROP STRUCT ENUM NAME TYPE LT LE GT GE DIV
MOD LS RS EQ NE INCR DECR NOT COMPL STREF DOT ISSTRUCT
ISUNION COMOP INDR ADDR CAST BRACK CALL UMINUS
SM LIT KEYWORD
%%
unit_list:
unit
{$$ = NOP;}
| unit_list unit
{$$ = NOP;}
;
unit: COLON
{$$ = NOP;}
| SM
{$$ = NOP;}
| e
{$$ = $1;}
| KEYWORD
{$$ = NOP;}
;
e: e RELOP e
{bop: consider($2->l_val, $1, $3);
$$ = bld($2->l_val, BINARY, $1->n_ledge, $3->n_redge);
}
| e CM e
{ $2->l_val = COMOP; goto bop; }
| e DIVOP e
{ goto bop; }
| e PLUS e
{ goto bop; }
| e MINUS e
{ goto bop; }
| e SHIFTOP e
{ goto bop; }
| e MUL e
{ goto bop; }
| e EQUOP e
{ goto bop; }
| e AND e
{ goto bop; }
| e OR e
{ goto bop; }
| e ER e
{ goto bop; }
| e ANDAND e
{ goto bop; }
| e OROR e
{ goto bop; }
| e MUL ASSIGN e
{ abop:
$2->l_val = asgof($2->l_val);
consider($2->l_val, $1, $4);
$$ = bld($2->l_val, BINARY, $1->n_ledge, $4->n_redge);
}
| e DIVOP ASSIGN e
{ goto abop; }
| e PLUS ASSIGN e
{ goto abop; }
| e MINUS ASSIGN e
{ goto abop; }
| e SHIFTOP ASSIGN e
{ goto abop; }
| e AND ASSIGN e
{ goto abop; }
| e OR ASSIGN e
{ goto abop; }
| e ER ASSIGN e
{ goto abop; }
| e QUEST e COLON e
{ consider($2->l_val, $1, NIL);
consider($4->l_val, $3, $5);
$$ = bld($2->l_val, BINARY, $1->n_ledge, $5->n_redge);
}
| e ASOP e
{
$2->l_val = asgof($2->l_val);
consider($2->l_val, $1, $3);
$$ = bld($2->l_val, BINARY, $1->n_ledge, $3->n_redge);
}
| e ASSIGN e
{ goto bop; }
| term
;
term: term INCOP
{ consider($2->l_val, $1, NIL);
$$ = bld($2->l_val, HASL, $1->n_ledge, $2);
}
| INCOP term
{ unop: consider($1->l_val, NIL, $2);
$$ = bld($1->l_val, HASR, $1, $2->n_redge);
}
| MUL term
{$1->l_val = INDR; goto unop;}
| AND term
{$1->l_val = ADDR; goto unop;}
| MINUS term
{$1->l_val = UMINUS; goto unop;}
| UNOP term
{ goto unop; }
| SIZEOF LP cast_type RP %prec SIZEOF
{
$$ = bld($1->l_val, HASR, $1, $4);
}
| SIZEOF term
{ goto unop; }
| LP cast_type RP term %prec INCOP
{
consider(CAST, NOP, $4);
$$ = bld(CAST, BINARY, $1, $4->n_redge);
}
| term LB e RB
{ consider(BRACK, $1, $3);
$$ = bld(BRACK, BINARY, $1->n_ledge, $4);
}
| term STROP NAME
{ consider($2->l_val, $1, NOP);
$$ = bld($2->l_val, BINARY, $1->n_ledge, $3);
}
| funct_idn RP
{
$$ = bld(CALL, HASL, $1->n_ledge, $2);
}
| funct_idn elist RP
{
$$ = bld(CALL, BINARY, $1->n_ledge, $3);
}
| NAME /* includes ICON, FCON, and STRING */
{ $$ = bld(LIT, 0, $1, $1); }
| LP unit_list RP
{ $$ = bld(LIT, HASPAR, $1, $3);}
;
elist: e %prec CM
{$$ = $1;}
| elist CM e
{
$$ = bld(LIT, 0, $1->n_ledge, $3->n_redge);
}
;
cast_type: atype null_decl
{
$$ = bld(LIT, 0, $1->n_ledge,
$2->n_redge ? $2->n_redge : $1->n_redge);
}
;
null_decl: /* empty */
{ $$ = NOP; }
| LP null_decl RP LP RP
{$$ = bld(LIT, 0, $1, $5);}
| MUL null_decl
{$$ = bld(LIT, 0, $1, $2->n_redge ? $2->n_redge : $1);}
| null_decl LB RB
{$$ = bld(LIT, 0, $1->n_ledge ? $1->n_ledge : $2, $3);}
| null_decl LB e RB
{
$$ = bld(LIT, 0, $1->n_ledge ? $1->n_ledge : $2, $4);
}
| LP null_decl RP
{$$ = bld(LIT, 0 , $1, $3);}
;
funct_idn: NAME LP
{ $$ = bld(LIT, 0, $1, $2); }
| term LP
{ $$ = bld(LIT, 0, $1->n_ledge, $2); }
;
atype: TYPE
{$$ = bld(LIT, 0, $1, $1);}
| TYPE TYPE
{$$ = bld(LIT, 0, $1, $2);}
| TYPE TYPE TYPE
{$$ = bld(LIT, 0, $1, $3);}
| struct_dcl
{$$ = $1;}
| enum_dcl
{$$ = $1;}
;
struct_dcl: STRUCT NAME
{$$ = bld(LIT, 0, $1, $2);}
;
enum_dcl: ENUM NAME
{$$ = bld(LIT, 0, $1, $2);}
;
%%
yyerror(s)
char *s;
{
fprintf(stderr,"%s: %s\n", cmd, s);
}
struct node * /* the allocated node */
bld(op, flags, left, right)
int op; /* the operation to be performed */
int flags; /* the flags to set */
struct lexed *left; /* points to the left token */
struct lexed *right; /* points to the right token */
{
struct node *res;
if (!(res = (struct node *) malloc(sizeof(struct node)))) {
fprintf(stderr,"%s: out of memory\n", cmd);
exit(1);
}
res->n_op = op;
res->n_flags = flags;
res->n_ledge = left;
res->n_redge = right;
return(res);
}
static int
asgof(v) /* convert the given op into the = form e.g. + to += */
int v;
{
if (v < ASSIGN) {
v += ASSIGN;
}
return(v);
}
EOF
More information about the Comp.sources.unix
mailing list