From 712b0690da4b03842a954bfbd1f75925bb7b234e Mon Sep 17 00:00:00 2001 From: anthk Date: Mon, 8 Mar 2021 21:34:43 +0000 Subject: =?UTF-8?q?Importaci=C3=B3n=20inicial=20a=20texto-plano?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bwbasic.c | 3639 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3639 insertions(+) create mode 100644 bwbasic.c (limited to 'bwbasic.c') diff --git a/bwbasic.c b/bwbasic.c new file mode 100644 index 0000000..4549495 --- /dev/null +++ b/bwbasic.c @@ -0,0 +1,3639 @@ +/*************************************************************** + + bwbasic.c Main Program File + for Bywater BASIC Interpreter + + Copyright (c) 1993, Ted A. Campbell + Bywater Software + + email: tcamp@delphi.com + + Copyright and Permissions Information: + + All U.S. and international rights are claimed by the author, + Ted A. Campbell. + + This software is released under the terms of the GNU General + Public License (GPL), which is distributed with this software + in the file "COPYING". The GPL specifies the terms under + which users may copy and use the software in this distribution. + + A separate license is available for commercial distribution, + for information on which you should contact the author. + +***************************************************************/ + +/*---------------------------------------------------------------*/ +/* NOTE: Modifications marked "JBV" were made by Jon B. Volkoff, */ +/* 11/1995 (eidetics@cerf.net). */ +/* */ +/* Those additionally marked with "DD" were at the suggestion of */ +/* Dale DePriest (daled@cadence.com). */ +/* */ +/* Version 3.00 by Howard Wulf, AF5NE */ +/* */ +/* Version 3.10 by Howard Wulf, AF5NE */ +/* */ +/* Version 3.20 by Howard Wulf, AF5NE */ +/* */ +/*---------------------------------------------------------------*/ + + + +#include "bwbasic.h" + +static void break_handler (void); +static void break_mes (int x); +static int bwb_init (void); +static void bwb_initialize_warnings (void); +static void bwb_interact (void); +static int bwb_ladd (char *buffer, LineType * p, int IsUser); +static void bwb_single_step (char *buffer); +static void bwb_xtxtline (char *buffer); +static int bwx_signon (void); +static void execute_profile (char *FileName); +static void execute_program (char *FileName); +static char *FindClassicStatementEnd (char *C); +static int FixQuotes (char *tbuf); +static void ImportClassicIfThenElse (char *InBuffer); +static int is_ln (char *buffer); +static int is_numconst (char *buffer); +static void mark_preset_variables (void); +static FILE *nice_open (char *BaseName); +static void process_basic_line (char *buffer); + +GlobalType *My = NULL; + +static char *Banner[] = { + "######## ## ## ## ## ### ######## ######## ######## ", + "## ## ## ## ## ## ## ## ## ## ## ## ## ", + "## ## #### ## ## ## ## ## ## ## ## ## ", + "######## ## ## ## ## ## ## ## ###### ######## ", + "## ## ## ## ## ## ######### ## ## ## ## ", + "## ## ## ## ## ## ## ## ## ## ## ## ", + "######## ## ### ### ## ## ## ######## ## ## ", + " ", + " ", + " ######## ### ###### #### ###### ", + " ## ## ## ## ## ## ## ## ##", + " ## ## ## ## ## ## ## ", + " ######## ## ## ###### ## ## ", + " ## ## ######### ## ## ## ", + " ## ## ## ## ## ## ## ## ##", + " ######## ## ## ###### #### ###### ", + " ", + "Bywater BASIC Interpreter, version 3.20 ", + "Copyright (c) 1993, Ted A. Campbell ", + "Copyright (c) 1995-1997, Jon B. Volkoff ", + "Copyright (c) 2014-2017, Howard Wulf, AF5NE ", + " ", + NULL +}; + +#define NUM_WARNINGS 80 + +static char *ERROR4[NUM_WARNINGS]; + +static void +bwb_initialize_warnings (void) +{ + int i; + for (i = 0; i < NUM_WARNINGS; i++) + { + ERROR4[i] = NULL; + } + ERROR4[1] = "NEXT without FOR"; + ERROR4[2] = "Syntax error"; + ERROR4[3] = "RETURN without GOSUB"; + ERROR4[4] = "Out of DATA"; + ERROR4[5] = "Illegal function call"; + ERROR4[6] = "Overflow"; + ERROR4[7] = "Out of memory"; + ERROR4[8] = "Undefined line"; + ERROR4[9] = "Subscript out of range"; + ERROR4[10] = "Redimensioned array"; + ERROR4[11] = "Division by zero"; + ERROR4[12] = "Illegal direct"; + ERROR4[13] = "Type mismatch"; + ERROR4[14] = "Out of string space"; + ERROR4[15] = "String too long"; + ERROR4[16] = "String formula too complex"; + ERROR4[17] = "Can't continue"; + ERROR4[18] = "Undefined user function"; + ERROR4[19] = "No RESUME"; + ERROR4[20] = "RESUME without error"; + ERROR4[21] = "Unprintable error"; + ERROR4[22] = "Missing operand"; + ERROR4[23] = "Line buffer overflow"; + ERROR4[26] = "FOR without NEXT"; + ERROR4[27] = "Bad DATA"; + ERROR4[29] = "WHILE without WEND"; + ERROR4[30] = "WEND without WHILE"; + ERROR4[31] = "EXIT FUNCTION without FUNCTION"; + ERROR4[32] = "END FUNCTION without FUNCTION"; + ERROR4[33] = "EXIT SUB without SUB"; + ERROR4[34] = "END SUB without SUB"; + ERROR4[35] = "EXIT FOR without FOR"; + ERROR4[50] = "Field overflow"; + ERROR4[51] = "Internal error"; + ERROR4[52] = "Bad file number"; + ERROR4[53] = "File not found"; + ERROR4[54] = "Bad file mode"; + ERROR4[55] = "File already open"; + ERROR4[57] = "Disk I/O error"; + ERROR4[58] = "File already exists"; + ERROR4[61] = "Disk full"; + ERROR4[62] = "Input past end"; + ERROR4[63] = "Bad record number"; + ERROR4[64] = "Bad file name"; + ERROR4[66] = "Direct statement in file"; + ERROR4[67] = "Too many files"; + ERROR4[70] = "Variable Not Declared"; + ERROR4[73] = "Advanced Feature"; +} + +/*************************************************************** + + FUNCTION: bwx_terminate() + + DESCRIPTION: This function terminates program execution. + +***************************************************************/ + +void +bwx_terminate (void) +{ + + exit (0); +} + + + +/*************************************************************** + + FUNCTION: break_handler() + + DESCRIPTION: This function is called by break_mes() + and handles program interruption by break + (or by the STOP command). + +***************************************************************/ +static void +break_handler (void) +{ + /* + ** + ** + */ + assert( My != NULL ); + + My->AutomaticLineNumber = 0; + My->AutomaticLineIncrement = 0; + + if (My->IsInteractive) + { + /* INTERACTIVE: terminate program */ + + /* reset all stack counters */ + bwb_clrexec (); + SetOnError (0); + + My->ERR = -1; /* in break_handler() */ + + + /* reset the break handler */ + signal (SIGINT, break_mes); + + longjmp (My->mark, -1); + + + return; + } + /* NOT INTERACTIVE: terminate immediately */ + bwx_terminate (); +} + +/*************************************************************** + + FUNCTION: break_mes() + + DESCRIPTION: This function is called (a) by a SIGINT + signal or (b) by bwb_STOP via bwx_STOP. + It prints an error message then calls + break_handler() to terminate the program. + +***************************************************************/ + +static void +break_mes (int x /* Parameter 'x' is never used */ ) +{ + /* + ** + ** break_mes is FATAL. + ** x == SIGINT for control-C + ** x == 0 for bwx_STOP + ** + */ + assert( My != NULL ); + assert( My->SYSOUT != NULL ); + assert( My->SYSOUT->cfp != NULL ); + assert( My->CurrentVersion != NULL ); + + + if (My->ERR < 0) /* in break_mes(), do not make a bad situation worse */ + { + /* an error has already ben reported */ + } + else + { + fputc ('\n', My->SYSOUT->cfp); + ResetConsoleColumn (); + if (My->CurrentVersion->OptionVersionValue & (C77)) + { + if (is_empty_string (My->ProgramFilename) == FALSE) + { + fprintf (My->SYSOUT->cfp, "FILE:%s, ", My->ProgramFilename); + } + } + fprintf (My->SYSOUT->cfp, "Program interrupted"); + if (My->ThisLine) /* break_mes */ + { + if (My->ThisLine->LineFlags & (LINE_USER)) /* break_mes */ + { + /* don't print the line number */ + } + else + { + fprintf (My->SYSOUT->cfp, " at line %d", My->ThisLine->number); /* break_mes */ + } + } + fputc ('\n', My->SYSOUT->cfp); + ResetConsoleColumn (); + fflush (My->SYSOUT->cfp); + } + break_handler (); +} + +extern void +bwx_STOP (int IsShowMessage) +{ + + if (IsShowMessage) + { + break_mes (0); + } + else + { + break_handler (); + } +} + +static int +bwx_signon (void) +{ + /* + ** + ** Display a sign-on banner. + ** NOT called if a file is provided on the command line. + ** + */ + int i; + assert( My != NULL ); + assert( My->SYSOUT != NULL ); + assert( My->SYSOUT->cfp != NULL ); + + + for (i = 0; Banner[i] != NULL; i++) + { + fprintf (My->SYSOUT->cfp, "%s\n", Banner[i]); + } + ResetConsoleColumn (); + return TRUE; +} + + + +DoubleType +bwx_TIMER (DoubleType Seconds) +{ + /* + ** + ** Return a number representing Seconds in the future. Seconds >= 0. + ** Seconds may be non-integer, such as 0.001 or 86399.999. The + ** maximum allowed Seconds is MAXDBL. This is used two ways: + ** + ** 1) in bwb_TIMER(), the ON TIMER count (>0) is used to determine + ** the expiration time. In this case, simply return what the value + ** will be in the future. Note that ON TIMER enforces + ** Seconds > (1 / CLOCKS_PER_SEC), and + ** + ** 2) in bwb_execline(), zero (=0) is used to determine the current + ** time and compare it to #1. In this case, simply return what the + ** value is now. + ** + ** Both the resolution of the timer, and the frequency of update, + ** are implementation defined. + ** + */ + + if (Seconds < 0) + { + WARN_INTERNAL_ERROR; + return 0; + } + else + { + DoubleType Result; + Result = clock (); + assert (CLOCKS_PER_SEC > 0); + Result /= CLOCKS_PER_SEC; + if (Seconds > 0) + { + Result += Seconds; + } + return Result; + } +} + +void +CleanLine (char *buffer) +{ + /* + ** + ** cleanup the line, so it is easier to parse + ** + */ + char *newbuffer; + + + + if (is_empty_string (buffer)) + { + /* do nothing */ + return; + } + + /* remove CR/LF */ + newbuffer = bwb_strchr (buffer, '\r'); + if (newbuffer != NULL) + { + *newbuffer = NulChar; + } + newbuffer = bwb_strchr (buffer, '\n'); + if (newbuffer != NULL) + { + *newbuffer = NulChar; + } + + /* remove ALL embedded control characters */ + /* if you want a control character, then use CHR$ */ + newbuffer = buffer; + while (*newbuffer != NulChar) + { + if (bwb_isprint (*newbuffer)) + { + /* OK */ + } + else + { + *newbuffer = ' '; + } + newbuffer++; + } + /* LTRIM$ */ + newbuffer = buffer; + if (*newbuffer != NulChar) + { + /* not an empty line, so remove one (or more) leading spaces */ + while (*newbuffer == ' ') + { + newbuffer++; + } + if (newbuffer > buffer) + { + bwb_strcpy (buffer, newbuffer); + } + } + /* RTRIM$ */ + newbuffer = buffer; + if (*newbuffer != NulChar) + { + /* not an empty line, so remove one (or more) trailing spaces */ + char *E; + + E = bwb_strchr (newbuffer, NulChar); + E--; + while (E >= newbuffer && *E == ' ') + { + *E = NulChar; + E--; + } + } +} + +static int +bwb_init (void) +{ + /* + ** + ** initialize Bywater BASIC + ** + */ + int n; + static char start_buf[] = ""; + static char end_buf[] = ""; + + /* Memory allocation */ + if ((My = (GlobalType *) calloc (1, sizeof (GlobalType))) == NULL) + { + return FALSE; + } + if ((My->MaxLenBuffer = + (char *) calloc (MAXLEN + 1 /* NulChar */ , sizeof (char))) == NULL) + { + return FALSE; + } + if ((My->NumLenBuffer = + (char *) calloc (NUMLEN + 1 /* NulChar */ , sizeof (char))) == NULL) + { + return FALSE; + } + if ((My->ConsoleOutput = + (char *) calloc (MAX_LINE_LENGTH + 1 /* NulChar */ , + sizeof (char))) == NULL) + { + return FALSE; + } + if ((My->ConsoleInput = + (char *) calloc (MAX_LINE_LENGTH + 1 /* NulChar */ , + sizeof (char))) == NULL) + { + return FALSE; + } + if ((My->SYSIN = (FileType *) calloc (1, sizeof (FileType))) == NULL) + { + return FALSE; + } + if ((My->SYSOUT = (FileType *) calloc (1, sizeof (FileType))) == NULL) + { + return FALSE; + } + if ((My->SYSPRN = (FileType *) calloc (1, sizeof (FileType))) == NULL) + { + return FALSE; + } + if ((My->StartMarker = (LineType *) calloc (1, sizeof (LineType))) == NULL) + { + return FALSE; + } + if ((My->UserMarker = (LineType *) calloc (1, sizeof (LineType))) == NULL) + { + return FALSE; + } + if ((My->EndMarker = (LineType *) calloc (1, sizeof (LineType))) == NULL) + { + return FALSE; + } + if ((My->EndMarker = (LineType *) calloc (1, sizeof (LineType))) == NULL) + { + return FALSE; + } + if ((My->ERROR4 = + (char *) calloc (MAX_ERR_LENGTH + 1 /* NulChar */ , + sizeof (char))) == NULL) + { + return FALSE; + } + + My->CurrentVersion = &bwb_vertable[0]; + My->IsInteractive = TRUE; + My->OptionSleepDouble = 1; + My->OptionIndentInteger = 2; + My->OptionTerminalType = C_OPTION_TERMINAL_NONE; + My->OptionRoundType = C_OPTION_ROUND_BANK; + My->NextValidLineNumber = MINLIN; + My->IncludeLevel = 0; /* %INCLUDE */ + My->IsCommandLineFile = FALSE; + My->ExternalInputFile = NULL; /* for automated testing, --TAPE command line parameter */ + My->IsPrinter = FALSE; /* CBASIC-II: CONSOLE and LPRINTER commands */ + My->OptionPromptString = DEF_PROMPT; + My->OptionEditString = DEF_EDITOR; + My->OptionFilesString = DEF_FILES; + My->OptionRenumString = DEF_RENUM; + My->OptionExtensionString = DEF_EXTENSION; + My->OptionScaleInteger = 0; + My->OptionDigitsInteger = SIGNIFICANT_DIGITS; + My->OptionZoneInteger = ZONE_WIDTH; + My->UseParameterString = NULL; + My->ProgramFilename = NULL; + + My->StartMarker->number = MINLIN - 1; + My->StartMarker->next = My->EndMarker; + My->StartMarker->position = 0; + My->StartMarker->buffer = start_buf; + + My->EndMarker->number = MAXLIN + 1; + My->EndMarker->next = My->EndMarker; + My->EndMarker->position = 0; + My->EndMarker->buffer = end_buf; + + My->UserMarker->number = MINLIN - 1; + My->UserMarker->next = My->EndMarker; + My->UserMarker->position = 0; + My->UserMarker->buffer = NULL; + + My->DataLine = My->EndMarker; + My->DataPosition = 0; + + My->StackHead = NULL; + My->StackDepthInteger = 0; + + My->FieldHead = NULL; + + My->VirtualHead = NULL; + My->FileHead = NULL; + My->ThisLine = My->StartMarker; /* bwb_init */ + + My->SYSIN->DevMode = DEVMODE_INPUT; + My->SYSIN->width = 80; + My->SYSIN->col = 1; + My->SYSIN->row = 1; + My->SYSIN->delimit = ','; + My->SYSIN->cfp = stdin; + + My->SYSOUT->DevMode = DEVMODE_OUTPUT; + My->SYSOUT->width = 80; + My->SYSOUT->col = 1; + My->SYSOUT->row = 1; + My->SYSOUT->delimit = ','; + My->SYSOUT->cfp = stdout; + + My->SYSPRN->DevMode = DEVMODE_OUTPUT; + My->SYSPRN->width = 80; + My->SYSPRN->col = 1; + My->SYSPRN->row = 1; + My->SYSPRN->delimit = ','; + My->SYSPRN->cfp = stderr; + + My->LPRINT_NULLS = 0; + My->SCREEN_ROWS = 24; + + /* OPEN #0 is an ERROR. */ + /* CLOSE #0 is an ERROR. */ + /* WIDTH #0, 80 is the same as WIDTH 80. */ + /* LPRINT and LLIST are sent to bwx_LPRINT() */ + + /* default variable type */ + for (n = 0; n < 26; n++) + { + My->DefaultVariableType[n] = DoubleTypeCode; + } + /* default COMMAND$(0-9) */ + for (n = 0; n < 10; n++) + { + My->COMMAND4[n] = NULL; + } + + /* initialize tables of variables, functions */ + bwb_initialize_warnings (); + SortAllCommands (); + SortAllFunctions (); + SortAllOperators (); + var_init (); + IntrinsicFunction_init (); + UserFunction_init (); + OptionVersionSet (0); + /* OK */ + return TRUE; +} + +/*************************************************************** + + FUNCTION: main() + + DESCRIPTION: As in any C program, main() is the basic + function from which the rest of the + program is called. Some environments, + however, provide their own main() functions + (Microsoft Windows (tm) is an example). + In these cases, the following code will + have to be included in the initialization + function that is called by the environment. + +***************************************************************/ + +static void +process_basic_line (char *buffer) +{ + CleanLine (buffer); + if (is_empty_string (buffer)) + { + /* empty -- do nothing */ + } + else if (is_ln (buffer) == FALSE) + { + /* If there is no line number, then execute the line as received */ + /* RUN */ + WARN_CLEAR; /* process_basic_line */ + SetOnError (0); + bwb_xtxtline (buffer); /* process_basic_line */ + } + else if (is_numconst (buffer) == TRUE) + { + /*-----------------------------------------------------------------*/ + /* Another possibility: if buffer is a numeric constant, */ + /* then delete the indicated line number (JBV) */ + /*-----------------------------------------------------------------*/ + /* 100 */ + int LineNumber; + LineNumber = atoi (buffer); + WARN_CLEAR; /* process_basic_line */ + SetOnError (0); + sprintf (buffer, "delete %d", LineNumber); + bwb_xtxtline (buffer); /* process_basic_line */ + } + else + { + /* If there is a line number, then add it to the BASIC program */ + /* 100 REM */ + bwb_ladd (buffer, My->StartMarker, FALSE); + } +} +static void +bwb_single_step (char *buffer) +{ + assert( My != NULL ); + assert (buffer != NULL); + + process_basic_line (buffer); + while (My->StackHead != NULL) + { + bwb_execline (); + } +} + +static void +mark_preset_variables (void) +{ + /* mark all existing variables as preset */ + /* this includes all variables declared in any PROFILE */ + VariableType *v; + assert( My != NULL ); + + + for (v = My->VariableHead; v != NULL; v = v->next) + { + v->VariableFlags |= VARIABLE_PRESET; + v->VariableFlags |= VARIABLE_COMMON; + } +} + + +static void +execute_profile (char *FileName) +{ + FILE *profile; + assert( My != NULL ); + assert (FileName != NULL); + + My->NextValidLineNumber = MINLIN; + profile = fopen (FileName, "r"); + if (profile == NULL) + { + /* NOT FOUND */ + /* OPTIONAL */ + return; + } + /* FOUND */ + if (My->IsInteractive) + { + /* + ** + ** set a buffer for jump: program execution returns to this point in + ** case of a jump (error, interrupt, or finish program) + ** + */ + My->program_run = 0; + signal (SIGINT, break_mes); + setjmp (My->mark); + if (My->program_run > 0) + { + /* error in PROFILE */ + exit (1); + } + My->program_run++; + } + + /* + The profile only exists to allow executing OPTION ... commands. No other use is supported. + */ + { + char *tbuf; + int tlen; + + tbuf = My->ConsoleInput; + tlen = MAX_LINE_LENGTH; + while (fgets (tbuf, tlen, profile)) /* execute_profile */ + { + tbuf[tlen] = NulChar; + bwb_single_step (tbuf); /* in execute_profile() */ + } + bwb_fclose (profile); + mark_preset_variables (); + } +} + + + +static void +execute_program (char *FileName) +{ + assert( My != NULL ); + assert( My->SYSOUT != NULL ); + assert( My->SYSOUT->cfp != NULL ); + + assert (FileName != NULL); + + My->NextValidLineNumber = MINLIN; + My->IsCommandLineFile = TRUE; + if (bwb_fload (FileName) == FALSE) + { + fprintf (My->SYSOUT->cfp, "Failed to open file %s\n", FileName); + /* the file load has failed, so do NOT run the program */ + exit (1); + } + if (My->ERR < 0 /* in execute_program(), file load failed */ ) + { + /* the file load has failed, so do NOT run the program */ + exit (1); + } + bwb_RUN (My->StartMarker); +} + +extern int +main (int argc, char **argv) +{ + int i; + assert (argc >= 0); + assert (argv != NULL); + + if (bwb_init () == FALSE) + { + /* FATAL */ + puts ("Out of memory"); + return 1; + } + assert( My != NULL ); + assert( My->SYSOUT != NULL ); + assert( My->SYSOUT->cfp != NULL ); + assert( My->SYSIN != NULL ); + assert( My->SYSIN->cfp != NULL ); + + /* Signon message banner */ + if (argc < 2) + { + /* no parameters */ + if (My->IsInteractive) + { + bwx_signon (); + } + else + { + /* if INTERACTIVE is FALSE, then we must have a program file */ + fputs ("Program file not specified\n", My->SYSOUT->cfp); + return 1; + } + } + + if (My->IsInteractive) + { + /* + ** + ** set a buffer for jump: program execution returns to this point in + ** case of a jump (error, interrupt, or finish program) + ** + */ + My->program_run = 0; + signal (SIGINT, break_mes); + setjmp (My->mark); + if (My->program_run > 0) + { + /* error in profile */ + return 1; + } + My->program_run++; + } + +#if PROFILE + execute_profile (PROFILENAME); +#endif + + /* check to see if there is a program file: but do this only the first time around! */ + for (i = 1; i < argc; i++) + { + /* + SYNTAX: bwbasic [ --profile profile.bas ] [ --tape tapefile.inp ] [ program.bas ] + */ + if (bwb_stricmp (argv[i], "--profile") == 0 + || bwb_stricmp (argv[i], "-p") == 0 + || bwb_stricmp (argv[i], "/profile") == 0 + || bwb_stricmp (argv[i], "/p") == 0) + { + i++; + if (i < argc) + { + /* --profile profile.bas */ + execute_profile (argv[i]); + } + } + else + if (bwb_stricmp (argv[i], "--tape") == 0 + || bwb_stricmp (argv[i], "-t") == 0 + || bwb_stricmp (argv[i], "/tape") == 0 + || bwb_stricmp (argv[i], "/t") == 0) + { + i++; + if (i < argc) + { + /* --tape tapefile.inp */ + My->ExternalInputFile = fopen (argv[i], "r"); + } + } + else + { + /* program.bas */ + { + int j; + int n; + + j = i; + for (n = 0; n < 10 && j < argc; n++, j++) + { + My->COMMAND4[n] = argv[j]; + } + } + execute_program (argv[i]); + break; + } + } + + if (My->IsInteractive) + { + /* + ** + ** set a buffer for jump: program execution returns to this point in + ** case of a jump (error, interrupt, or finish program) + ** + */ + My->program_run = 0; + signal (SIGINT, break_mes); + setjmp (My->mark); + if (My->program_run > 0) + { + /* error in console mode */ + } + My->program_run++; + } + + /* main program loop */ + My->NextValidLineNumber = MINLIN; + while (!feof (My->SYSIN->cfp)) /* condition !feof( My->SYSIN->cfp ) added in v1.11 */ + { + bwb_mainloop (); + } + + bwx_terminate (); /* allow ^D (Unix) exit with grace */ + + return 0; +} + + + +/*************************************************************** + + FUNCTION: bwb_interact() + + DESCRIPTION: This function gets a line from the user + and processes it. + +***************************************************************/ + +static void +bwb_interact (void) +{ + char *tbuf; + int tlen; + assert( My != NULL ); + + + tbuf = My->ConsoleInput; + tlen = MAX_LINE_LENGTH; + My->NextValidLineNumber = MINLIN; + /* take input from keyboard */ + if (My->AutomaticLineNumber > 0 && My->AutomaticLineIncrement > 0) + { + /* AUTO 100, 10 */ + char *zbuf; /* end of the prompt, start of the response */ + int zlen; /* length of the prompt */ + char LineExists; + LineType *l; + + LineExists = ' '; + for (l = My->StartMarker->next; l != My->EndMarker; l = l->next) + { + if (l->number == My->AutomaticLineNumber) + { + /* FOUND */ + LineExists = '*'; + break; + } + else if (l->number > My->AutomaticLineNumber) + { + /* NOT FOUND */ + LineExists = ' '; + break; + } + } + sprintf (tbuf, "%d%c", My->AutomaticLineNumber, LineExists); + zbuf = bwb_strchr (tbuf, NulChar); + zlen = bwb_strlen (tbuf); + bwx_input (tbuf, FALSE, zbuf, tlen - zlen); + zbuf[-1] = ' '; /* remove LineExists indicator */ + CleanLine (zbuf); /* JBV */ + if (is_empty_string (zbuf)) + { + /* empty response */ + if (LineExists == '*') + { + /* + An empty response with an existing line, + causes AUTO to continue with the next line, + leaving the current line intact. + */ + My->AutomaticLineNumber += My->AutomaticLineIncrement; + } + else + { + /* + An empty response with a non-existing line, + causes AUTO to terminate. + */ + My->AutomaticLineNumber = 0; + My->AutomaticLineIncrement = 0; + } + } + else + { + /* non-empty response */ + if (bwb_stricmp (zbuf, "MAN") == 0) + { + /* MAN terminates AUTO mode */ + My->AutomaticLineNumber = 0; + My->AutomaticLineIncrement = 0; + } + else + { + /* overwrite any existing line */ + bwb_ladd (tbuf, My->StartMarker, FALSE); + My->AutomaticLineNumber += My->AutomaticLineIncrement; + } + } + } + else + { + bwx_input (My->OptionPromptString, FALSE, tbuf, tlen); + process_basic_line (tbuf); + } +} + + + +/*************************************************************** + + FUNCTION: bwb_fload() + + DESCRIPTION: This function loads a BASIC program + file into memory given a FILE pointer. + +***************************************************************/ + +static int +FixQuotes (char *tbuf) +{ + /* fix unbalanced quotes */ + /* 'tbuf' shall be declared "char tbuf[ tlen + 1]". */ + int p; + int QuoteCount; + int tlen; + assert( My != NULL ); + assert( My->CurrentVersion != NULL ); + + assert (tbuf != NULL); + + QuoteCount = 0; + tlen = MAX_LINE_LENGTH; + tbuf[tlen] = NulChar; + p = 0; + while (tbuf[p]) + { + if (tbuf[p] == My->CurrentVersion->OptionQuoteChar) + { + QuoteCount++; + } + p++; + } + if (QuoteCount & 1) + { + /* odd == missing trailing quote */ + if (p < tlen) + { + /* we have room to put the missig quote */ + tbuf[p] = My->CurrentVersion->OptionQuoteChar; + p++; + tbuf[p] = NulChar; + } + else + { + /* we cannot fix it */ + return FALSE; + } + } + /* OK */ + return TRUE; +} + +static FILE * +nice_open (char *BaseName) +{ + FILE *file; + assert( My != NULL ); + + if (BaseName == NULL) + { + BaseName = My->ProgramFilename; + } + if (is_empty_string (BaseName)) + { + WARN_BAD_FILE_NAME; + return NULL; + } + + file = fopen (BaseName, "r"); + if (file == NULL) + if (is_empty_string (My->OptionExtensionString) == FALSE) + { + char *FileName; + + FileName = bwb_strdup2 (BaseName, My->OptionExtensionString); + if (FileName == NULL) + { + WARN_OUT_OF_MEMORY; + return NULL; + } + file = fopen (FileName, "r"); + if (file == NULL) + { + free (FileName); + } + else if (BaseName == My->ProgramFilename) + { + if (My->ProgramFilename != NULL) + { + free (My->ProgramFilename); + } + My->ProgramFilename = FileName; + } + } + return file; +} + +extern int +bwb_fload (char *FileName) +{ + /* + ** + ** Load a BASIC program from the specified 'FileName'. + ** If 'FileName' is NULL, then load from My->ProgramFilename, + ** + */ + char *Magic_Word; /* SYNTAX: %INCLUDE literal.file.name */ + int Magic_Length; + FILE *file; + char *tbuf; + int tlen; + + + + + Magic_Word = "%INCLUDE "; /* SYNTAX: %INCLUDE literal.file.name */ + Magic_Length = bwb_strlen (Magic_Word); + tbuf = My->MaxLenBuffer; + tlen = MAXLEN; + + + /* + Just in case you are wondering... + Although this handles the most common cases, it does not handle all possible cases. + The correct solution is to provide the actual filename (with extension), + as it exists in the operating system. + */ + file = nice_open (FileName); + if (file == NULL) + { + WARN_BAD_FILE_NAME; + return FALSE; + } + My->NextValidLineNumber = MINLIN; + while (fgets (tbuf, tlen, file)) /* bwb_fload */ + { + tbuf[tlen] = NulChar; + CleanLine (tbuf); + if (is_empty_string (tbuf)) + { + /* ignore */ + } + else if (bwb_strnicmp (tbuf, Magic_Word, Magic_Length) == 0) + { + /* %iNCLUDE */ + int Result; + int p; + char varname[NameLengthMax + 1]; + + p = Magic_Length; + if (buff_read_varname (tbuf, &p, varname) == FALSE) + { + fprintf (My->SYSOUT->cfp, "%s Filename\n", Magic_Word); + ResetConsoleColumn (); + return FALSE; + } + My->IncludeLevel++; /* %INCLUDE */ + Result = bwb_fload (varname); + My->IncludeLevel--; /* %INCLUDE */ + if (Result == FALSE) + { + fprintf (My->SYSOUT->cfp, "%s %s Failed\n", Magic_Word, varname); + ResetConsoleColumn (); + return FALSE; + } + } + else + { + /* normal */ + bwb_ladd (tbuf, My->StartMarker, FALSE); + } + } + + /* close file stream */ + + bwb_fclose (file); /* file != NULL */ + + My->NextValidLineNumber = MINLIN; + + return TRUE; +} + + +static char * +FindClassicStatementEnd (char *C) +{ + /* + ** find the end of the current statement + */ + assert( My != NULL ); + assert( My->CurrentVersion != NULL ); + + assert (C != NULL); + + + if (My->CurrentVersion->OptionStatementChar == NulChar + && My->CurrentVersion->OptionCommentChar == NulChar) + { + /* DO NOTHING: Multi-statment lines are not possible */ + return NULL; + } + /* skip line number */ + while (bwb_isdigit (*C)) + { + C++; + } + /* skip spaces */ + while (*C == ' ') + { + C++; + } + if (IS_CHAR (*C, My->CurrentVersion->OptionCommentChar)) + { + /* The entire line is a comment */ + return NULL; + } + if (bwb_strnicmp (C, "REM", 3) == 0) + { + /* The entire line is a comment */ + return NULL; + } + if ((My->CurrentVersion->OptionFlags & OPTION_LABELS_ON) + && (My->CurrentVersion->OptionStatementChar != NulChar)) + { + /* determine if this line is a LABEL */ + int p; + char label[NameLengthMax + 1]; + + p = 0; + if (buff_read_label (C, &p, label)) + { + if (buff_skip_char (C, &p, My->CurrentVersion->OptionStatementChar)) + { + if (buff_is_eol (C, &p)) + { + /* The entire line is a label */ + /* LABEL : \0 */ + return NULL; + } + } + } + } + /* not a special case, so split on the first unquoted OptionCommentChar or OptionStatementChar */ + while (*C != NulChar) + { + if (*C == My->CurrentVersion->OptionQuoteChar) + { + /* skip leading quote */ + C++; + while (*C != NulChar && *C != My->CurrentVersion->OptionQuoteChar) + { + /* skip string constant */ + C++; + } + if (*C == My->CurrentVersion->OptionQuoteChar) + { + /* skip trailing quote */ + C++; + } + } + else if (IS_CHAR (*C, My->CurrentVersion->OptionCommentChar) /* ', ! */ ) + { + /* FOUND */ + return C; + } + else + if (IS_CHAR (*C, My->CurrentVersion->OptionStatementChar) /* :, \ */ ) + { + /* FOUND */ + return C; + } + else + { + C++; + } + } + /* NOT FOUND */ + return NULL; +} + + +static void +ImportClassicIfThenElse (char *InBuffer) +{ +/* +** +** Determine the type of IF command: +** +** a) STANDARD: +** IF x THEN line ELSE line +** +** b) CLASSIC: +** IF x THEN stmt(s) ELSE stmt(s) +** +** c) STRUCTURED: +** IF x THEN +** stmts +** ELSE +** stmts +** END IF +** +** The STANDARD and STRUCTURED forms +** are natively supported. +** +** The CLASSIC form is converted to +** the STRUCTURED form. +** +*/ + + int i; + + int nIF = 0; + int nTHEN = 0; + int nELSE = 0; + int nENDIF = 0; + +#define NO_COMMAND 0 +#define IF_COMMAND 1 +#define THEN_COMMAND 2 +#define ELSE_COMMAND 3 +#define ENDIF_COMMAND 4 + int LastCommand = NO_COMMAND; + + const char *REM = "REM "; + const char *IF = "IF "; + const char *THEN = "THEN "; + const char *THEN2 = "THEN"; + const char *ELSE = "ELSE "; + const char *ENDIF = "END IF"; + const char *GOTO = "GOTO "; + const char *DATA = "DATA "; + const char *CASE = "CASE "; + char *OutBuffer = My->ConsoleOutput; + char *Input; + char *Output; + char LastChar = My->CurrentVersion->OptionStatementChar; + + int REM_len = bwb_strlen (REM); + int IF_len = bwb_strlen (IF); + int THEN_len = bwb_strlen (THEN); + int THEN2_len = bwb_strlen (THEN2); + int ELSE_len = bwb_strlen (ELSE); + int ENDIF_len = bwb_strlen (ENDIF); + int GOTO_len = bwb_strlen (GOTO); + int DATA_len = bwb_strlen (DATA); + int CASE_len = bwb_strlen (CASE); + +#define OUTPUTCHAR( c ) { *Output = c; Output++; } +#define COPYCHAR { LastChar = *Input; *Output = *Input; Output++; Input++; } +#define COPY_LINENUMBER while( bwb_isdigit( *Input ) ) COPYCHAR; +#define COPY_SPACES while( *Input == ' ' ) COPYCHAR; +#define COPY_IF for( i = 0; i < IF_len; i++ ) COPYCHAR; +#define COPY_THEN for( i = 0; i < THEN_len; i++ ) COPYCHAR; +#define COPY_THEN2 for( i = 0; i < THEN2_len; i++ ) COPYCHAR; +#define COPY_ELSE for( i = 0; i < ELSE_len; i++ ) COPYCHAR; +#define COPY_ENDIF for( i = 0; i < ENDIF_len; i++ ) COPYCHAR; +#define FORCE_ENDIF for( i = 0; i < ENDIF_len; i++ ) OUTPUTCHAR( ENDIF[ i ] ); +#define FORCE_GOTO for( i = 0; i < GOTO_len; i++ ) OUTPUTCHAR( GOTO[ i ] ); +#define FORCE_COLON if( LastChar != My->CurrentVersion->OptionStatementChar ) OUTPUTCHAR( My->CurrentVersion->OptionStatementChar ); + + assert( My != NULL ); + assert( My->CurrentVersion != NULL ); + assert (InBuffer != NULL); + + + Input = InBuffer; + Output = OutBuffer; + + + + + + if (My->CurrentVersion->OptionStatementChar == NulChar) + { + /* DO NOTHING: All IFs must be STANDARD or STRUCTURED */ + return; + } + + + COPY_LINENUMBER; + COPY_SPACES; + LastChar = My->CurrentVersion->OptionStatementChar; + + + while (*Input != NulChar) + { + if (*Input == My->CurrentVersion->OptionCommentChar) + { + /* comment */ + break; + } + else if (*Input == My->CurrentVersion->OptionQuoteChar) + { + /* string constant */ + COPYCHAR; + while (*Input != NulChar + && *Input != My->CurrentVersion->OptionQuoteChar) + { + COPYCHAR; + } + if (*Input == My->CurrentVersion->OptionQuoteChar) + { + COPYCHAR; + } + else + { + /* add missing Quote */ + OUTPUTCHAR (My->CurrentVersion->OptionQuoteChar); + } + COPY_SPACES; + } + else if (bwb_isalnum (LastChar)) + { + /* can NOT be the start of a command */ + COPYCHAR; + } + else if (!bwb_isalpha (*Input)) + { + /* can NOT be the start of a command */ + COPYCHAR; + } + else if (bwb_strnicmp (Input, REM, REM_len) == 0) + { + break; + } + else if (bwb_strnicmp (Input, DATA, DATA_len) == 0) + { + /* DATA ... */ + break; + } + else if (bwb_strnicmp (Input, CASE, CASE_len) == 0) + { + /* CASE ... */ + break; + } + else if (bwb_strnicmp (Input, IF, IF_len) == 0) + { + /* IF */ + LastCommand = IF_COMMAND; + nIF++; + COPY_IF; + COPY_SPACES; + } + else if (bwb_strnicmp (Input, GOTO, GOTO_len) == 0 && nIF > nTHEN) + { + /* IF x GOTO line ELSE line */ + LastCommand = THEN_COMMAND; + nTHEN++; + COPY_THEN; + COPY_SPACES; + COPY_LINENUMBER; + COPY_SPACES; + if (bwb_strnicmp (Input, ELSE, ELSE_len) == 0) + { + /* ELSE line */ + COPY_ELSE; + COPY_SPACES; + COPY_LINENUMBER; + COPY_SPACES; + } + /* IS STANDARD, NOT CLASSIC */ + nENDIF++; + LastCommand = ENDIF_COMMAND; + } + else if (bwb_strnicmp (Input, THEN, THEN_len) == 0) + { + /* THEN */ + LastCommand = THEN_COMMAND; + nTHEN++; + COPY_THEN; + COPY_SPACES; + if (bwb_isdigit (*Input)) + { + /* STANDARD: IF x THEN line ELSE line */ + char *SavedInput; + char *SavedOutput; + SavedInput = Input; + SavedOutput = Output; + + COPY_LINENUMBER; + COPY_SPACES; + if (bwb_strnicmp (Input, ELSE, ELSE_len) == 0) + { + /* ELSE line */ + COPY_ELSE; + COPY_SPACES; + if (bwb_isdigit (*Input)) + { + COPY_LINENUMBER; + COPY_SPACES; + /* IS STANDARD, NOT CLASSIC */ + nENDIF++; + LastCommand = ENDIF_COMMAND; + } + else + { + /* IF x THEN line ELSE stmts */ + Input = SavedInput; + Output = SavedOutput; + FORCE_COLON; + FORCE_GOTO; + COPY_LINENUMBER; + COPY_SPACES; + } + } + else + { + /* IS STANDARD, NOT CLASSIC */ + nENDIF++; + LastCommand = ENDIF_COMMAND; + } + } + else + if (*Input == My->CurrentVersion->OptionCommentChar + || *Input == NulChar) + { + /* IS STRUCTURED, NOT CLASSIC */ + nENDIF++; + LastCommand = ENDIF_COMMAND; + } + else + { + /* CLASSIC: IF x THEN stmts ELSE stmts */ + } + FORCE_COLON; + } + else if (bwb_strnicmp (Input, THEN2, THEN2_len) == 0) + { + /* trailing THEN ? */ + char *PeekInput; + + PeekInput = Input; + PeekInput += THEN2_len; + while (*PeekInput == ' ') + { + PeekInput++; + } + if (*PeekInput == My->CurrentVersion->OptionCommentChar + || *PeekInput == NulChar) + { + /* IS STRUCTURED, NOT CLASSIC */ + nTHEN++; + COPY_THEN2; + nENDIF++; + LastCommand = ENDIF_COMMAND; + FORCE_COLON; + } + else + { + /* THEN line */ + } + } + else if (bwb_strnicmp (Input, ELSE, ELSE_len) == 0) + { + /* ELSE */ + if (LastCommand == ELSE_COMMAND) + { + /* we need an ENDIF here */ + FORCE_COLON; + FORCE_ENDIF; + FORCE_COLON; + nENDIF++; + } + LastCommand = ELSE_COMMAND; + nELSE++; + FORCE_COLON; + COPY_ELSE; + FORCE_COLON; + COPY_SPACES; + if (bwb_isdigit (*Input)) + { + /* IF x THEN stmts ELSE line */ + FORCE_GOTO; + COPY_LINENUMBER; + COPY_SPACES; + } + FORCE_COLON; + } + else if (bwb_strnicmp (Input, ENDIF, ENDIF_len) == 0) + { + /* ENDIF */ + LastCommand = ENDIF_COMMAND; + nENDIF++; + COPY_ENDIF; + FORCE_COLON; + } + else + { + /* was NOT the start of a command */ + COPYCHAR; + } + } + /* end of input */ + if (nENDIF < nIF) + { + while (nENDIF < nIF) + { + /* we need trailing ENDIF's */ + nENDIF++; + FORCE_COLON; + FORCE_ENDIF; + } + } + /* fixup trailing REMark command */ + if (bwb_strnicmp (Input, REM, REM_len) == 0) + { + /* REMark */ + /* 100 A=1 REMark */ + /* 100 A=1:REMark */ + /* 100 A=1'REMark */ + FORCE_COLON; + } + /* copy the comments */ + while (*Input != NulChar) + { + COPYCHAR; + /* cppcheck: (style) Variable 'LastChar' is assigned a value that is never used. */ + } + OUTPUTCHAR (NulChar); + bwb_strcpy (InBuffer, OutBuffer); +} + + +/*************************************************************** + + FUNCTION: bwb_ladd() + + DESCRIPTION: This function adds a new line (in the + buffer) to the program in memory. + +***************************************************************/ +static int +bwb_ladd (char *buffer, LineType * p, int IsUser) +{ + LineType *l; + LineType *previous; + char *newbuffer; + char *NextStatement; + char *ThisStatement; + int Replace; + char BreakChar; + + assert( My != NULL ); + assert( My->SYSOUT != NULL ); + assert( My->SYSOUT->cfp != NULL ); + assert( My->CurrentVersion != NULL ); + assert (buffer != NULL); + assert (p != NULL); + + + Replace = TRUE; + BreakChar = NulChar; + CleanLine (buffer); + if (is_empty_string (buffer)) + { + /* silengtly ignore blank lines */ + return FALSE; + } + /* + from here, the line WILL be added so the user can EDIT it, + we just complain and refuse to run if any error is detected. + */ + My->IsScanRequired = TRUE; /* program needs to be scanned again */ + + /* AUTO-FIX UNBALANCED QUOTES */ + if (FixQuotes (buffer) == FALSE) + { + /* ERROR */ + fprintf (My->SYSOUT->cfp, "UNBALANCED QUOTES: %s\n", buffer); + ResetConsoleColumn (); + My->ERR = -1; /* bwb_ladd, UNBALANCED QUOTES */ + } + + if (IS_CHAR (*buffer, My->CurrentVersion->OptionStatementChar)) + { + /* part of a multi-statement line */ + } + else if (IS_CHAR (*buffer, My->CurrentVersion->OptionCommentChar)) + { + /* part of a multi-statement line */ + } + else + { + ImportClassicIfThenElse (buffer); + } + ThisStatement = buffer; + NextStatement = NULL; + BreakChar = NulChar; + + do + { + if (BreakChar == NulChar) + { + /* first pass thru the do{} while loop, do nothing */ + } + else if (IS_CHAR (BreakChar, My->CurrentVersion->OptionCommentChar)) + { + /* ThisStatment will turn out to be the last */ + *ThisStatement = My->CurrentVersion->OptionCommentChar; + } + else if (IS_CHAR (BreakChar, My->CurrentVersion->OptionStatementChar)) + { + /* we are NOT the last statement, skip over the OptionStatementChar */ + ThisStatement++; + } + else + { + /* Internal Error */ + } + + if (BreakChar == NulChar + && IS_CHAR (*buffer, My->CurrentVersion->OptionStatementChar)) + { + /* first pass thru and line begins with colon */ + /* part of a multi-statement line */ + NextStatement = NULL; + if (My->NextValidLineNumber > 1) + { + My->NextValidLineNumber--; + } + Replace = FALSE; + } + else + if (BreakChar == NulChar + && IS_CHAR (*buffer, My->CurrentVersion->OptionCommentChar)) + { + /* first pass thru and line begins with apostrophe */ + /* part of a multi-statement line */ + NextStatement = NULL; + if (My->NextValidLineNumber > 1) + { + My->NextValidLineNumber--; + } + Replace = FALSE; + } + else + { + NextStatement = FindClassicStatementEnd (ThisStatement); + } + + if (NextStatement == NULL) + { + /* we are the last statement */ + } + else + { + /* another statement follows */ + BreakChar = *NextStatement; + *NextStatement = NulChar; + } + CleanLine (ThisStatement); + if (is_empty_string (ThisStatement) == FALSE) + { + + /* get memory for this line */ + if ((l = (LineType *) calloc (1, sizeof (LineType))) == NULL) + { + /* ERROR */ + fprintf (My->SYSOUT->cfp, "Out of memory\n"); + ResetConsoleColumn (); + My->ERR = -1; /* bwb_ladd, Out of memory */ + return FALSE; + } + + /* this line has not been executed or numbered */ + l->LineFlags = 0; + if (IsUser) + { + l->LineFlags |= LINE_USER; + } + l->IncludeLevel = My->IncludeLevel; /* %INCLUDE */ + l->position = 0; + + /* + ** + ** ALL lines have a line number. + ** If a line number is not provided, + ** then the next available line number is assigned. + ** + */ + newbuffer = ThisStatement; + l->number = My->NextValidLineNumber; + + if (buff_read_line_number (newbuffer, &(l->position), &l->number)) + { + if (l->number < My->NextValidLineNumber) + { + /* ERROR */ + fprintf (My->SYSOUT->cfp, "%d < %d - LINE OUT OF ORDER: %s\n", + l->number, My->NextValidLineNumber, buffer); + ResetConsoleColumn (); + My->ERR = -1; /* bwb_ladd, LINE OUT OF ORDER */ + l->number = My->NextValidLineNumber; /* sane default */ + } + else if (l->number < MINLIN || l->number > MAXLIN) + { + /* ERROR */ + fprintf (My->SYSOUT->cfp, "INVALID LINE NUMBER: %s\n", buffer); + ResetConsoleColumn (); + My->ERR = -1; /* bwb_ladd, INVALID LINE NUMBER */ + l->number = My->NextValidLineNumber; /* sane default */ + } + else + { + /* OK */ + My->NextValidLineNumber = l->number; + l->LineFlags |= LINE_NUMBERED; /* line was manually numbered */ + } + /* A SPACE IS REQUIRED AFTER THE LINE NUMBER -- NO EXCEPTIONS */ + if (newbuffer[l->position] != ' ') + { + /* ERROR */ + fprintf (My->SYSOUT->cfp, "MISSING SPACE AFTER LINE NUMBER: %s\n", + buffer); + ResetConsoleColumn (); + My->ERR = -1; /* bwb_ladd, MISSING SPACE AFTER LINE NUMBER */ + } + /* newuffer does NOT contain the line number */ + newbuffer += l->position; + } + /* the next valid line number is this line number plus one */ + CleanLine (newbuffer); + if (*newbuffer != NulChar + && *newbuffer == My->CurrentVersion->OptionStatementChar) + { + /* this is part of a multi-statement line */ + newbuffer++; + CleanLine (newbuffer); + } + /* + ** + ** copy into the line buffer + ** + */ + if (l->buffer != NULL) + { + free (l->buffer); + l->buffer = NULL; /* JBV */ + } + if ((l->buffer = + (char *) calloc (bwb_strlen (newbuffer) + 1 /* NulChar */ , + sizeof (char))) == NULL) + { + /* ERROR */ + fprintf (My->SYSOUT->cfp, "Out of memory\n"); + ResetConsoleColumn (); + My->ERR = -1; /* bwb_ladd, Out of memory */ + return FALSE; /* we cannot determine the command */ + } + bwb_strcpy (l->buffer, newbuffer); + /* + ** + ** determine command + ** + */ + line_start (l); + if (l->cmdnum) + { + /* OK */ + } + else + { + /* ERROR */ + fprintf (My->SYSOUT->cfp, + "ILLEGAL COMMAND AFTER LINE NUMBER: %d %s\n", l->number, + l->buffer); + ResetConsoleColumn (); + My->ERR = -1; /* bwb_ladd, ILLEGAL COMMAND AFTER LINE NUMBER */ + } + /* + ** + ** add the line to the linked-list of lines + ** + */ + for (previous = p; previous != My->EndMarker; previous = previous->next) + { + if (previous->number == l->number) + { + if (Replace == TRUE) + { + /* REPLACE 'previous' */ + while (previous->number == l->number) + { + LineType *z; + + z = previous; + previous = previous->next; + bwb_freeline (z); + } + l->next = previous; + p->next = l; + + } + else + { + /* APPEND after 'previous' */ + while (previous->next->number == l->number) + { + previous = previous->next; + } + l->next = previous->next; + previous->next = l; + } + break; + } + else + if (previous->number < l->number + && l->number < previous->next->number) + { + /* INSERT BETWEEN 'previous' AND 'previous->next' */ + l->next = previous->next; + previous->next = l; + break; + } + p = previous; + } + + } + /* another statement may follow */ + ThisStatement = NextStatement; + Replace = FALSE; + } + while (ThisStatement != NULL); + My->NextValidLineNumber++; + return TRUE; +} + +/*************************************************************** + + FUNCTION: bwb_xtxtline() + + DESCRIPTION: This function executes a text line, i.e., + places it in memory and then relinquishes + control. + +***************************************************************/ + +static void +bwb_xtxtline (char *buffer) +{ + assert( My != NULL ); + assert (buffer != NULL); + + /* remove old program from memory */ + bwb_xnew (My->UserMarker); + + CleanLine (buffer); + if (is_empty_string (buffer)) + { + /* silengtly ignore blank lines */ + return; + } + + /* add to the user line list */ + bwb_ladd (buffer, My->UserMarker, TRUE); + + /* execute the line as BASIC command line */ + if (bwb_incexec ()) + { + My->StackHead->line = My->UserMarker->next; /* and set current line in it */ + My->StackHead->ExecCode = EXEC_NORM; + } +} + +/*************************************************************** + + FUNCTION: bwb_incexec() + + DESCRIPTION: This function increments the EXEC + stack counter. + +***************************************************************/ + +int +bwb_incexec (void) +{ + StackType *StackItem; + assert( My != NULL ); + + + if (My->StackDepthInteger >= EXECLEVELS) + { + WARN_OUT_OF_MEMORY; + return FALSE; + } + if ((StackItem = (StackType *) calloc (1, sizeof (StackType))) == NULL) + { + WARN_OUT_OF_MEMORY; + return FALSE; + } + StackItem->ExecCode = EXEC_NORM; /* sane default */ + StackItem->line = My->ThisLine; /* bwb_incexec */ + StackItem->LoopTopLine = NULL; + StackItem->local_variable = NULL; + StackItem->OnErrorGoto = 0; + StackItem->next = My->StackHead; + My->StackHead = StackItem; + My->StackDepthInteger++; + return TRUE; +} + +/*************************************************************** + + FUNCTION: bwb_decexec() + + DESCRIPTION: This function decrements the EXEC + stack counter. + +***************************************************************/ +void +bwb_clrexec (void) +{ + assert( My != NULL ); + + while (My->StackHead != NULL) + { + bwb_decexec (); + } +} + +void +bwb_decexec (void) +{ + StackType *StackItem; + assert( My != NULL ); + + + if (My->StackHead == NULL) + { + WARN_RETURN_WITHOUT_GOSUB; + return; + } + StackItem = My->StackHead; + My->StackHead = StackItem->next; + free (StackItem); + My->StackDepthInteger--; +} + +/*************************************************************** + + FUNCTION: bwb_mainloop() + + DESCRIPTION: This C function performs one iteration + of the interpreter. In a non-preemptive + scheduler, this function should be called + by the scheduler, not by bwBASIC code. + +***************************************************************/ + +void +bwb_mainloop (void) +{ + assert( My != NULL ); + + + if (My->StackHead) + { + /* BASIC program running */ + bwb_execline (); /* execute one line of program */ + return; + } + /* BASIC program completed */ + + if (My->ExternalInputFile != NULL) + { + /* for automated testing, --TAPE command line parameter */ + if (bwb_is_eof (My->ExternalInputFile) == FALSE) + { + /* --TAPE command line parameter is active */ + bwb_interact (); /* get user interaction */ + return; + } + } + /* TAPE command inactive or completed */ + + if (My->IsCommandLineFile) + { + /* BASIC program was started from command line */ + bwx_terminate (); + return; + } + /* BASIC program was not started from command line */ + + if (My->IsInteractive) + { + /* interactive */ + bwb_interact (); /* get user interaction */ + return; + } + /* non-interactive */ + + bwx_terminate (); +} + +/*************************************************************** + + FUNCTION: bwb_execline() + + DESCRIPTION: This function executes a single line of + a program in memory. This function is + called by bwb_mainloop(). + +***************************************************************/ + +extern int +bwx_Error (int ERR, char *ErrorMessage) +{ + /* + ERR is the error number + ErrorMessage is used to override the default error message, and is usually NULL + */ + assert( My != NULL ); + + switch (ERR) + { + case 0: + /* + ** + ** Clear any existing error + ** + */ + My->IsErrorPending = FALSE; /* bwx_Error, ERR == 0 */ + My->ERR = 0; /* bwx_Error, ERR == 0 */ + My->ERL = NULL; /* bwx_Error, ERR == 0 */ + bwb_strcpy (My->ERROR4, ""); /* bwx_Error, ERR == 0 */ + return FALSE; + case 6: /* WARN_OVERFLOW */ + case 11: /* WARN_DIVISION_BY_ZERO */ + case 15: /* WARN_STRING_TOO_LONG */ + /* + ** + ** Behavior depends upon whether an Error handler is active. + ** + */ + if (GetOnError () == 0) + { + /* + ** + ** Error handler is NOT active. + ** Do NOT set ERL, ERR, and ERROR$. + ** Continue processing. + ** + */ + if (ErrorMessage == NULL) + { + /* use the default error message */ + if (ERR > 0 && ERR < NUM_WARNINGS) + { + ErrorMessage = ERROR4[ERR]; + } + } + if (ErrorMessage != NULL) + { + if (bwb_strlen (ErrorMessage) > 0) + { + fprintf (My->SYSOUT->cfp, "%s\n", ErrorMessage); + ResetConsoleColumn (); + } + } + return FALSE; /* continue processing */ + } + /* + ** + ** Error handler IS active. + ** Fall-thru to set ERL, ERR, and ERROR$. + ** Abort processing. + ** + */ + } + if (My->IsErrorPending == FALSE) /* no errors pending */ + { + /* + ** + ** only keep the first pending error to occur + ** + */ + My->IsErrorPending = TRUE; /* bwx_Error, ERR != 0 */ + My->ERR = ERR; /* bwx_Error, ERR != 0 */ + My->ERL = NULL; /* bwx_Error, ERR != 0 */ + bwb_strcpy (My->ERROR4, ""); /* bwx_Error, ERR != 0 */ + if (My->StackHead) + { + My->ERL = My->StackHead->line; + } + if (ErrorMessage == NULL) + { + /* use the default error message */ + if (ERR > 0 && ERR < NUM_WARNINGS) + { + ErrorMessage = ERROR4[ERR]; + } + } + if (ErrorMessage != NULL) + { + if (bwb_strlen (ErrorMessage) > MAX_ERR_LENGTH) + { + ErrorMessage[MAX_ERR_LENGTH] = NulChar; + } + bwb_strcpy (My->ERROR4, ErrorMessage); + } + } + return TRUE; /* abort processing */ +} + +void +bwb_execline (void) +{ + LineType *r, *l; + assert( My != NULL ); + assert( My->SYSOUT != NULL ); + assert( My->SYSOUT->cfp != NULL ); + assert( My->CurrentVersion != NULL ); + + if (My->StackHead == NULL) /* in bwb_execline(), FATAL ERROR PENDING */ + { + return; + } + + l = My->StackHead->line; + + /* if the line is My->EndMarker, then break out of EXEC loops */ + if (l == NULL || l == My->EndMarker || My->ERR < 0) /* in bwb_execline(), FATAL ERROR PENDING */ + { + bwb_clrexec (); + return; + } + + My->ThisLine = l; /* bwb_execline */ + + /* Print line number if trace is on */ + if (My->IsTraceOn == TRUE) + { + if (l->LineFlags & (LINE_USER)) + { + /* USER line in console */ + } + else if (l->number > 0) + { + fprintf (My->SYSOUT->cfp, "[ %d %s ]", l->number, l->buffer); + } + } + l->position = l->Startpos; + + /* if there is a BASIC command in the line, execute it here */ + if (l->cmdnum) + { + /* OK */ + } + else + { + WARN_ILLEGAL_DIRECT; + l->cmdnum = C_REM; + } + /* l->cmdnum != 0 */ + + if (l->LineFlags & LINE_BREAK) + { + /* BREAK line */ + l->LineFlags &= ~LINE_BREAK; + My->ContinueLine = l; + bwx_STOP (TRUE); + return; + } + + /* advance beyond whitespace */ + line_skip_spaces (l); /* keep this */ + + /* execute the command vector */ + if (My->CurrentVersion->OptionFlags & (OPTION_COVERAGE_ON)) + { + /* We do this here so "END" and "STOP" are marked */ + if (l->cmdnum == C_DATA) + { + /* DATA lines are marked when they are READ */ + } + else + { + /* this line was executed */ + l->LineFlags |= LINE_EXECUTED; + } + } + r = bwb_vector (l); + if (r == NULL) + { + WARN_INTERNAL_ERROR; + return; + } + assert (r != NULL); + + if (My->ERR < 0) /* in bwb_execline(), FATAL ERROR PENDING */ + { + /* FATAL */ + bwb_clrexec (); + return; + } + + if (My->IsErrorPending /* Keep This */ ) + { + /* we are probably not at the end-of-the-line */ + } + else if (r == l) + { + /* we should be at the end-of-the-line */ + if (line_is_eol (l)) + { + /* OK */ + } + else + { + WARN_SYNTAX_ERROR; + return; + } + } + else + { + /* we are probably not at the end-of-the-line */ + } + + if (My->IsErrorPending /* Keep This */ ) + { + /* + ** + ** a NON-FATAL ERROR has occurred. ERR, ERL, and ERROR$ were + ** already set using bwb_warning(ERR,ERROR$) + ** + */ + int err_gotol; + My->IsErrorPending = FALSE; /* Error Recognized */ + err_gotol = GetOnError (); + if (l->LineFlags & (LINE_USER)) + { + /* + ** + ** ------------------------------------------------------------------------- + ** USER line in console + ** ------------------------------------------------------------------------- + ** + ** fall thru to the DEFAULT ERROR HANDLER + ** + */ + } + else if (l->number == 0) + { + /* fall thru to the DEFAULT ERROR HANDLER */ + } + else if (My->ERL == NULL) + { + /* fall thru to the DEFAULT ERROR HANDLER */ + } + else if (My->ERL->number == 0) + { + /* fall thru to the DEFAULT ERROR HANDLER */ + } + else if (err_gotol == -1) + { + /* + ** + ** ------------------------------------------------------------------------- + ** ON ERROR RESUME NEXT + ** ------------------------------------------------------------------------- + ** + */ + assert (r != NULL); + assert (r->next != NULL); + + r->next->position = 0; + assert (My->StackHead != NULL); + My->StackHead->line = r->next; + return; + } + else if (err_gotol == 0) + { + /* + ** + ** ------------------------------------------------------------------------- + ** ON ERROR GOTO 0 + ** ------------------------------------------------------------------------- + ** + ** fall thru to the DEFAULT ERROR HANDLER + ** + */ + } + else if (err_gotol == My->ERL->number) + { + /* + ** + ** ------------------------------------------------------------------------- + ** RECURSION + ** ------------------------------------------------------------------------- + ** + ** For example: + ** 10 ON ERROR GOTO 20 + ** 20 ERROR 1 + ** + ** fall thru to the DEFAULT ERROR HANDLER + ** + */ + } + else + { + /* USER ERROR HANDLER SPECIFIED */ + /* find the user-specified error handler and jump there */ + LineType *x; + for (x = My->StartMarker->next; x != My->EndMarker; x = x->next) + { + if (x->number == err_gotol) + { + /* FOUND */ + if (My->CurrentVersion->OptionFlags & (OPTION_ERROR_GOSUB)) + { + /* + ** + ** ------------------------------------------------------------------------- + ** OPTION ERROR GOSUB + ** ------------------------------------------------------------------------- + ** + ** RETURN should act like RESUME NEXT... + ** Execution resumes at the statement immediately following the one which caused the error. + ** For structured commands, this is the bottom line of the structure. + ** + */ + switch (l->cmdnum) + { + case C_IF8THEN: + /* skip to END_IF */ + assert (l->OtherLine != NULL); + for (l = l->OtherLine; l->cmdnum != C_END_IF; l = l->OtherLine); + break; + case C_SELECT_CASE: + /* skip to END_SELECT */ + assert (l->OtherLine != NULL); + for (l = l->OtherLine; l->cmdnum != C_END_SELECT; + l = l->OtherLine); + break; + default: + l = l->next; + } + l->position = 0; + My->StackHead->line = l; + if (bwb_incexec ()) + { + x->position = 0; + assert (My->StackHead != NULL); + My->StackHead->line = x; + My->StackHead->ExecCode = EXEC_GOSUB; + } + else + { + /* ERROR -- OUT OF MEMORY */ + assert (My->StackHead != NULL); + My->StackHead->line = My->EndMarker; + } + } + else + { + /* + ** + ** ------------------------------------------------------------------------- + ** OPTION ERROR GOTO + ** ------------------------------------------------------------------------- + ** + */ + x->position = 0; /* start of line */ + assert (My->StackHead != NULL); + My->StackHead->line = x; + } + return; + } + } + /* NOT FOUND */ + /* fall thru to the DEFAULT ERROR HANDLER */ + } + /* + ** + ** ------------------------------------------------------------------------- + ** DEFAULT ERROR HANDLER (FATAL) + ** ------------------------------------------------------------------------- + ** + */ + /* + ** + ** display error message + ** + */ + if (l->LineFlags & (LINE_USER) || l->number <= 0) + { + /* USER line in console */ + fprintf (My->SYSOUT->cfp, "\nERROR: %s\n", My->ERROR4); + ResetConsoleColumn (); + } + else + { + /* BASIC program line */ + fprintf (My->SYSOUT->cfp, "\nERROR in line %d: %s\n", l->number, + My->ERROR4); + ResetConsoleColumn (); + /* + ** + ** display stack trace + ** + */ + if (My->CurrentVersion->OptionFlags & (OPTION_TRACE_ON)) + { + /* + ** Dump the BASIC stack trace when a FATAL error occurs. + ** First line is the TOP of the stack. + ** Last line is the BOTTOM of the stack. + */ + StackType *StackItem; + fprintf (My->SYSOUT->cfp, "\nSTACK TRACE:\n"); + for (StackItem = My->StackHead; StackItem != NULL; + StackItem = StackItem->next) + { + LineType *l; + + l = StackItem->line; + if (l != NULL) + { + if (MINLIN <= l->number && l->number <= MAXLIN) + { + /* BASIC program line */ + if (l->buffer == NULL) + { + fprintf (My->SYSOUT->cfp, "%d\n", l->number); + } + else + { + fprintf (My->SYSOUT->cfp, "%d:%s\n", l->number, l->buffer); + } + } + } + } + ResetConsoleColumn (); + } + } + + My->AutomaticLineNumber = 0; + My->AutomaticLineIncrement = 0; + + if (My->IsInteractive) + { + /* INTERACTIVE: terminate program */ + + /* reset all stack counters */ + bwb_clrexec (); + SetOnError (0); + + My->ERR = -1; /* in bwb_execline(), default error handler */ + + + /* reset the break handler */ + signal (SIGINT, break_mes); + + + return; + } + /* NOT INTERACTIVE: terminate immediately */ + bwx_terminate (); + return; /* never reached */ + } + if (l->number > 0) + { + /* These events only occur in running programs */ + if (My->IsTimerOn) + { + /* TIMER ON */ + if (My->OnTimerCount > 0) + { + if (bwx_TIMER (0) > My->OnTimerExpires) + { + My->IsTimerOn = FALSE; + if (My->OnTimerLineNumber > 0) + { + /* ON TIMER( My->OnTimerCount ) GOSUB My->OnTimerLineNumber */ + LineType *x; + + for (x = My->StartMarker->next; x != My->EndMarker; x = x->next) + { + if (x->number == My->OnTimerLineNumber) + { + /* FOUND */ + /* save current stack level */ + assert (My->StackHead != NULL); + My->StackHead->line = r; + /* increment exec stack */ + if (bwb_incexec ()) + { + /* set the new position to x and return x */ + x->position = 0; + assert (My->StackHead != NULL); + My->StackHead->line = x; + My->StackHead->ExecCode = EXEC_GOSUB; + } + else + { + /* ERROR */ + assert (My->StackHead != NULL); + My->StackHead->line = My->EndMarker; + } + return; + } + } + /* NOT FOUND */ + } + } + } + } + } + /* check for end of line: if so, advance to next line and return */ + if (r == l) + { + /* advance to the next line */ + l->next->position = 0; + r = l->next; + } + else if (line_is_eol (r)) + { + /* we could be at the end-of-the-line, added for RETURN */ + /* advance to the next line */ + r->next->position = 0; + r = r->next; + } + /* else reset with the value in r */ + assert (My->StackHead != NULL); + My->StackHead->line = r; +} + +/*************************************************************** + + FUNCTION: is_ln() + + DESCRIPTION: This function determines whether a program + line (in buffer) begins with a line number. + +***************************************************************/ + +static int +is_ln (char *buffer) +{ + int position; + + assert (buffer != NULL); + + position = 0; + buff_skip_spaces (buffer, &position); /* keep this */ + if (bwb_isdigit (buffer[position])) + { + return TRUE; + } + return FALSE; +} + +/*************************************************************** + + FUNCTION: is_numconst() + + DESCRIPTION: This function reads the string in + and returns TRUE if it is a numerical + constant and FALSE if it is not. At + this point, only decimal (base 10) + constants are detected. + +***************************************************************/ + +static int +is_numconst (char *buffer) +{ + char *p; + + assert (buffer != NULL); + + /* Return FALSE for empty buffer */ + + if (buffer[0] == NulChar) + { + return FALSE; + } + /* else check digits */ + + p = buffer; + while (*p != NulChar) + { + switch (*p) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + break; + default: + return FALSE; + } + p++; + } + + /* only numerical characters detected */ + + return TRUE; + +} + +/* SWITCH */ +LineType * +bwb_vector( LineType *l ) +{ + LineType *r; + assert (l != NULL); + switch( l->cmdnum ) + { + case C_DEF8LBL: + r = bwb_DEF8LBL( l ); + break; + case C_APPEND: + r = bwb_APPEND( l ); + break; + case C_AS: + r = bwb_AS( l ); + break; + case C_AUTO: + r = bwb_AUTO( l ); + break; + case C_BACKSPACE: + r = bwb_BACKSPACE( l ); + break; + case C_BREAK: + r = bwb_BREAK( l ); + break; + case C_BUILD: + r = bwb_BUILD( l ); + break; + case C_BYE: + r = bwb_BYE( l ); + break; + case C_CALL: + r = bwb_CALL( l ); + break; + case C_CASE: + r = bwb_CASE( l ); + break; + case C_CASE_ELSE: + r = bwb_CASE_ELSE( l ); + break; + case C_CHAIN: + r = bwb_CHAIN( l ); + break; + case C_CHANGE: + r = bwb_CHANGE( l ); + break; + case C_CLEAR: + r = bwb_CLEAR( l ); + break; + case C_CLOAD: + r = bwb_CLOAD( l ); + break; + case C_CLOAD8: + r = bwb_CLOAD8( l ); + break; + case C_CLOSE: + r = bwb_CLOSE( l ); + break; + case C_CLR: + r = bwb_CLR( l ); + break; + case C_CMDS: + r = bwb_CMDS( l ); + break; + case C_COMMON: + r = bwb_COMMON( l ); + break; + case C_CONSOLE: + r = bwb_CONSOLE( l ); + break; + case C_CONST: + r = bwb_CONST( l ); + break; + case C_CONT: + r = bwb_CONT( l ); + break; + case C_CONTINUE: + r = bwb_CONTINUE( l ); + break; + case C_COPY: + r = bwb_COPY( l ); + break; + case C_CREATE: + r = bwb_CREATE( l ); + break; + case C_CSAVE: + r = bwb_CSAVE( l ); + break; + case C_CSAVE8: + r = bwb_CSAVE8( l ); + break; + case C_DATA: + r = bwb_DATA( l ); + break; + case C_DEC: + r = bwb_DEC( l ); + break; + case C_DEF: + r = bwb_DEF( l ); + break; + case C_DEFBYT: + r = bwb_DEFBYT( l ); + break; + case C_DEFCUR: + r = bwb_DEFCUR( l ); + break; + case C_DEFDBL: + r = bwb_DEFDBL( l ); + break; + case C_DEFINT: + r = bwb_DEFINT( l ); + break; + case C_DEFLNG: + r = bwb_DEFLNG( l ); + break; + case C_DEFSNG: + r = bwb_DEFSNG( l ); + break; + case C_DEFSTR: + r = bwb_DEFSTR( l ); + break; + case C_DELETE: + r = bwb_DELETE( l ); + break; + case C_DELIMIT: + r = bwb_DELIMIT( l ); + break; + case C_DIM: + r = bwb_DIM( l ); + break; + case C_DISPLAY: + r = bwb_DISPLAY( l ); + break; + case C_DO: + r = bwb_DO( l ); + break; + case C_DOS: + r = bwb_DOS( l ); + break; + case C_DSP: + r = bwb_DSP( l ); + break; + case C_EDIT: + r = bwb_EDIT( l ); + break; + case C_ELSE: + r = bwb_ELSE( l ); + break; + case C_ELSEIF: + r = bwb_ELSEIF( l ); + break; + case C_END: + r = bwb_END( l ); + break; + case C_END_FUNCTION: + r = bwb_END_FUNCTION( l ); + break; + case C_END_IF: + r = bwb_END_IF( l ); + break; + case C_END_SELECT: + r = bwb_END_SELECT( l ); + break; + case C_END_SUB: + r = bwb_END_SUB( l ); + break; + case C_ERASE: + r = bwb_ERASE( l ); + break; + case C_EXCHANGE: + r = bwb_EXCHANGE( l ); + break; + case C_EXIT: + r = bwb_EXIT( l ); + break; + case C_EXIT_DO: + r = bwb_EXIT_DO( l ); + break; + case C_EXIT_FOR: + r = bwb_EXIT_FOR( l ); + break; + case C_EXIT_FUNCTION: + r = bwb_EXIT_FUNCTION( l ); + break; + case C_EXIT_REPEAT: + r = bwb_EXIT_REPEAT( l ); + break; + case C_EXIT_SUB: + r = bwb_EXIT_SUB( l ); + break; + case C_EXIT_WHILE: + r = bwb_EXIT_WHILE( l ); + break; + case C_FEND: + r = bwb_FEND( l ); + break; + case C_FIELD: + r = bwb_FIELD( l ); + break; + case C_FILE: + r = bwb_FILE( l ); + break; + case C_FILES: + r = bwb_FILES( l ); + break; + case C_FLEX: + r = bwb_FLEX( l ); + break; + case C_FNCS: + r = bwb_FNCS( l ); + break; + case C_FNEND: + r = bwb_FNEND( l ); + break; + case C_FOR: + r = bwb_FOR( l ); + break; + case C_FUNCTION: + r = bwb_FUNCTION( l ); + break; + case C_GET: + r = bwb_GET( l ); + break; + case C_GO: + r = bwb_GO( l ); + break; + case C_GO_SUB: + r = bwb_GO_SUB( l ); + break; + case C_GO_TO: + r = bwb_GO_TO( l ); + break; + case C_GOODBYE: + r = bwb_GOODBYE( l ); + break; + case C_GOSUB: + r = bwb_GOSUB( l ); + break; + case C_GOTO: + r = bwb_GOTO( l ); + break; + case C_HELP: + r = bwb_HELP( l ); + break; + case C_IF: + r = bwb_IF( l ); + break; + case C_IF_END: + r = bwb_IF_END( l ); + break; + case C_IF_MORE: + r = bwb_IF_MORE( l ); + break; + case C_IF8THEN: + r = bwb_IF8THEN( l ); + break; + case C_IMAGE: + r = bwb_IMAGE( l ); + break; + case C_INC: + r = bwb_INC( l ); + break; + case C_INPUT: + r = bwb_INPUT( l ); + break; + case C_INPUT_LINE: + r = bwb_INPUT_LINE( l ); + break; + case C_LET: + r = bwb_LET( l ); + break; + case C_LINE: + r = bwb_LINE( l ); + break; + case C_LINE_INPUT: + r = bwb_LINE_INPUT( l ); + break; + case C_LIST: + r = bwb_LIST( l ); + break; + case C_LISTNH: + r = bwb_LISTNH( l ); + break; + case C_LLIST: + r = bwb_LLIST( l ); + break; + case C_LOAD: + r = bwb_LOAD( l ); + break; + case C_LOCAL: + r = bwb_LOCAL( l ); + break; + case C_LOOP: + r = bwb_LOOP( l ); + break; + case C_LPRINT: + r = bwb_LPRINT( l ); + break; + case C_LPRINTER: + r = bwb_LPRINTER( l ); + break; + case C_LPT: + r = bwb_LPT( l ); + break; + case C_LSET: + r = bwb_LSET( l ); + break; + case C_MAINTAINER: + r = bwb_MAINTAINER( l ); + break; + case C_MAINTAINER_CMDS: + r = bwb_MAINTAINER_CMDS( l ); + break; + case C_MAINTAINER_CMDS_HTML: + r = bwb_MAINTAINER_CMDS_HTML( l ); + break; + case C_MAINTAINER_CMDS_ID: + r = bwb_MAINTAINER_CMDS_ID( l ); + break; + case C_MAINTAINER_CMDS_MANUAL: + r = bwb_MAINTAINER_CMDS_MANUAL( l ); + break; + case C_MAINTAINER_CMDS_SWITCH: + r = bwb_MAINTAINER_CMDS_SWITCH( l ); + break; + case C_MAINTAINER_CMDS_TABLE: + r = bwb_MAINTAINER_CMDS_TABLE( l ); + break; + case C_MAINTAINER_DEBUG: + r = bwb_MAINTAINER_DEBUG( l ); + break; + case C_MAINTAINER_DEBUG_OFF: + r = bwb_MAINTAINER_DEBUG_OFF( l ); + break; + case C_MAINTAINER_DEBUG_ON: + r = bwb_MAINTAINER_DEBUG_ON( l ); + break; + case C_MAINTAINER_FNCS: + r = bwb_MAINTAINER_FNCS( l ); + break; + case C_MAINTAINER_FNCS_HTML: + r = bwb_MAINTAINER_FNCS_HTML( l ); + break; + case C_MAINTAINER_FNCS_ID: + r = bwb_MAINTAINER_FNCS_ID( l ); + break; + case C_MAINTAINER_FNCS_MANUAL: + r = bwb_MAINTAINER_FNCS_MANUAL( l ); + break; + case C_MAINTAINER_FNCS_SWITCH: + r = bwb_MAINTAINER_FNCS_SWITCH( l ); + break; + case C_MAINTAINER_FNCS_TABLE: + r = bwb_MAINTAINER_FNCS_TABLE( l ); + break; + case C_MAINTAINER_MANUAL: + r = bwb_MAINTAINER_MANUAL( l ); + break; + case C_MAINTAINER_STACK: + r = bwb_MAINTAINER_STACK( l ); + break; + case C_MARGIN: + r = bwb_MARGIN( l ); + break; + case C_MAT: + r = bwb_MAT( l ); + break; + case C_MAT_GET: + r = bwb_MAT_GET( l ); + break; + case C_MAT_INPUT: + r = bwb_MAT_INPUT( l ); + break; + case C_MAT_PRINT: + r = bwb_MAT_PRINT( l ); + break; + case C_MAT_PUT: + r = bwb_MAT_PUT( l ); + break; + case C_MAT_READ: + r = bwb_MAT_READ( l ); + break; + case C_MAT_WRITE: + r = bwb_MAT_WRITE( l ); + break; + case C_MERGE: + r = bwb_MERGE( l ); + break; + case C_MID4: + r = bwb_MID4( l ); + break; + case C_MON: + r = bwb_MON( l ); + break; + case C_NAME: + r = bwb_NAME( l ); + break; + case C_NEW: + r = bwb_NEW( l ); + break; + case C_NEXT: + r = bwb_NEXT( l ); + break; + case C_OF: + r = bwb_OF( l ); + break; + case C_OLD: + r = bwb_OLD( l ); + break; + case C_ON: + r = bwb_ON( l ); + break; + case C_ON_ERROR: + r = bwb_ON_ERROR( l ); + break; + case C_ON_ERROR_GOSUB: + r = bwb_ON_ERROR_GOSUB( l ); + break; + case C_ON_ERROR_GOTO: + r = bwb_ON_ERROR_GOTO( l ); + break; + case C_ON_ERROR_RESUME: + r = bwb_ON_ERROR_RESUME( l ); + break; + case C_ON_ERROR_RESUME_NEXT: + r = bwb_ON_ERROR_RESUME_NEXT( l ); + break; + case C_ON_ERROR_RETURN: + r = bwb_ON_ERROR_RETURN( l ); + break; + case C_ON_ERROR_RETURN_NEXT: + r = bwb_ON_ERROR_RETURN_NEXT( l ); + break; + case C_ON_TIMER: + r = bwb_ON_TIMER( l ); + break; + case C_OPEN: + r = bwb_OPEN( l ); + break; + case C_OPTION: + r = bwb_OPTION( l ); + break; + case C_OPTION_ANGLE: + r = bwb_OPTION_ANGLE( l ); + break; + case C_OPTION_ANGLE_DEGREES: + r = bwb_OPTION_ANGLE_DEGREES( l ); + break; + case C_OPTION_ANGLE_GRADIANS: + r = bwb_OPTION_ANGLE_GRADIANS( l ); + break; + case C_OPTION_ANGLE_RADIANS: + r = bwb_OPTION_ANGLE_RADIANS( l ); + break; + case C_OPTION_ARITHMETIC: + r = bwb_OPTION_ARITHMETIC( l ); + break; + case C_OPTION_ARITHMETIC_DECIMAL: + r = bwb_OPTION_ARITHMETIC_DECIMAL( l ); + break; + case C_OPTION_ARITHMETIC_FIXED: + r = bwb_OPTION_ARITHMETIC_FIXED( l ); + break; + case C_OPTION_ARITHMETIC_NATIVE: + r = bwb_OPTION_ARITHMETIC_NATIVE( l ); + break; + case C_OPTION_BASE: + r = bwb_OPTION_BASE( l ); + break; + case C_OPTION_BUGS: + r = bwb_OPTION_BUGS( l ); + break; + case C_OPTION_BUGS_BOOLEAN: + r = bwb_OPTION_BUGS_BOOLEAN( l ); + break; + case C_OPTION_BUGS_OFF: + r = bwb_OPTION_BUGS_OFF( l ); + break; + case C_OPTION_BUGS_ON: + r = bwb_OPTION_BUGS_ON( l ); + break; + case C_OPTION_COMPARE: + r = bwb_OPTION_COMPARE( l ); + break; + case C_OPTION_COMPARE_BINARY: + r = bwb_OPTION_COMPARE_BINARY( l ); + break; + case C_OPTION_COMPARE_DATABASE: + r = bwb_OPTION_COMPARE_DATABASE( l ); + break; + case C_OPTION_COMPARE_TEXT: + r = bwb_OPTION_COMPARE_TEXT( l ); + break; + case C_OPTION_COVERAGE: + r = bwb_OPTION_COVERAGE( l ); + break; + case C_OPTION_COVERAGE_OFF: + r = bwb_OPTION_COVERAGE_OFF( l ); + break; + case C_OPTION_COVERAGE_ON: + r = bwb_OPTION_COVERAGE_ON( l ); + break; + case C_OPTION_DATE: + r = bwb_OPTION_DATE( l ); + break; + case C_OPTION_DIGITS: + r = bwb_OPTION_DIGITS( l ); + break; + case C_OPTION_DISABLE: + r = bwb_OPTION_DISABLE( l ); + break; + case C_OPTION_DISABLE_COMMAND: + r = bwb_OPTION_DISABLE_COMMAND( l ); + break; + case C_OPTION_DISABLE_FUNCTION: + r = bwb_OPTION_DISABLE_FUNCTION( l ); + break; + case C_OPTION_DISABLE_OPERATOR: + r = bwb_OPTION_DISABLE_OPERATOR( l ); + break; + case C_OPTION_EDIT: + r = bwb_OPTION_EDIT( l ); + break; + case C_OPTION_ENABLE: + r = bwb_OPTION_ENABLE( l ); + break; + case C_OPTION_ENABLE_COMMAND: + r = bwb_OPTION_ENABLE_COMMAND( l ); + break; + case C_OPTION_ENABLE_FUNCTION: + r = bwb_OPTION_ENABLE_FUNCTION( l ); + break; + case C_OPTION_ENABLE_OPERATOR: + r = bwb_OPTION_ENABLE_OPERATOR( l ); + break; + case C_OPTION_ERROR: + r = bwb_OPTION_ERROR( l ); + break; + case C_OPTION_ERROR_GOSUB: + r = bwb_OPTION_ERROR_GOSUB( l ); + break; + case C_OPTION_ERROR_GOTO: + r = bwb_OPTION_ERROR_GOTO( l ); + break; + case C_OPTION_EXPLICIT: + r = bwb_OPTION_EXPLICIT( l ); + break; + case C_OPTION_EXTENSION: + r = bwb_OPTION_EXTENSION( l ); + break; + case C_OPTION_FILES: + r = bwb_OPTION_FILES( l ); + break; + case C_OPTION_IMPLICIT: + r = bwb_OPTION_IMPLICIT( l ); + break; + case C_OPTION_INDENT: + r = bwb_OPTION_INDENT( l ); + break; + case C_OPTION_LABELS: + r = bwb_OPTION_LABELS( l ); + break; + case C_OPTION_LABELS_OFF: + r = bwb_OPTION_LABELS_OFF( l ); + break; + case C_OPTION_LABELS_ON: + r = bwb_OPTION_LABELS_ON( l ); + break; + case C_OPTION_PROMPT: + r = bwb_OPTION_PROMPT( l ); + break; + case C_OPTION_PUNCT: + r = bwb_OPTION_PUNCT( l ); + break; + case C_OPTION_PUNCT_AT: + r = bwb_OPTION_PUNCT_AT( l ); + break; + case C_OPTION_PUNCT_BYTE: + r = bwb_OPTION_PUNCT_BYTE( l ); + break; + case C_OPTION_PUNCT_COMMENT: + r = bwb_OPTION_PUNCT_COMMENT( l ); + break; + case C_OPTION_PUNCT_CURRENCY: + r = bwb_OPTION_PUNCT_CURRENCY( l ); + break; + case C_OPTION_PUNCT_DOUBLE: + r = bwb_OPTION_PUNCT_DOUBLE( l ); + break; + case C_OPTION_PUNCT_FILENUM: + r = bwb_OPTION_PUNCT_FILENUM( l ); + break; + case C_OPTION_PUNCT_IMAGE: + r = bwb_OPTION_PUNCT_IMAGE( l ); + break; + case C_OPTION_PUNCT_INPUT: + r = bwb_OPTION_PUNCT_INPUT( l ); + break; + case C_OPTION_PUNCT_INTEGER: + r = bwb_OPTION_PUNCT_INTEGER( l ); + break; + case C_OPTION_PUNCT_LONG: + r = bwb_OPTION_PUNCT_LONG( l ); + break; + case C_OPTION_PUNCT_LPAREN: + r = bwb_OPTION_PUNCT_LPAREN( l ); + break; + case C_OPTION_PUNCT_PRINT: + r = bwb_OPTION_PUNCT_PRINT( l ); + break; + case C_OPTION_PUNCT_QUOTE: + r = bwb_OPTION_PUNCT_QUOTE( l ); + break; + case C_OPTION_PUNCT_RPAREN: + r = bwb_OPTION_PUNCT_RPAREN( l ); + break; + case C_OPTION_PUNCT_SINGLE: + r = bwb_OPTION_PUNCT_SINGLE( l ); + break; + case C_OPTION_PUNCT_STATEMENT: + r = bwb_OPTION_PUNCT_STATEMENT( l ); + break; + case C_OPTION_PUNCT_STRING: + r = bwb_OPTION_PUNCT_STRING( l ); + break; + case C_OPTION_RECLEN: + r = bwb_OPTION_RECLEN( l ); + break; + case C_OPTION_RENUM: + r = bwb_OPTION_RENUM( l ); + break; + case C_OPTION_ROUND: + r = bwb_OPTION_ROUND( l ); + break; + case C_OPTION_ROUND_BANK: + r = bwb_OPTION_ROUND_BANK( l ); + break; + case C_OPTION_ROUND_MATH: + r = bwb_OPTION_ROUND_MATH( l ); + break; + case C_OPTION_ROUND_TRUNCATE: + r = bwb_OPTION_ROUND_TRUNCATE( l ); + break; + case C_OPTION_SCALE: + r = bwb_OPTION_SCALE( l ); + break; + case C_OPTION_SLEEP: + r = bwb_OPTION_SLEEP( l ); + break; + case C_OPTION_STDERR: + r = bwb_OPTION_STDERR( l ); + break; + case C_OPTION_STDIN: + r = bwb_OPTION_STDIN( l ); + break; + case C_OPTION_STDOUT: + r = bwb_OPTION_STDOUT( l ); + break; + case C_OPTION_STRICT: + r = bwb_OPTION_STRICT( l ); + break; + case C_OPTION_STRICT_OFF: + r = bwb_OPTION_STRICT_OFF( l ); + break; + case C_OPTION_STRICT_ON: + r = bwb_OPTION_STRICT_ON( l ); + break; + case C_OPTION_TERMINAL: + r = bwb_OPTION_TERMINAL( l ); + break; + case C_OPTION_TERMINAL_ADM: + r = bwb_OPTION_TERMINAL_ADM( l ); + break; + case C_OPTION_TERMINAL_ANSI: + r = bwb_OPTION_TERMINAL_ANSI( l ); + break; + case C_OPTION_TERMINAL_NONE: + r = bwb_OPTION_TERMINAL_NONE( l ); + break; + case C_OPTION_TIME: + r = bwb_OPTION_TIME( l ); + break; + case C_OPTION_TRACE: + r = bwb_OPTION_TRACE( l ); + break; + case C_OPTION_TRACE_OFF: + r = bwb_OPTION_TRACE_OFF( l ); + break; + case C_OPTION_TRACE_ON: + r = bwb_OPTION_TRACE_ON( l ); + break; + case C_OPTION_USING: + r = bwb_OPTION_USING( l ); + break; + case C_OPTION_USING_ALL: + r = bwb_OPTION_USING_ALL( l ); + break; + case C_OPTION_USING_COMMA: + r = bwb_OPTION_USING_COMMA( l ); + break; + case C_OPTION_USING_DIGIT: + r = bwb_OPTION_USING_DIGIT( l ); + break; + case C_OPTION_USING_DOLLAR: + r = bwb_OPTION_USING_DOLLAR( l ); + break; + case C_OPTION_USING_EXRAD: + r = bwb_OPTION_USING_EXRAD( l ); + break; + case C_OPTION_USING_FILLER: + r = bwb_OPTION_USING_FILLER( l ); + break; + case C_OPTION_USING_FIRST: + r = bwb_OPTION_USING_FIRST( l ); + break; + case C_OPTION_USING_LENGTH: + r = bwb_OPTION_USING_LENGTH( l ); + break; + case C_OPTION_USING_LITERAL: + r = bwb_OPTION_USING_LITERAL( l ); + break; + case C_OPTION_USING_MINUS: + r = bwb_OPTION_USING_MINUS( l ); + break; + case C_OPTION_USING_PERIOD: + r = bwb_OPTION_USING_PERIOD( l ); + break; + case C_OPTION_USING_PLUS: + r = bwb_OPTION_USING_PLUS( l ); + break; + case C_OPTION_VERSION: + r = bwb_OPTION_VERSION( l ); + break; + case C_OPTION_ZONE: + r = bwb_OPTION_ZONE( l ); + break; + case C_PAUSE: + r = bwb_PAUSE( l ); + break; + case C_PDEL: + r = bwb_PDEL( l ); + break; + case C_POP: + r = bwb_POP( l ); + break; + case C_PRINT: + r = bwb_PRINT( l ); + break; + case C_PTP: + r = bwb_PTP( l ); + break; + case C_PTR: + r = bwb_PTR( l ); + break; + case C_PUT: + r = bwb_PUT( l ); + break; + case C_QUIT: + r = bwb_QUIT( l ); + break; + case C_READ: + r = bwb_READ( l ); + break; + case C_RECALL: + r = bwb_RECALL( l ); + break; + case C_REM: + r = bwb_REM( l ); + break; + case C_RENAME: + r = bwb_RENAME( l ); + break; + case C_RENUM: + r = bwb_RENUM( l ); + break; + case C_RENUMBER: + r = bwb_RENUMBER( l ); + break; + case C_REPEAT: + r = bwb_REPEAT( l ); + break; + case C_REPLACE: + r = bwb_REPLACE( l ); + break; + case C_RESET: + r = bwb_RESET( l ); + break; + case C_RESTORE: + r = bwb_RESTORE( l ); + break; + case C_RESUME: + r = bwb_RESUME( l ); + break; + case C_RETURN: + r = bwb_RETURN( l ); + break; + case C_RSET: + r = bwb_RSET( l ); + break; + case C_RUN: + r = bwb_RUN( l ); + break; + case C_RUNNH: + r = bwb_RUNNH( l ); + break; + case C_SAVE: + r = bwb_SAVE( l ); + break; + case C_SCRATCH: + r = bwb_SCRATCH( l ); + break; + case C_SELECT: + r = bwb_SELECT( l ); + break; + case C_SELECT_CASE: + r = bwb_SELECT_CASE( l ); + break; + case C_STEP: + r = bwb_STEP( l ); + break; + case C_STOP: + r = bwb_STOP( l ); + break; + case C_STORE: + r = bwb_STORE( l ); + break; + case C_SUB: + r = bwb_SUB( l ); + break; + case C_SUB_END: + r = bwb_SUB_END( l ); + break; + case C_SUB_EXIT: + r = bwb_SUB_EXIT( l ); + break; + case C_SUBEND: + r = bwb_SUBEND( l ); + break; + case C_SUBEXIT: + r = bwb_SUBEXIT( l ); + break; + case C_SWAP: + r = bwb_SWAP( l ); + break; + case C_SYSTEM: + r = bwb_SYSTEM( l ); + break; + case C_TEXT: + r = bwb_TEXT( l ); + break; + case C_THEN: + r = bwb_THEN( l ); + break; + case C_TIMER: + r = bwb_TIMER( l ); + break; + case C_TIMER_OFF: + r = bwb_TIMER_OFF( l ); + break; + case C_TIMER_ON: + r = bwb_TIMER_ON( l ); + break; + case C_TIMER_STOP: + r = bwb_TIMER_STOP( l ); + break; + case C_TLOAD: + r = bwb_TLOAD( l ); + break; + case C_TO: + r = bwb_TO( l ); + break; + case C_TRACE: + r = bwb_TRACE( l ); + break; + case C_TRACE_OFF: + r = bwb_TRACE_OFF( l ); + break; + case C_TRACE_ON: + r = bwb_TRACE_ON( l ); + break; + case C_TSAVE: + r = bwb_TSAVE( l ); + break; + case C_TTY: + r = bwb_TTY( l ); + break; + case C_TTY_IN: + r = bwb_TTY_IN( l ); + break; + case C_TTY_OUT: + r = bwb_TTY_OUT( l ); + break; + case C_UNTIL: + r = bwb_UNTIL( l ); + break; + case C_USE: + r = bwb_USE( l ); + break; + case C_VARS: + r = bwb_VARS( l ); + break; + case C_WEND: + r = bwb_WEND( l ); + break; + case C_WHILE: + r = bwb_WHILE( l ); + break; + case C_WRITE: + r = bwb_WRITE( l ); + break; + default: + WARN_INTERNAL_ERROR; + r = l; + break; + } + return r; +} + +/* EOF */ -- cgit v1.2.3