home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include "c.h"
- #include "expr.h"
- #include "gen.h"
- #include "cglbdec.h"
-
- /*
- * 68000 C compiler
- *
- * Copyright 1984, 1985, 1986 Matthew Brandt.
- * all commercial rights reserved.
- *
- * This compiler is intended as an instructive tool for personal use. Any
- * use for profit without the written consent of the author is prohibited.
- *
- * This compiler may be distributed freely for non-commercial use as long
- * as this notice stays intact. Please forward any enhancements or questions
- * to:
- *
- * Matthew Brandt
- * Box 920337
- * Norcross, Ga 30092
- */
-
- /*
- * the statement module handles all of the possible c statements
- * and builds a parse tree of the statements.
- *
- * each routine returns a pointer to a statement parse node which
- * reflects the statement just parsed.
- */
-
- struct snode *statement(); /* forward declaration */
-
- struct snode *whilestmt()
- /*
- * whilestmt parses the c while statement.
- */
- { struct snode *snp;
- snp = xalloc(sizeof(struct snode));
- snp->stype = st_while;
- getsym();
- if( lastst != openpa )
- error(ERR_EXPREXPECT);
- else {
- getsym();
- if( expression(&(snp->exp)) == 0 )
- error(ERR_EXPREXPECT);
- needpunc( closepa );
- snp->s1 = statement();
- }
- return snp;
- }
-
- struct snode *dostmt()
- /*
- * dostmt parses the c do-while construct.
- */
- { struct snode *snp;
- snp = xalloc(sizeof(struct snode));
- snp->stype = st_do;
- getsym();
- snp->s1 = statement();
- if( lastst != kw_while )
- error(ERR_WHILEXPECT);
- else {
- getsym();
- if( lastst != openpa )
- error(ERR_EXPREXPECT);
- else {
- getsym();
- if( expression(&(snp->exp)) == 0 )
- error(ERR_EXPREXPECT);
- needpunc(closepa);
- }
- if( lastst != end )
- needpunc( semicolon );
- }
- return snp;
- }
-
- struct snode *forstmt()
- { struct snode *snp;
- snp = xalloc(sizeof(struct snode));
- getsym();
- needpunc(openpa);
- if( expression(&(snp->label)) == 0 )
- snp->label = 0;
- needpunc(semicolon);
- snp->stype = st_for;
- if( expression(&(snp->exp)) == 0 )
- snp->exp = 0;
- needpunc(semicolon);
- if( expression(&(snp->s2)) == 0 )
- snp->s2 = 0;
- needpunc(closepa);
- snp->s1 = statement();
- return snp;
- }
-
- struct snode *ifstmt()
- /*
- * ifstmt parses the c if statement and an else clause if
- * one is present.
- */
- { struct snode *snp;
- snp = xalloc(sizeof(struct snode));
- snp->stype = st_if;
- getsym();
- if( lastst != openpa )
- error(ERR_EXPREXPECT);
- else {
- getsym();
- if( expression(&(snp->exp)) == 0 )
- error(ERR_EXPREXPECT);
- needpunc( closepa );
- snp->s1 = statement();
- if( lastst == kw_else ) {
- getsym();
- snp->s2 = statement();
- }
- else
- snp->s2 = 0;
- }
- return snp;
- }
-
- struct snode *casestmt()
- /*
- * cases are returned as seperate statements. for normal
- * cases label is the case value and s2 is zero. for the
- * default case s2 is nonzero.
- */
- { struct snode *snp;
- struct snode *head, *tail;
- snp = xalloc(sizeof(struct snode));
- if( lastst == kw_case ) {
- getsym();
- snp->s2 = 0;
- snp->stype = st_case;
- snp->label = intexpr();
- }
- else if( lastst == kw_default) {
- getsym();
- snp->s2 = 1;
- }
- else {
- error(ERR_NOCASE);
- return 0;
- }
- needpunc(colon);
- head = 0;
- while( lastst != end &&
- lastst != kw_case &&
- lastst != kw_default ) {
- if( head == 0 )
- head = tail = statement();
- else {
- tail->next = statement();
- if( tail->next != 0 )
- tail = tail->next;
- }
- tail->next = 0;
- }
- snp->s1 = head;
- return snp;
- }
-
- int checkcases(head)
- /*
- * checkcases will check to see if any duplicate cases
- * exist in the case list pointed to by head.
- */
- struct snode *head;
- {
- struct snode *top, *cur;
- cur = top = head;
- while( top != 0 )
- {
- cur = top->next;
- while( cur != 0 )
- {
- if( (!(cur->s1 || cur->s2) && cur->label == top->label)
- || (cur->s2 && top->s2) )
- {
- printf(" duplicate case label %d\n",cur->label);
- return 1;
- }
- cur = cur->next;
- }
- top = top->next;
- }
- return 0;
- }
-
- struct snode *switchstmt()
- { struct snode *snp;
- struct snode *head, *tail;
- snp = xalloc(sizeof(struct snode));
- snp->stype = st_switch;
- getsym();
- needpunc(openpa);
- if( expression(&(snp->exp)) == 0 )
- error(ERR_EXPREXPECT);
- needpunc(closepa);
- needpunc(begin);
- head = 0;
- while( lastst != end ) {
- if( head == 0 )
- head = tail = casestmt();
- else {
- tail->next = casestmt();
- if( tail->next != 0 )
- tail = tail->next;
- }
- tail->next = 0;
- }
- snp->s1 = head;
- getsym();
- if( checkcases(head) )
- error(ERR_DUPCASE);
- return snp;
- }
-
- struct snode *retstmt()
- { struct snode *snp;
- snp = xalloc(sizeof(struct snode));
- snp->stype = st_return;
- getsym();
- expression(&(snp->exp));
- if( lastst != end )
- needpunc( semicolon );
- return snp;
- }
-
- struct snode *breakstmt()
- { struct snode *snp;
- snp = xalloc(sizeof(struct snode));
- snp->stype = st_break;
- getsym();
- if( lastst != end )
- needpunc( semicolon );
- return snp;
- }
-
- struct snode *contstmt()
- { struct snode *snp;
- snp = xalloc(sizeof(struct snode));
- snp->stype = st_continue;
- getsym();
- if( lastst != end )
- needpunc( semicolon );
- return snp;
- }
-
- struct snode *exprstmt()
- /*
- * exprstmt is called whenever a statement does not begin
- * with a keyword. the statement should be an expression.
- */
- { struct snode *snp;
- snp = xalloc(sizeof(struct snode));
- snp->stype = st_expr;
- if( expression(&(snp->exp)) == 0 ) {
- error(ERR_EXPREXPECT);
- getsym();
- }
- if( lastst != end )
- needpunc( semicolon );
- return snp;
- }
-
- struct snode *compound()
- /*
- * compound processes a block of statements and forms a linked
- * list of the statements within the block.
- *
- * compound expects the input pointer to already be past the
- * begin symbol of the block.
- */
- { struct snode *head, *tail;
- head = 0;
- while( lastst != end ) {
- if( head == 0 )
- head = tail = statement();
- else {
- tail->next = statement();
- if( tail->next != 0 )
- tail = tail->next;
- }
- }
- getsym();
- return head;
- }
-
- struct snode *labelstmt()
- /*
- * labelstmt processes a label that appears before a
- * statement as a seperate statement.
- */
- { struct snode *snp;
- SYM *sp;
- snp = xalloc(sizeof(struct snode));
- snp->stype = st_label;
- if( (sp = search(lastid,lsyms.head)) == 0 ) {
- sp = xalloc(sizeof(SYM));
- sp->name = litlate(lastid);
- sp->storage_class = sc_label;
- sp->tp = 0;
- sp->value.i = nextlabel++;
- insert(sp,&lsyms);
- }
- else {
- if( sp->storage_class != sc_ulabel )
- error(ERR_LABEL);
- else
- sp->storage_class = sc_label;
- }
- getsym(); /* get past id */
- needpunc(colon);
- if( sp->storage_class == sc_label ) {
- snp->label = sp->value.i;
- snp->next = 0;
- return snp;
- }
- return 0;
- }
-
- struct snode *gotostmt()
- /*
- * gotostmt processes the goto statement and puts undefined
- * labels into the symbol table.
- */
- { struct snode *snp;
- SYM *sp;
- getsym();
- if( lastst != id ) {
- error(ERR_IDEXPECT);
- return 0;
- }
- snp = xalloc(sizeof(struct snode));
- if( (sp = search(lastid,lsyms.head)) == 0 ) {
- sp = xalloc(sizeof(SYM));
- sp->name = litlate(lastid);
- sp->value.i = nextlabel++;
- sp->storage_class = sc_ulabel;
- sp->tp = 0;
- insert(sp,&lsyms);
- }
- getsym(); /* get past label name */
- if( lastst != end )
- needpunc( semicolon );
- if( sp->storage_class != sc_label && sp->storage_class != sc_ulabel)
- error( ERR_LABEL );
- else {
- snp->stype = st_goto;
- snp->label = sp->value.i;
- snp->next = 0;
- return snp;
- }
- return 0;
- }
-
- struct snode *statement()
- /*
- * statement figures out which of the statement processors
- * should be called and transfers control to the proper
- * routine.
- */
- { struct snode *snp;
- switch( lastst ) {
- case semicolon:
- getsym();
- snp = 0;
- break;
- case begin:
- getsym();
- snp = compound();
- return snp;
- case kw_if:
- snp = ifstmt();
- break;
- case kw_while:
- snp = whilestmt();
- break;
- case kw_for:
- snp = forstmt();
- break;
- case kw_return:
- snp = retstmt();
- break;
- case kw_break:
- snp = breakstmt();
- break;
- case kw_goto:
- snp = gotostmt();
- break;
- case kw_continue:
- snp = contstmt();
- break;
- case kw_do:
- snp = dostmt();
- break;
- case kw_switch:
- snp = switchstmt();
- break;
- case id:
- while( isspace(lastch) )
- getch();
- if( lastch == ':' )
- return labelstmt();
- /* else fall through to process expression */
- default:
- snp = exprstmt();
- break;
- }
- if( snp != 0 )
- snp->next = 0;
- return snp;
- }
-