/* ** MBPRE.C v 1.2 ** ** MBasic PREprocessor ** ** 28 Jul 86 Modified to allow the use of a semicolon, or the ** v 1.2 word REM, at the beginning of a line to specify ** that the line is a comment or remark line. Blank ** lines are still ignored as in the original. ** G. F. Reding [72436,45] ** ** 07 Nov 85 Typed from Microsystems magazine, May 1984 issue. ** v 1.1 Modified for compilation with BDS-C v1.50. Added ** strip of high bit from input strings. Document or ** nondocument mode of text editor may be used. Some ** minor changes made, plus more comments added. ** G. F. Reding [72436,45] ** ** Original by James L. Shearer, Angola, IN 46703. ** For compilation with C80, by Software Toolworks. ** Thanks very much! ** ** ** This program allows the creation of a MBasic programs in stuctured ** format using a text editor in either the document or non-document mode. ** Line numbers are NOT USED. Instead, labels mark the entry/exit points ** of routines. All labels are 8-character strings (or shorter) whose ** first character MUST be the '@' character and subsequent characters ** may be letters, numerals, or periods, inclusive. Labels longer than ** 8 characters are allowed but would be truncated, so only the first 8 ** characters would be recognized. Following are some examples: ** ** Acceptable Unacceptable ** ** @PRINT.1 @WRITE#4 ( # is an illegal char ) ** @EXIT EXIT.6 ( no leading @ ) ** @age.sr @POSITION.35 ( too long, would be truncated) ** ** Simply, write your program as you would in assembly, C-language, etc. ** Lines BEGINNING with 'REM' are remark lines, as in basic. These such ** lines are not included in the resultant file created by this program. ** ** If a REM is included near the end of a program line, then such remark ** is retained in the new file, which could be helpful at odd spots and ** for some areas of difficult code, etc. ** ** +++ NEW +++ Lines beginning with a semicolon, as in assembly language ** programs, are also considered as "remark lines". ** ** The capability to use the (original) REM is retained in this version, ** should anyone prefer to use it instead of the (new) semicolon, and/or ** to allow persons time to convert their old programs to the new format ** of using just a semicolon at the beginning of a remark/comment line. ** ** +++ FUTURE +++ Version 1.3 will NOT use the REM, but will be ONLY for ** remark/comment lines that start with the semicolon. Other minor mods ** may also be included. ** ** Usage: mbpre oldfile.ext newfile.ext ** ** NOTE: Be sure no file by your proposed newfile.ext name exists when ** you use this as it would be written over. Suggest as extentions for ** the oldfile (source) and newfile (destination) respectively to be ** .MBP and .BAS ** */ #include /* standard header file */ #define MAXLEN 255 /* Max line length */ #define MAXLBL 500 /* Room for 500 labels */ char ibuf[BUFSIZ], /* input file buffer */ obuf[BUFSIZ], /* output file buffer */ label[9*MAXLBL]; /* arrays for labels */ int labelno[MAXLBL], /* arrays for line nbrs */ lblcnt, /* count of labels */ lineno; /* line number variable */ main(argc,argv) int argc; /* arg count */ char **argv; /* arg vector */ { char line[MAXLEN], /* temp line string */ word[MAXLEN]; /* temp word string */ int pass, /* in-file read counter */ len; /* length of line read */ printf("\nMBPRE MBasic PREprocessor v1.2\n"); if (argc != 3) /* allow only 2 args */ { printf("Usage: mbpre oldfile.ext newfile.ext \n"); exit(); } if (fopen(argv[1],ibuf) == ERROR) /* try to open file */ { printf("Can't open: %s\n",argv[1]); exit(); } if (fcreat(argv[2],obuf) == ERROR) /* create 2nd file */ { printf("Can't create: %s\n",argv[2]); exit(); } /* ** On either pass, test for REM lines and drop any that are found. ** "Remark lines" may also be any line which begins with the first ** character of a semicolon in addition to the alternative of a line ** which begins with the first 3 characters of REM. ** ** On first pass, assign line numbers for the labels and build the ** label table as the labels are found. On the second pass, write ** numbered program lines to out-file, eliminating any unnecessary ** white-space from beginning of each program line and replacing any ** labels found in the program line with its appropriate line number. */ pass = 1; /* show this is the first pass */ while (pass != 3) /* use only 2x */ { if (pass == 2) { /* if pass 2, re-open in-file for second read */ if (fopen(argv[1],ibuf) == ERROR) { printf("Can't open: %s\n",argv[1]); exit(); } } lineno = 0; /* initialize line nbr to zero */ while ((len = getln(line,MAXLEN)) > 0) /* do until end */ { getwrd(word,line); /* this next conditional makes sure that blank lines or lines which begin with either a semicolon or the letters REM are not counted and consequently are not sent to the output file */ if ((len > 2) && (strcmp(word,";") != 0) && (strcmp(word,"REM") != 0)) { /* if not REM line, assign a line nbr, */ /* build or write depending on pass nbr */ lineno = lineno + 10; /* give line # */ if (pass == 1) { if (*line == '@') /* build table if label */ bldlabel(line,lineno); } else writeln(line,lineno); } } fclose(ibuf); /* close at end of each pass */ pass = pass + 1; /* show doing another pass */ } int j; putc(CPMEOF,obuf); /* add EOF char */ fclose(obuf); /* close with autoflush */ for (j = 0; j <= lblcnt; ++j) /* give summary */ printf("\n%4d %10s",labelno[j],label+9*j); printf("\n"); exit(); } /* ** Subroutines used above */ getln(s,lim) /* Reads line from file f1 to s */ int lim; /* Returns line len (0 if EOF) */ char s[]; { int c, i, mask; mask = 127; /* high order bit mask */ i = 0; do (c=getc(ibuf)); /* pass white space */ while (isspace(c)); if (c != EOF && c != CPMEOF &&c != '\n') { /* strip hi order bit of characters by AND with mask */ s[i++] = (c & mask); while (--lim > 0 && (c=getc(ibuf)) != EOF && c != '\n') s[i++] = (c & mask); } if (c == '\n') s[i++] = c; s[i] = '\0'; return(i); } bldlabel(s,n) /* Put label from line s and line */ char *s; /* number n into arrays. */ int n; { if (lblcnt <= MAXLBL); { wrdcpy(label+9*lblcnt,s); label[9*lblcnt+8] = '\0'; /* limit label to 8 char */ labelno[lblcnt] = n; lblcnt = lblcnt + 1; } } writeln(s,n) /* Write line s to outfile inserting line */ int n; /* number n, and replace internal labels */ char s[]; /* with appropriate line number. */ { int i, j; char t[MAXLEN]; i = 0; if (s[i] == '@') /* label if 1st char @ */ { while (!isspace(s[i++])) /* and we pass it */ ; while (isspace(s[i])) /* and white space */ ++i; } fprintf(obuf,"%d ",n); /* write line number */ while (s[i] != '\n') { if (s[i] == '"') /* check for quotes */ { putc(s[i],obuf); /* write first " and */ while (s[++i] != '"') /* and all in between */ putc(s[i],obuf); putc(s[i++],obuf); /* write last " */ } else if (s[i] == '@') /* check for label */ { getwrd(t,&s[i]); /* get label into t */ i = i + strlen(t); /* move ptr past label */ t[8] = '\0'; /* only 8 char signif */ for (j = 0; j <= lblcnt; j++) if (strcmp(t,label+9*j) == 0) { /* write line # if match */ fprintf(obuf,"%d",labelno[j]); break; } if (j > lblcnt ) /* no match */ { printf("\n##### No match for label "); printf("%s on line %d\n",t,n); fprintf(obuf,"?%s?",t); } } else putc(s[i++],obuf); /* regular character */ } putc(s[i],obuf); /* end-of-line char(s) */ } getwrd(t,s) /* Get next word from s, put it in t. */ char s[],t[]; /* For our purposes, words start with @ */ { /* or alpha and then alpha, digits, */ int i, j; /* embedded '.' and optional final char */ i = 0; if ((s[i] == ';') && (i == 0)) /* if start is a semi */ i++; /* then get only it */ else if (s[i] == '@' || isalpha(s[i])) /* otherwise handle as */ /* normal line and get */ { /* first word of line */ ++i; while (isalpha(s[i]) || isdigit(s[i]) || s[i] == '.') i++; if (s[i]=='%' || s[i]=='!' || s[i]=='#' || s[i]=='$') i++; } for (j = 0; j <= i; j++) t[j] = s[j]; t[i] = '\0'; } wrdcpy(s,t) /* copy next word (see getwrd) from t to s */ char *s, *t; { while (isalpha(*t) || isdigit(*t) || *t == '@' || *t == '.') { *s = *t; s++; t++; } }