summaryrefslogtreecommitdiff
path: root/bcc/express.c
diff options
context:
space:
mode:
Diffstat (limited to 'bcc/express.c')
-rw-r--r--bcc/express.c466
1 files changed, 466 insertions, 0 deletions
diff --git a/bcc/express.c b/bcc/express.c
new file mode 100644
index 0000000..e6ee64c
--- /dev/null
+++ b/bcc/express.c
@@ -0,0 +1,466 @@
+/* express.c - expression parsing routines for bcc */
+
+/* Copyright (C) 1992 Bruce Evans */
+
+#include "const.h"
+#include "types.h"
+#include "gencode.h"
+#include "parse.h"
+#include "reg.h"
+#include "sc.h"
+#include "scan.h"
+#include "table.h" /* just for charptr for string constant */
+#include "type.h"
+
+PRIVATE unsigned insizeof; /* nest level for getsizeof */
+ /* used to avoid aborting undefined idents */
+ /* to 0 when they appear in a cpp expression */
+ /* under sizeof */
+
+/* names of expression functions are related to the 15 precedence levels */
+/* on p49 of K & R */
+
+FORWARD struct nodestruct *cast_exp P((void));
+FORWARD struct nodestruct *exp2 P((void));
+FORWARD struct nodestruct *exp3to12 P((fastin_pt lprecedence));
+FORWARD struct nodestruct *listargs P((void));
+FORWARD struct nodestruct *postfix_exp P((bool_pt seenlp));
+FORWARD struct nodestruct *primary_exp P((void));
+FORWARD struct nodestruct *unary_exp P((void));
+
+PRIVATE struct nodestruct *cast_exp()
+{
+ struct nodestruct *nodeptr;
+ scalar_t scalar;
+ struct typestruct *vartype;
+
+ if (sym != LPAREN)
+ return unary_exp();
+ nextsym();
+ if ((vartype = typename()) == NULL)
+ return postfix_exp(TRUE);
+ rparen();
+ scalar = (nodeptr = cast_exp())->nodetype->scalar;
+ if (vartype->scalar & INT && scalar & (CHAR | SHORT | INT)
+ && !((vartype->scalar ^ scalar) & UNSIGNED))
+ {
+ nodeptr->flags &= ~LVALUE;
+ return nodeptr; /* skip casts that are default promotions */
+ }
+ return castnode(vartype, nodeptr);
+}
+
+PUBLIC struct nodestruct *assignment_exp()
+{
+ struct nodestruct *lhs;
+ op_pt op;
+
+ lhs = exp2();
+ if (sym >= ASSIGNOP && sym <= SUBABOP) /* assign-op syms in order! */
+ {
+ op = sym;
+ nextsym();
+ lhs = node(op, lhs, assignment_exp());
+ }
+ return lhs;
+}
+
+PUBLIC struct nodestruct *expression()
+{
+ struct nodestruct *lhs;
+
+ lhs = assignment_exp();
+ while (sym == COMMA)
+ {
+ nextsym();
+ lhs = node(COMMAOP, lhs, assignment_exp());
+ }
+ return lhs;
+}
+
+PRIVATE struct nodestruct *exp2()
+{
+ struct nodestruct *lhs;
+ struct nodestruct *rhs;
+
+ lhs = exp3to12(0);
+ if (sym == CONDOP)
+ {
+ nextsym();
+ rhs = expression();
+ colon();
+ lhs = node(CONDOP, lhs, node(COLONOP, rhs, exp2()));
+ }
+ return lhs;
+}
+
+PRIVATE struct nodestruct *exp3to12(lprecedence)
+fastin_pt lprecedence;
+{
+ struct nodestruct *lhs;
+ op_pt op;
+ fastin_t rprecedence;
+
+ lhs = cast_exp();
+ while (TRUE)
+ {
+ rprecedence = 0;
+ switch (sym)
+ {
+ case LOGOROP:
+ if ((fastin_t) lprecedence <= 1)
+ rprecedence = 2;
+ break;
+ case LOGANDOP:
+ if ((fastin_t) lprecedence <= 3)
+ rprecedence = 4;
+ break;
+ case OROP:
+ if ((fastin_t) lprecedence <= 5)
+ rprecedence = 6;
+ break;
+ case EOROP:
+ if ((fastin_t) lprecedence <= 7)
+ rprecedence = 8;
+ break;
+ case AMPERSAND:
+ if ((fastin_t) lprecedence <= 9)
+ {
+ sym = ANDOP;
+ rprecedence = 10;
+ }
+ break;
+ case EQOP:
+ case NEOP:
+ if ((fastin_t) lprecedence <= 11)
+ rprecedence = 12;
+ break;
+ case GEOP:
+ case GTOP:
+ case LEOP:
+ case LTOP:
+ if ((fastin_t) lprecedence <= 13)
+ rprecedence = 14;
+ break;
+ case SLOP:
+ case SROP:
+ if ((fastin_t) lprecedence <= 15)
+ rprecedence = 16;
+ break;
+ case HYPHEN:
+ if ((fastin_t) lprecedence <= 17)
+ {
+ sym = SUBOP;
+ rprecedence = 18;
+ }
+ break;
+ case ADDOP:
+ if ((fastin_t) lprecedence <= 17)
+ rprecedence = 18;
+ break;
+ case STAR:
+ if ((fastin_t) lprecedence <= 19)
+ {
+ sym = MULOP;
+ rprecedence = 20;
+ }
+ break;
+ case DIVOP:
+ case MODOP:
+ if ((fastin_t) lprecedence <= 19)
+ rprecedence = 20;
+ break;
+ }
+ if (rprecedence == 0)
+ break;
+ op = sym;
+ nextsym();
+ lhs = node(op, lhs, exp3to12(rprecedence));
+ }
+ return lhs;
+}
+
+PRIVATE struct nodestruct *listargs()
+{
+ struct nodestruct *parent;
+ struct nodestruct *nextright;
+
+ if (sym == RPAREN)
+ {
+ nextsym();
+ return NULLNODE;
+ }
+ parent = node(arg1op, assignment_exp(), NULLNODE);
+ nextright = parent;
+ while (sym == COMMA)
+ {
+ nextsym();
+ nextright = nextright->right
+ = node(LISTOP, assignment_exp(), NULLNODE);
+ }
+ rparen();
+ return parent;
+}
+
+PRIVATE struct nodestruct *postfix_exp(seenlp)
+bool_pt seenlp;
+{
+ struct nodestruct *nodeptr;
+ struct symstruct *symptr;
+
+ if (seenlp)
+ {
+ nodeptr = expression();
+ rparen();
+ }
+ else
+ nodeptr = primary_exp();
+ while (TRUE)
+ {
+ switch (sym)
+ {
+ case DECSYM:
+ nextsym();
+ nodeptr = node(POSTDECOP, nodeptr, NULLNODE);
+ continue;
+ case INCSYM:
+ nextsym();
+ nodeptr = node(POSTINCOP, nodeptr, NULLNODE);
+ continue;
+ case LBRACKET:
+ nextsym();
+ nodeptr = node(INDIRECTOP, node(ADDOP, nodeptr, expression()),
+ NULLNODE);
+ rbracket();
+ continue;
+ case LPAREN:
+ nextsym();
+ nodeptr = node(FUNCOP, nodeptr, listargs());
+ {
+ register struct nodestruct *np;
+
+ for (np = nodeptr->right; np != NULL; np = np->right)
+ {
+ if (np->nodetype->scalar & RSCALAR)
+ {
+ np = nodeptr->left.nodeptr;
+ if (np->tag != LEAF)
+ printf_fp = TRUE;
+ else
+ {
+ unsigned len;
+ register char *name;
+
+ name = np->left.symptr->name.namep;
+ if ((len = strlen(name)) >= 6
+ && strcmp(name + len - 6, "printf") == 0)
+ printf_fp = TRUE;
+ }
+ break;
+ }
+ }
+ for (np = nodeptr->right; np != NULL; np = np->right)
+ {
+ if (np->nodetype->constructor & POINTER
+ && np->nodetype->nexttype->scalar & RSCALAR)
+ {
+ np = nodeptr->left.nodeptr;
+ if (np->tag != LEAF)
+ scanf_fp = TRUE;
+ else
+ {
+ unsigned len;
+ register char *name;
+
+ name = np->left.symptr->name.namep;
+ if ((len = strlen(name)) >= 5
+ && strcmp(name + len - 5, "scanf") == 0)
+ scanf_fp = TRUE;
+ }
+ break;
+ }
+ }
+ }
+ continue;
+ case STRUCPTROP:
+ nodeptr = node(INDIRECTOP, nodeptr, NULLNODE);
+ case STRUCELTOP:
+ nextsym();
+ gs2name[0] = nodeptr->nodetype->structkey[0];
+ gs2name[1] = nodeptr->nodetype->structkey[1];
+ if ((gsymptr = findlorg(gs2name)) == NULL)
+ {
+ error("undefined structure element");
+ gsymptr = addglb(gs2name, itype);
+ }
+ symptr = exprsym(gsymptr);
+ nextsym();
+ nodeptr = node(STRUCELTOP, nodeptr, leafnode(symptr));
+ continue;
+ default:
+ return nodeptr;
+ }
+ }
+}
+
+PRIVATE struct nodestruct *primary_exp()
+{
+ bool_t isdefined;
+ struct nodestruct *nodeptr;
+ uoffset_t stringlen;
+ struct symstruct *symptr;
+ struct symstruct *symptr1;
+ bool_t waslparen;
+
+ switch (sym)
+ {
+ case IDENT:
+ if (incppexpr && !insizeof)
+ {
+cpp_ident:
+ nextsym();
+ return leafnode(constsym((value_t) 0));
+ }
+ if ((symptr = gsymptr) != NULL)
+ nextsym();
+ else
+ {
+ symptr = addglb(gsname, fitype);
+ nextsym();
+ if (sym != LPAREN)
+ {
+ error2error(symptr->name.namea, " undeclared");
+ symptr->indcount = 1;
+ symptr->type = itype;
+ }
+ }
+ symptr1 = exprsym(symptr);
+ if (symptr->flags & STATIC && symptr->level != GLBLEVEL)
+ {
+ symptr1->flags |= LABELLED;
+ symptr1->offset.offi = 0;
+ symptr1->name.label = symptr->offset.offlabel;
+ }
+ nodeptr = leafnode(symptr1);
+ if (!(nodeptr->nodetype->constructor & (ARRAY | FUNCTION | VOID)))
+ nodeptr->flags = LVALUE;
+ return nodeptr;
+ case TYPEDEFNAME:
+ if (incppexpr && !insizeof)
+ goto cpp_ident; /* else fall through */
+ default:
+ error("bad expression");
+ constant.value.v = 0;
+ constant.type = itype;
+ case CHARCONST:
+ case INTCONST: /* this includes enumeration-constants */
+ symptr = constsym(constant.value.v);
+ symptr->type = constant.type;
+ if (!(ltype->scalar & LONG))
+ {
+ if (symptr->type == ltype)
+ symptr->type = itype;
+ else if (symptr->type == ultype)
+ symptr->type = uitype;
+ }
+ nextsym();
+ return leafnode(symptr);
+ case DEFINEDSYM:
+ waslparen = isdefined = FALSE;
+ if (!blanksident())
+ {
+ nextsym();
+ if (sym != LPAREN)
+ lparen();
+ else
+ waslparen = TRUE;
+ }
+ if (waslparen && !blanksident())
+ needvarname();
+ else
+ {
+ if ((symptr = findlorg(gsname)) != NULL &&
+ symptr->flags == DEFINITION)
+ isdefined = TRUE;
+ nextsym();
+ }
+ if (waslparen)
+ rparen();
+ return leafnode(constsym((value_t) isdefined));
+ case FLOATCONST:
+ symptr = constsym((value_t) 0);
+ symptr->type = constant.type;
+ symptr->offset.offd = qmalloc(sizeof *symptr->offset.offd);
+ *symptr->offset.offd = constant.value.d;
+ nextsym();
+ return leafnode(symptr);
+ case LPAREN:
+ nextsym();
+ nodeptr = expression();
+ rparen();
+ return nodeptr;
+ case STRINGCONST:
+ symptr = constsym((value_t) 0);
+ symptr->storage = GLOBAL;
+ symptr->flags = LABELLED | STRING;
+ /* string length before defstr() or prefix() updates charptr */
+ stringlen = charptr - constant.value.s + 1;
+ symptr->name.label = defstr(constant.value.s, charptr, FALSE);
+ symptr->type = prefix(ARRAY, stringlen, ctype);
+ nextsym();
+ return leafnode(symptr);
+ }
+}
+
+PRIVATE struct nodestruct *unary_exp()
+{
+ value_t size;
+ struct typestruct *vartype;
+
+ switch (sym)
+ {
+ case ADDOP:
+ nextsym();
+ return cast_exp();
+ case AMPERSAND:
+ nextsym();
+ return node(ADDRESSOP, cast_exp(), NULLNODE); /* maybe unary_exp */
+ case DECSYM:
+ nextsym();
+ return node(PREDECOP, unary_exp(), NULLNODE);
+ case HYPHEN:
+ nextsym();
+ return node(NEGOP, cast_exp(), NULLNODE);
+ case INCSYM:
+ nextsym();
+ return node(PREINCOP, unary_exp(), NULLNODE);
+ case LOGNOTOP:
+ nextsym();
+ return node(LOGNOTOP, cast_exp(), NULLNODE);
+ case NOTOP:
+ nextsym();
+ return node(NOTOP, cast_exp(), NULLNODE);
+ case SIZEOFSYM:
+ nextsym();
+ ++insizeof;
+ if (sym != LPAREN)
+ size = unary_exp()->nodetype->typesize;
+ else
+ {
+ nextsym();
+ if ((vartype = typename()) != NULL)
+ {
+ rparen();
+ size = vartype->typesize;
+ }
+ else
+ size = postfix_exp(TRUE)->nodetype->typesize;
+ }
+ --insizeof;
+ return leafnode(constsym(size));
+ case STAR:
+ nextsym();
+ return node(INDIRECTOP, cast_exp(), NULLNODE); /* maybe unary_exp */
+ }
+ return postfix_exp(FALSE);
+}