home services resume portfolio contact us about me


Return To Portfolio Home


/* ----------------------------------------------------------------------
 * FILE: boss_parse.y
 * PACKAGE: boss - 
 * DESCRIPTION:
 *	Parser for the Casio B.O.S.S data exchange format.
 *
 * REVISION HISTORY:
 *
 * AUTHOR:
 *	Ken Stauffer. December 1995
 */

%{
#include <setjmp.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>

#include "boss.h"
#include "bossP.h"

/* #define YYSTYPE union ystack REMOVE THIS LINE */

/* proto-types */
static BOSS_TIME	mktime(int, int, int);
static BOSS_TIME	no_time(void);
static BOSS_DATE	mkdate(int, int, int, int);
static DATETIME		mk_datetime(BOSS_DATE *, BOSS_TIME *);
static BOSS_PHONE	*phone_join(BOSS_PHONE *, BOSS_PHONE *);
static BOSS_MEMO	*memo_join(BOSS_MEMO *, BOSS_MEMO *);
static BOSS_SCHEDULE	*schedule_join(BOSS_SCHEDULE *, BOSS_SCHEDULE *);
static BOSS_REMINDER	*reminder_join(BOSS_REMINDER *, BOSS_REMINDER *);
static BOSS_CALENDAR	*calendar_join(BOSS_CALENDAR *, BOSS_CALENDAR *);
static BOSS_TODO	*todo_join(BOSS_TODO *, BOSS_TODO *);
static BOSS_EXPENSE	*expense_join(BOSS_EXPENSE *, BOSS_EXPENSE *);
static BOSS_TODO	*mktodo(int checkmark, DATETIME *, char *);
static BOSS_PHONE	*mkphone(STRLST *);
static BOSS_REMINDER	*mkreminder(BOSS_DATE *, BOSS_TIME *, char *);
static BOSS_MEMO	*mkmemo(char *, char *);
static BOSS_SCHEDULE	*mkschedule(BOSS_DATE *, RANGE *, BOSS_TIME *, char *);
static BOSS_CALENDAR	*mkcalendar(int, int, NUMLST *);
static BOSS_EXPENSE	*mkexpense(double, BOSS_DATE *, char *, char *, char *);
static STRLST		*mkstrlst(STRLST *, char *);
static NUMLST		*mknumlst(NUMLST *, int);
static RANGE		mkrange(BOSS_TIME *, BOSS_TIME *); /* ADD THIS LINE */

%}

%token <value>	NUMBER
%token <fvalue>	FLOAT
%token <str>	STRING
%token JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC
%token AM PM
%token ENDREC
%token SECTION
%token CHECKMARK
%token TODO
%token PHONE
%token REMINDER
%token MEMO
%token SCHEDULE
%token CALENDAR
%token EXPENSE
%token SATSUN MON TUE WED THUR FRI

%type <phone>		phone_rec	phone_list	phone_section
%type <memo>		memo_rec	memo_list	memo_section
%type <schedule>	schedule_rec	schedule_list	schedule_section
%type <reminder>	reminder_rec	reminder_list	reminder_section
%type <calendar>	calendar_rec	calendar_list	calendar_section
%type <todo>		todo_rec	todo_list	todo_section
%type <expense>		expense_rec	expense_list	expense_section

%type <dt>		opt_date_time
%type <date>		date_spec reminder_spec
%type <time>		time_spec opt_time
%type <range>		opt_range
%type <value>		month check_mark ampm calnum
%type <str>		opt_string
%type <strlst>		string_list
%type <numlst>		cal_num_list

%start datafile

/* ------------------------ G R A M M A R ----------------------------- */

%%
datafile	: section_list
		;

section_list	: section
		| section_list section
		;

section		: phone_section				{ phone_add($1); }
		| memo_section				{ memo_add($1); }
		| schedule_section			{ schedule_add($1); }
		| reminder_section			{ reminder_add($1); }
		| calendar_section			{ calendar_add($1); }
		| todo_section				{ todo_add($1); }
		| expense_section			{ expense_add($1); }
		;

/*----------------------------------------------------------------------*/

todo_section	: SECTION TODO SECTION todo_list		{ $$ = $4; }
		| SECTION TODO SECTION 				{ $$ = NULL; }
		;

phone_section	: SECTION PHONE SECTION phone_list		{ $$ = $4; }
		| SECTION PHONE SECTION 			{ $$ = NULL; }
		;

reminder_section: SECTION REMINDER SECTION reminder_list	{ $$ = $4; }
		| SECTION REMINDER SECTION 				{ $$ = NULL; }
		;

memo_section	: SECTION MEMO SECTION memo_list		{ $$ = $4; }
		| SECTION MEMO SECTION 				{ $$ = NULL; }
		;

schedule_section: SECTION SCHEDULE SECTION schedule_list	{ $$ = $4; }
		| SECTION SCHEDULE SECTION 			{ $$ = NULL; }
		;

calendar_section: SECTION CALENDAR SECTION calendar_list	{ $$ = $4; }
		| SECTION CALENDAR SECTION 			{ $$ = NULL; }
		;

expense_section	: SECTION EXPENSE SECTION expense_list		{ $$ = $4; }
		| SECTION EXPENSE SECTION 			{ $$ = NULL; }
		;

/*----------------------------------------------------------------------*/

todo_list	: todo_rec ENDREC			{ $$ = $1; }
		| todo_list todo_rec ENDREC		{ $$ = todo_join($1,$2); }
		;

phone_list	: phone_rec ENDREC			{ $$ = $1; }
		| phone_list phone_rec ENDREC		{ $$ = phone_join($1,$2); }
		;

reminder_list	: reminder_rec ENDREC			{ $$ = $1; }
		| reminder_list reminder_rec ENDREC	{ $$ = reminder_join($1,$2); }
		;

memo_list	: memo_rec ENDREC			{ $$ = $1; }
		| memo_list memo_rec ENDREC		{ $$ = memo_join($1,$2); }
		;

schedule_list	: schedule_rec ENDREC			{ $$ = $1; }
		| schedule_list schedule_rec ENDREC	{ $$ = schedule_join($1,$2); }
		;

calendar_list	: calendar_rec ENDREC			{ $$ = $1; }
		| calendar_list calendar_rec ENDREC	{ $$ = calendar_join($1,$2); }
		;

expense_list	: expense_rec ENDREC			{ $$ = $1; }
		| expense_list expense_rec ENDREC	{ $$ = expense_join($1,$2); }
		;

/*----------------------------------------------------------------------*/

todo_rec	: check_mark opt_date_time STRING	{ $$ = mktodo($1,&$2,$3); }
		;

phone_rec	: string_list				{ $$ = mkphone($1); }
		;

reminder_rec	: reminder_spec opt_time STRING		{ $$ = mkreminder(&$1,&$2,$3); }
		;

memo_rec	: STRING opt_string			{ $$ = mkmemo($1, $2); }
		;

schedule_rec	: date_spec opt_range STRING opt_time
						{ $$ = mkschedule(&$1,&$2,&$4,$3); }
		;

calendar_rec	: month NUMBER
		SATSUN MON TUE WED THUR FRI SATSUN
		cal_num_list
						{ $$ = mkcalendar($1,$2,$10); }

expense_rec	: FLOAT date_spec STRING STRING opt_string
						{ $$ = mkexpense($1,&$2,$3,$4,$5); }
		| NUMBER date_spec STRING STRING opt_string
						{ $$ = mkexpense($1,&$2,$3,$4,$5); }
		;

/*----------------------------------------------------------------------*/

string_list	: STRING				{ $$ = mkstrlst(NULL,$1); }
		| string_list STRING			{ $$ = mkstrlst($1,$2); }
		;

opt_string	: STRING			{ $$ = $1; }
		| /* empty */			{ $$ = strdup(""); }
		;

opt_time	: time_spec			{ $$ = $1; }
		| /* empty */			{ $$ = no_time(); }
		;

opt_range	: time_spec			{ $$ = mkrange(&$1, NULL); }
		| time_spec '-' time_spec	{ $$ = mkrange(&$1, &$3); }
		| /* empty */			{ $$ = mkrange(NULL, NULL); }
		;

opt_date_time	: date_spec time_spec		{ $$ = mk_datetime(&$1,&$2); }
		| date_spec			{ $$ = mk_datetime(&$1,NULL); }
		| /* empty */			{ $$ = mk_datetime(NULL,NULL); }
		;

reminder_spec	: '['  '-'  '/'  '-'  ']'		{ $$ = mkdate(1,0,0,0); }
		| '['  '-'  '/'  NUMBER  ']'		{ $$ = mkdate(1,0,0,$4); }
		| '['  NUMBER  '/'  NUMBER  ']'		{ $$ = mkdate(1,0,$2,$4); }
		;

time_spec	: '[' NUMBER ':' NUMBER ampm ']'	{ $$ = mktime($2,$4,$5); }
		;

ampm		: AM				{ $$ = T_AM; }
		| PM				{ $$ = T_PM; }
		| /* empty */			{ $$ = T_NOTSPECIFIED; }
		;

cal_num_list	: calnum			{ $$ = mknumlst(NULL,$1); }
		| cal_num_list calnum		{ $$ = mknumlst($1,$2); }
		;

calnum		: NUMBER			{ $$ = $1; }
		| SECTION			{ $$ = -1; }
		;

		/* -------------------------------------------------
		 * Date formats:
		 *	year / month / day	95/11/4
		 *	month / day / year	Nov/4/95
		 *	day / month / year	4/NOV/95
		 *	day-month-year		4-november-1995
		 */

date_spec	: '[' NUMBER '/' NUMBER '/' NUMBER ']'	{ $$ = mkdate(0,$2,$4,$6); }
		| '[' month '/' NUMBER '/' NUMBER ']'	{ $$ = mkdate(0,$6,$2,$4); }
		| '[' NUMBER '/' month '/' NUMBER ']'	{ $$ = mkdate(0,$6,$4,$2); }
		| '[' NUMBER '-' month '-' NUMBER ']'	{ $$ = mkdate(0,$6,$4,$2); }
		;

check_mark	: '[' CHECKMARK ']'		{ $$ = 1; }
		| '[' ']'			{ $$ = 0; }
		;

month		: JAN				{ $$ = 1; }
		| FEB				{ $$ = 2; }
		| MAR				{ $$ = 3; }
		| APR				{ $$ = 4; }
		| MAY				{ $$ = 5; }
		| JUN				{ $$ = 6; }
		| JUL				{ $$ = 7; }
		| AUG				{ $$ = 8; }
		| SEP				{ $$ = 9; }
		| OCT				{ $$ = 10; }
		| NOV				{ $$ = 11; }
		| DEC				{ $$ = 12; }
		;
%%

/* ---------------------------------------------------------------------- */

void bosserror(char *s)
{
	boss_error(s);
}

/* ----------------------------------------------------------------------
 * Uses variable arguments. This causes immediate termination
 * of the parse.
 */
void boss_error(char *cs, ...)
{
	va_list ap;
	char buf[ 2000 ];

	va_start(ap, cs);

	sprintf(buf,"File: %s, line: %d, ", Boss.datafile, Boss.lineno);
	strcpy(Boss.error, buf);

	vsprintf(buf, cs, ap);
	strcat(Boss.error, buf);
	strcat(Boss.error, ".");
	va_end(ap);

	longjmp(Boss.main_env, 1);
}

/* Build a BOSS_TIME structure. Perform
 * the following checks:
 *	- if ampm is not specified (T_NOTSPECIFIED), then
 *	  hours must be 0-23. Else hours must be 0-12
 *	- Minutes must be 0-59.
 *	- If T_NOTSPECIFIED, assume 24-hour clock, and convert
 *	  final result to 12 hour clock system.
 *	- If any field is < 0, all
 *
 */
static BOSS_TIME mktime(int hours, int minutes, int ampm)
{
	BOSS_TIME time;
	int cnt;

	cnt = 0;
	if( hours < 0 ) cnt++;
	if( minutes < 0 ) cnt++;
	if( ampm < 0 ) cnt++;

	if( cnt > 0 && cnt != 3 )
		boss_error("Bogus time specification %d:%d", hours,minutes);
	else if( cnt == 3 ) {
		/* "notime" */
		time.hour = -1;
		time.minute = -1;
		time.pm = -1;
		return time;
	}

	if( minutes > 59 || minutes < 0 )
		boss_error("Minutes out of range: %d", minutes);

	if( ampm == T_NOTSPECIFIED ) {
		if( hours > 23 || hours < 0 )
			boss_error("Hours out of range: %d", hours);

		time.hour	= HOUR24TO12(hours);
		time.pm		= HOUR24TOAMPM(hours);
		time.minute	= minutes;
	} else {
		if( hours > 12 || hours <= 0 )
			boss_error("Hours out of range: %d", hours);

		time.hour	= hours;
		time.pm		= (ampm == T_AM ) ? 0 : 1;
		time.minute	= minutes;
	}

	return time;
}

/*
 * Return a BOSS_TIME structure, set to the "no time" configuration.
 */
static BOSS_TIME no_time(void)
{
	BOSS_TIME time;

	time.hour = -1;
	time.minute = -1;
	time.pm = -1;
	return time;
}

static RANGE mkrange(BOSS_TIME *start, BOSS_TIME *end)
{
	RANGE r;

	if( start )
		r.start = *start;
	else
		r.start = no_time();

	if( end )
		r.end = *end;
	else
		r.end = no_time();

	return r;
}

/*
 * Build a BOSS_DATE structure. Perform the following checks:
 *	- If month specified, check the day.
 *	- If month not specified (is 0), day can be 0 to 32.
 *	- Month must be between 1-12.
 *	- If year is less than 100, then add 1900 to year.
 *	  (valid ranges for years are: 1960 to 2100)
 *
 *	year, month and day cannot be 0 when reminder is FALSE.
 *
 */
static BOSS_DATE mkdate(int reminder, int year, int month, int day)
{
	BOSS_DATE date;
	static monlen[] = { 0, 31,29,31,30,31,30,31,31,30,31,30,31 };

	if( year > 0 && year < 100 )
		year += 1900;

	if( (year < 1960 || year > 2099) && year != 0 )
		boss_error("Year out of valid range: %d", year);

	if( year == 0 && !reminder )
		boss_error("Year out of valid range: %d", year);

	if( month != 0 && (month < 1 || month > 12) )
		boss_error("Month out of range: %d", month);

	if( month ) {
		if( day <= 0 || day > monlen[month] )
			boss_error("Day-of-month out of range: %d (for month %d)",
							day, month);
	} else {
		if( !reminder )
			boss_error("Month out of range: %d", month);

		if( day == 0 && !reminder )
			boss_error("Day out of range: %d", day);

		if( day != 0 && (day <= 0 || day > 32) )
			boss_error("Day-of-month out of range: %d", day);
	}

	date.year = year;
	date.month = month;
	date.day = day;

	return date;
}

/*
 * return a structure which contains both data and time.
 * If data or time is NULL, set the appropriate structure to
 * the "nodata" configuration.
 */
static DATETIME mk_datetime(BOSS_DATE *date, BOSS_TIME *time)
{
	DATETIME dt;

	if( date ) {
		dt.date		= *date;
	} else {
		dt.date.year	= 0;
		dt.date.month	= 0;
		dt.date.day	= 0;
	}

	if( time ) {
		dt.time		= *time;
	} else {
		dt.time.hour	= -1;
		dt.time.minute	= -1;
		dt.time.pm	= -1;
	}

	return dt;
}

/*----------------------------------------------------------------------
 * XXXXXX_join:
 *	Joins the list 'lst' and the item (or list) 'item'.
 * RETURNS:
 *	'lst' is returned. 
 *
 * ASSUMPTIONS:
 *	'lst' is not NULL. 'item' is not NULL.
 */

static BOSS_PHONE *phone_join(BOSS_PHONE *lst, BOSS_PHONE *item)
{
	BOSS_PHONE *curr;

	for(curr=lst; curr->next; curr=curr->next)
		;
	curr->next = item;
	return lst;
}
static BOSS_MEMO *memo_join(BOSS_MEMO *lst, BOSS_MEMO *item)
{
	BOSS_MEMO *curr;

	for(curr=lst; curr->next; curr=curr->next)
		;
	curr->next = item;
	return lst;
}
static BOSS_SCHEDULE *schedule_join(BOSS_SCHEDULE *lst, BOSS_SCHEDULE *item)
{
	BOSS_SCHEDULE *curr;

	for(curr=lst; curr->next; curr=curr->next)
		;
	curr->next = item;
	return lst;
}
static BOSS_REMINDER *reminder_join(BOSS_REMINDER *lst, BOSS_REMINDER *item)
{
	BOSS_REMINDER *curr;

	for(curr=lst; curr->next; curr=curr->next)
		;
	curr->next = item;
	return lst;
}
static BOSS_CALENDAR *calendar_join(BOSS_CALENDAR *lst, BOSS_CALENDAR *item)
{
	BOSS_CALENDAR *curr;

	for(curr=lst; curr->next; curr=curr->next)
		;
	curr->next = item;
	return lst;
}
static BOSS_TODO *todo_join(BOSS_TODO *lst, BOSS_TODO *item)
{
	BOSS_TODO *curr;

	for(curr=lst; curr->next; curr=curr->next)
		;
	curr->next = item;
	return lst;
}
static BOSS_EXPENSE *expense_join(BOSS_EXPENSE *lst, BOSS_EXPENSE *item)
{
	BOSS_EXPENSE *curr;

	for(curr=lst; curr->next; curr=curr->next)
		;
	curr->next = item;
	return lst;
}

/*----------------------------------------------------------------------
 * XXXX_add:
 *	These functions add 'list' to the end of Boss.data.XXXX.
 *	If Boss.data.XXXX is NULL, then set it to 'list'.
 *	This function will work if 'list' is NULL.
 */
void phone_add(BOSS_PHONE *list)
{
	if( Boss.data->phone == NULL )
		Boss.data->phone = list;
	else
		phone_join(Boss.data->phone, list);
}
void memo_add(BOSS_MEMO *list)
{
	if( Boss.data->memo == NULL )
		Boss.data->memo = list;
	else
		memo_join(Boss.data->memo, list);
}
void schedule_add(BOSS_SCHEDULE *list)
{
	if( Boss.data->schedule == NULL )
		Boss.data->schedule = list;
	else
		schedule_join(Boss.data->schedule, list);
}
void reminder_add(BOSS_REMINDER *list)
{
	if( Boss.data->reminder == NULL )
		Boss.data->reminder = list;
	else
		reminder_join(Boss.data->reminder, list);
}
void calendar_add(BOSS_CALENDAR *list)
{
	if( Boss.data->calendar == NULL )
		Boss.data->calendar = list;
	else
		calendar_join(Boss.data->calendar, list);
}
void todo_add(BOSS_TODO *list)
{
	if( Boss.data->todo == NULL )
		Boss.data->todo = list;
	else
		todo_join(Boss.data->todo, list);
}
void expense_add(BOSS_EXPENSE *list)
{
	if( Boss.data->expense == NULL )
		Boss.data->expense = list;
	else
		expense_join(Boss.data->expense, list);
}
/*----------------------------------------------------------------------
 * mkXXXXXX()
 *	Build a record type and return it.
 */
static BOSS_TODO *mktodo(int checkmark, DATETIME *dt, char *desc)
{
	BOSS_TODO *rec;

	rec = (BOSS_TODO*)calloc(1, sizeof(BOSS_TODO) );
	if( rec == NULL )
		boss_error("no memory for BOSS_TODO");

	rec->next = NULL;
	rec->checked = checkmark;
	rec->date_stamp = dt->date;
	rec->time_stamp = dt->time;
	rec->description = desc;
	return rec;
}

static BOSS_PHONE *mkphone(STRLST *strlst)
{
	STRLST *curr, *next;
	BOSS_PHONE *rec;

	rec = (BOSS_PHONE*)calloc(1, sizeof(BOSS_PHONE));
	if( rec == NULL )
		boss_error("no memory for BOSS_PHONE");

	rec->next = NULL;

	curr = strlst;

	if( curr ) {
		rec->name = curr->str;
		curr = curr->next;
	}

	if( curr ) {
		rec->number = curr->str;
		curr = curr->next;
	}

	if( curr ) {
		rec->address = curr->str;
		curr = curr->next;
	}

	if( curr ) {
		rec->free1 = curr->str;
		curr = curr->next;
	}

	if( curr ) {
		rec->free2 = curr->str;
		curr = curr->next;
	}

	if( curr ) {
		rec->free3 = curr->str;
		curr = curr->next;
	}

	if( curr ) {
		rec->free4 = curr->str;
		curr = curr->next;
	}

	if( curr ) {
		rec->free5 = curr->str;
		curr = curr->next;
	}

	if( curr ) {
		rec->free6 = curr->str;
		curr = curr->next;
	}

	if( curr )
		boss_error("Telepone entry contains more than 9 fields");

	/*
	 * Delete string list.
	 */
	curr = strlst;
	while( curr ) {
		next = curr->next;
		free(curr);
		curr = next;
	}

	return rec;
}

static BOSS_REMINDER *mkreminder(BOSS_DATE *date, BOSS_TIME *time, char *desc)
{
	BOSS_REMINDER *rec;

	rec = (BOSS_REMINDER*)calloc(1, sizeof(BOSS_REMINDER) );
	if( rec == NULL )
		boss_error("no memory for BOSS_REMINDER");

	rec->next = NULL;
	rec->date = *date;
	rec->alarm = *time;
	rec->description = desc;
	return rec;
}

static BOSS_MEMO *mkmemo(char *title, char *body)
{
	BOSS_MEMO *rec;

	rec = (BOSS_MEMO*)calloc(1, sizeof(BOSS_MEMO) );
	if( rec == NULL )
		boss_error("no memory for BOSS_MEMO");

	rec->next = NULL;
	rec->title = title;
	rec->body = body;
	return rec;
}

static BOSS_SCHEDULE *mkschedule(BOSS_DATE *date, RANGE *rng, BOSS_TIME *alarm,
									char *desc)
{
	BOSS_SCHEDULE *rec;

	rec = (BOSS_SCHEDULE*)calloc(1, sizeof(BOSS_SCHEDULE) );
	if( rec == NULL )
		boss_error("no memory for BOSS_SCHEDULE");

	rec->next = NULL;
	rec->date = *date;
	rec->start = rng->start;
	rec->end = rng->end;
	rec->alarm = *alarm;
	rec->description = desc;
	return rec;
}

static BOSS_CALENDAR *mkcalendar(int month, int year, NUMLST *days)
{
	BOSS_CALENDAR *rec;
	NUMLST *curr;
	static monlen[] = { 0, 31,29,31,30,31,30,31,31,30,31,30,31 };
	int cday;

	rec = (BOSS_CALENDAR*)calloc(1, sizeof(BOSS_CALENDAR) );
	if( rec == NULL )
		boss_error("out of memory for BOSS_CALENDAR");

	if( (year < 1960 || year > 2099) && year != 0 )
		boss_error("Year out of valid range: %d", year);

	rec->date.year = year;
	rec->date.month = month;
	rec->date.day = 1;

	rec->days = 0;

	cday = 1;
	for(curr=days; curr; curr=curr->next) {
		if( curr->num < 0 ) {
			if( cday > monlen[month] )
				boss_error("too many days for month %d", month);
			rec->days |= (1<<(cday-1));
		} else if( curr->num != cday ) {

			boss_error("Calendar day %d out of order (should be %d)",
						curr->num, cday);
		} else if( cday > monlen[month] )
			boss_error("too many days for month %d", month);
		cday += 1;
	}

	rec->next = NULL;
	return rec;
}

static BOSS_EXPENSE *mkexpense(double amount, BOSS_DATE *date,
						char *payment, char *expense, char *desc)
{
	BOSS_EXPENSE *rec;

	rec = (BOSS_EXPENSE*)calloc(1, sizeof(BOSS_EXPENSE) );
	if( rec == NULL )
		boss_error("no memory for BOSS_EXPENSE");

	rec->next = NULL;
	rec->amount = amount;
	rec->date = *date;
	rec->payment = payment;
	rec->expense = expense;
	rec->description = desc;
	return rec;
}

static STRLST *mkstrlst(STRLST *lst, char *item)
{
	STRLST *n, *curr;

	n = (STRLST*)calloc(1, sizeof(STRLST) );
	if( n == NULL )
		boss_error("out of memory for STRLST");

	n->str = item;
	n->next = NULL;

	if( lst == NULL )
		return n;

	for(curr=lst; curr->next; curr=curr->next)
		;
	curr->next = n;
	return lst;
}

static NUMLST *mknumlst(NUMLST *lst, int item)
{
	NUMLST *n, *curr;

	n = (NUMLST*)calloc(1, sizeof(NUMLST) );
	if( n == NULL )
		boss_error("out of memory for NUMLST");

	n->num = item;
	n->next = NULL;

	if( lst == NULL )
		return n;

	for(curr=lst; curr->next; curr=curr->next)
		;
	curr->next = n;
	return lst;
}

Return To Portfolio Home

compilers • parsers • translators • C++ • yacc &bull lex • bison • unix • windows • eiffel • grammars