home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
vol_300
/
355_02
/
slk2.exe
/
SPP
/
PAR.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-06-09
|
11KB
|
613 lines
/*
New Sherlock preprocessor -- Parser Part I (statements)
source: par.c
started: October 22, 1985
version:
July 15, 1988
February 16, 1989 error message start with upper case.
PUBLIC DOMAIN SOFTWARE
Sherlock, including the SPP, SDEL and SDIF programs, was placed in
the public domain on June 15, 1991, by its author,
Edward K. Ream
166 North Prospect Ave.
Madison, WI 53705.
(608) 257-0802
Sherlock may be used for any commercial or non-commercial purpose.
DISCLAIMER OF WARRANTIES
Edward K. Ream (Ream) specifically disclaims all warranties,
expressed or implied, with respect to this computer software,
including but not limited to implied warranties of merchantability
and fitness for a particular purpose. In no event shall Ream be
liable for any loss of profit or any commercial damage, including
but not limited to special, incidental consequential or other damages.
*/
#include "spp.h"
/* Declare types of internal parsing routines. */
static void stat_list (void);
static bool stat1 (void);
static void do_if (void);
static void do_do (void);
static void do_while (void);
static void do_do (void);
static void do_while (void);
static void do_for (void);
static void do_switch (void);
static void do_break (void);
static void do_continue (void);
static void do_case (void);
static void do_default (void);
static void do_return (void);
static void do_goto (void);
static void do_label (void);
static void show_need (char * s);
static void ll_check (void);
static void ll_enter (char * s);
static bool ll_lookup (char * s);
/* ========== Local data structures ========== */
static bool break_ok = FALSE; /* TRUE if break is allowed. */
static bool cont_ok = FALSE; /* TRUE if break is allowed. */
static bool in_switch = FALSE; /* TRUE if in a switch. */
/* ========== Globally visible routines ========== */
/*
Parse a block, including opening and closing braces.
This is NOT called to parse the block that comprises a function body.
*/
void
block(void)
{
TRACETOK("block");
must(LCURLY_TOK);
block_dcls();
stat_list();
need(RCURLY_TOK);
LEAVE("block");
}
/*
Parse a function body, including opening and closing braces.
*/
void
body(void)
{
TRACETOK("body");
must(LCURLY_TOK);
/* All future definitions are local to the block. */
st_begin();
/* Parse local declarations. */
block_dcls();
/* Output the sherlock macro. */
so_entry();
sf_1body();
stat_list();
sf_2body();
/* Output a LEAVE() macro if we have fallen through the end. */
so_leave();
need(RCURLY_TOK);
/* Go back to global definitions. */
st_end();
LEAVE("body");
}
/*
Skip the current token if it is what we think it is.
*/
void
need(en_tokens tok)
{
ENTER_TRACE("need", printf("(%d)\n", tok));
if (token == tok) {
get_token();
}
else {
show_need(pr_op(tok));
}
LEAVE("need");
}
/*
Internal error if the token is not found.
Othewise, eat it.
*/
void
must(en_tokens expected)
{
ENTER_TRACE("must", printf("(%d)\n", expected));
if (token != expected) {
printf("<%s> expected, <%s> found\n",
pr_op(expected), pr_op(token));
fatal("internal: must");
}
else {
get_token();
}
LEAVE("must");
}
/*
error message about needed symbol
*/
static void
show_need(char * s)
{
ENTER_TRACE("show_need", printf("(%s)\n", s));
if (token == ID_TOK) {
err3(s, " expected at: ", t_symbol);
}
else if (pr_op(token)) {
err3(s, " expected at: ", pr_op(token));
}
else {
err2(s, " expected");
}
LEAVE("show_need");
}
/*
If the current token is tok, return TRUE and eat it.
Otherwise find the next instance of tok, eat it, and return FALSE.
-- BUT --
Stop on and return an intervening semicolon or brace.
*/
bool
needend(en_tokens tok)
{
TRACETOK("needend");
if (token == tok) {
get_token();
RETURN_INT("needend", TRUE);
}
show_need(pr_op(tok));
for(;;) {
switch(token) {
case SEMICOLON_TOK:
case LCURLY_TOK:
case RCURLY_TOK:
case EOP_TOK:
RETURN_INT("needend", FALSE);
}
get_token();
if (token == tok) {
get_token();
RETURN_INT("needend", FALSE);
}
}
}
/* ========== Internal Routines ========== */
static void
stat_list(void)
{
TRACETOK("stat_list");
while(stat1()) {
;
}
LEAVE("stat_list");
}
/*
Parse a single statement.
Return TRUE if a statement was seen.
*/
static bool
stat1(void)
{
TRACETOK("stat1");
loop:
switch(token) {
case EOP_TOK:
case RCURLY_TOK:
RETURN_INT("stat1", FALSE);
case LCURLY_TOK:
block();
RETURN_INT("stat1", TRUE);
case SEMICOLON_TOK:
get_token();
goto loop;
case K_BREAK: do_break(); RETURN_INT("stat1", TRUE);
case K_CASE: do_case(); RETURN_INT("stat1", TRUE);
case K_CONTINUE: do_continue(); RETURN_INT("stat1", TRUE);
case K_DEFAULT: do_default(); RETURN_INT("stat1", TRUE);
case K_DO: do_do(); RETURN_INT("stat1", TRUE);
case K_FOR: do_for(); RETURN_INT("stat1", TRUE);
case K_GOTO: do_goto(); RETURN_INT("stat1", TRUE);
case K_IF: do_if(); RETURN_INT("stat1", TRUE);
case K_SWITCH: do_switch(); RETURN_INT("stat1", TRUE);
case K_WHILE: do_while(); RETURN_INT("stat1", TRUE);
case K_RETURN: do_return(); RETURN_INT("stat1", TRUE);
case ID_TOK:
/* Do character-oriented lookahead. */
skip_bl();
if (ch == ':') {
do_label();
goto loop;
}
default:
if (is_type()) {
error("Declaration in code: check brace structure");
RETURN_INT("stat1", FALSE);
}
else if (is_expr_tok()) {
sf_expr();
expr(SEMICOLON_TOK);
need(SEMICOLON_TOK);
RETURN_INT("stat1", TRUE);
}
else {
RETURN_INT("stat1", FALSE);
}
}
}
/*
Parse complex statements.
*/
static void
do_do(void)
{
int oldcont;
int oldbrk;
TRACETOK("do_do");
oldcont = cont_ok; cont_ok = TRUE;
oldbrk = break_ok; break_ok = TRUE;
must(K_DO);
sf_1do();
stat1();
sf_2do();
need(K_WHILE);
need(LPAREN_TOK);
expr(RPAREN_TOK);
need(RPAREN_TOK);
cont_ok = oldcont;
break_ok = oldbrk;
LEAVE("do_do");
}
static void
do_for(void)
{
int oldcont;
int oldbrk;
TRACETOK("do_for");
oldcont = cont_ok; cont_ok = TRUE;
oldbrk = break_ok; break_ok = TRUE;
must(K_FOR);
need(LPAREN_TOK);
expr(SEMICOLON_TOK); need(SEMICOLON_TOK);
sf_1for(is(SEMICOLON_TOK));
expr(SEMICOLON_TOK); need(SEMICOLON_TOK);
expr(RPAREN_TOK); need(RPAREN_TOK);
stat1();
sf_2for();
cont_ok = oldcont;
break_ok = oldbrk;
LEAVE("do_for");
}
static void
do_if(void)
{
TRACETOK("do_if");
must(K_IF);
need(LPAREN_TOK);
expr(RPAREN_TOK);
need(RPAREN_TOK);
sf_1if();
stat1();
if (token == K_ELSE) {
must(K_ELSE);
sf_2if();
stat1();
}
sf_3if();
LEAVE("do_if");
}
static void
do_switch(void)
{
int oldswitch;
int oldbrk;
TRACETOK("do_switch");
oldswitch = in_switch; in_switch = TRUE;
oldbrk = break_ok; break_ok = TRUE;
must(K_SWITCH);
need(LPAREN_TOK);
expr(RPAREN_TOK);
need(RPAREN_TOK);
need(LCURLY_TOK);
sf_1switch();
stat_list();
sf_2switch();
need(RCURLY_TOK);
in_switch = oldswitch;
break_ok = oldbrk;
LEAVE("do_switch");
}
static void
do_while(void)
{
int oldcont;
int oldbrk;
TRACETOK("do_while");
oldcont = cont_ok; cont_ok = TRUE;
oldbrk = break_ok; break_ok = TRUE;
must(K_WHILE);
need(LPAREN_TOK);
expr(RPAREN_TOK);
need(RPAREN_TOK);
sf_1while();
stat1();
sf_2while();
cont_ok = oldcont;
break_ok = oldbrk;
LEAVE("do_while");
}
/*
Parse subordinate statements.
*/
static void
do_break(void)
{
TRACETOK("do_break");
if (!break_ok) {
error("'break' does not match any statement");
}
sf_break();
must(K_BREAK);
need(SEMICOLON_TOK);
LEAVE("do_break");
}
static void
do_case(void)
{
TRACETOK("do_case");
if (!in_switch) {
error("'case' appears outside of any switch");
}
must(K_CASE);
con_expr(COLON_TOK);
need(COLON_TOK);
LEAVE("do_case");
}
static void
do_continue(void)
{
TRACETOK("do_continue");
if (!cont_ok) {
error("'continue' appears outside do, while and if");
}
must(K_CONTINUE);
need(SEMICOLON_TOK);
LEAVE("do_continue");
}
static void
do_default(void)
{
TRACETOK("do_default");
/* Make sure we are in a switch statement. */
if (in_switch == NULL) {
error("'default' appears outside of a switch");
}
sf_default();
must(K_DEFAULT);
need(COLON_TOK);
LEAVE("do_default");
}
static void
do_goto(void)
{
TRACETOK("do_goto");
sf_goto();
must(K_GOTO);
need(ID_TOK);
needend(SEMICOLON_TOK);
LEAVE("do_goto");
}
static void
do_label(void)
{
ENTER("do_label");
sf_label();
must(ID_TOK);
need(COLON_TOK);
LEAVE("do_label");
}
static void
do_return(void)
{
TRACETOK("do_return");
sf_return();
so_1exit();
must(K_RETURN);
if (token == SEMICOLON_TOK) {
so_2exit(FALSE);
}
else {
so_2exit(TRUE);
expr(SEMICOLON_TOK);
}
so_3exit();
need(SEMICOLON_TOK);
LEAVE("do_return");
}
/* =============== Label table routines =============== */
/* Define label list node. */
static struct label_node {
struct label_node * lab_next;
bool lab_defined;
char * lab_name;
};
static struct label_node
ll_head = {NULL, FALSE, NULL}; /* Header node. */
/*
Check the local label list table to see if any labels
have been referenced but not defined.
This should be done at the end of each function.
*/
static void
ll_check(void)
{
register struct label_node * p;
ENTER("ll_check");
for (p = ll_head.lab_next; p; p = p -> lab_next) {
if (p -> lab_defined == FALSE) {
err2("Undefined label: ", p -> lab_name);
}
}
LEAVE("ll_check");
}
/*
Enter a symbol in the local label list and mark it undefined.
*/
static void
ll_enter(char * symbol)
{
register struct label_node * p;
ENTER_TRACE("ll_enter", printf("(%s)\n", symbol));
/* Make a new entry entry in the local label list. */
p = m_alloc(sizeof(struct label_node));
p -> lab_defined = FALSE;
p -> lab_name = str_alloc(symbol);
/* Link it to the head of the list. */
p -> lab_next = ll_head.lab_next;
ll_head.lab_next = p;
LEAVE("ll_enter");
}
/*
Look up a symbol in the local label list.
*/
static bool
ll_lookup(char * symbol)
{
register struct label_node * p;
ENTER_TRACE("ll_lookup", printf("(%s)\n", symbol));
for (p = ll_head.lab_next; p != NULL; p = p -> lab_next) {
if (str_eq(symbol, p -> lab_name)) {
RETURN_INT("ll_lookup", TRUE);
}
}
RETURN_INT("ll_lookup", FALSE);
}