/* IBMLIP.C (Formerly PARSE.c) Copyright (C) 1982 by The Loglan Institute, Inc. Created 82.1.27 Gyro Gutted Sep 88 to remove common parts with Mac version. The "front end" part of this program reads preprocessed specimens from a file or the console, and hands the words to yyparse (the Yacc parser). It then displays or writes out the resulting parse. */ /* Modified by RAM in Jul 87 to ensure that globals are defined in parse.c but not in the other modules to avoid multiple definitions. Also extval.h includes parse.h so this is no longer required. yc.tab is no longer compiled separately, but is included in the main module. This has the parse tables and the yyparse.c routine in it with all the actions. */ #define DS (unsigned char *)"\n ",0 #define global /*to ensure the incorporation of globals in one of the modules */ #include #include "extval.h" char fname[20],tline[BIGLIN]; /*arrays for file name and input line*/ short textopen,dirty; /*flags for text file open, and line changed*/ // Prototypes for ibmlip.c only Common prototypes are in parse.h char * CtoPstr(char *); void CheckSave(); void Command(); void clrscr(void); /*clears the screen - this is an included routine in some DOS C compilers */ void editline(); void Entries(void); /*Gets the material to be parsed*/ void Error (char *msg, char *arg1); /*Display informative errors */ void Fatal (char *msg, char *arg1); /*Deal with fatal errors*/ void vgotoxy(short y, short x); /*A routine to deal with two different C-compiler calls*/ void Help(void); /*Display the table of parameter codes */ void IClose(STREAM buf); /* Close all files. I believe this is used only for corpus parsing */ void IOpen (char *name,STREAM fdesc, char *mode); /*General file opening routine*/ void nfputc (char c); /*A special routine for putting characters on the screen */ void OpenFiles (char *ext); /*Special routine for opening corpus files*/ void opentext(void); /*Open the explanatory text*/ void showins1(void); /*More explanatory text files*/ void showins2(void); void showins3(void); void showins4(void); void showins5(void); void WriteParse(short ptype); /*Write parses of various types*/ void CloseFiles (char *ext); /* close up shop */ short getmode(void); /*determine what type of parse is desired*/ Boolean GetLine (void); /*Get a line from console or text file */ Boolean INextLine(void); /*Used to get lines from the corpus files*/ char getche(void); /*getche is a Turbo C routine for console interaction. Defined here for MAC*/ /* RAM Jul 87. Note that all puts functions have had the \n removed, since C compilers nowadays usually include a new line in their definition */ int main (short argc, char **argv) /* The main file has parameters if a parse of a corpus file is to be done, otherwise it displays the copyright and version numbers, and the menu, and calls the appropriate routines to complete the parse */ {char s; #ifdef MACDOS argc = ccommand(&argv); /*A special console routine required by Think C*/ #endif #include "lextab" /*To associate lexeme names with their numbers*/ if (argc<2) { clrscr(); vgotoxy(6,20); puts ("Loglan interactive Parser, Version 2.3"); vgotoxy(7,25); puts ("Based on Loglan Grammar No.83"); vgotoxy(8,12); puts ("Copyright (C) 1982,1987-1998 by The Loglan Institute, Inc."); vgotoxy(9,30); puts ("All Rights Reserved"); vgotoxy(11,12); puts("The Institute wishes to acknowledge the contributions of"); vgotoxy(12,12); puts("James Cooke Brown, Scott Layson Burson, Douglas Landauer,"); vgotoxy(13,13); puts("Sheldon Linker, Robert A. McIvor, and Jeffrey S. Prothero"); vgotoxy(14,14); puts("to the design and/or writing of this parsing program"); vgotoxy(15,17); puts("and/or to the discovery and development of the"); vgotoxy(16,21); puts("machine grammar on which it is based."); vgotoxy(19,26); puts("Press any key to continue..."); s = getche(); /* Get a character without return */ Init(); /*Do the parse initiation*/ textopen = yydebug = dirty = FALSE; IOpen("LIPHELP",&rbuf,"r"); /*A text file of messages*/ domode: mode = getmode(); /*Get the parse mode desired*/ switch(mode) { case '1': /*Input from console*/ consp = TRUE; textf = itextf = FALSE; break; case '3': /*Sentence by sentence text file parsing*/ consp = itextf = TRUE; textf = FALSE; opentext(); /*Get the file name*/ break; case '2': /*All at once text file parsing*/ consp = itextf = FALSE; textf = TRUE; opentext(); /*Get the file name*/ break; case '4': showins1(); /*Display a help file*/ goto domode; /* and ask for the mode again*/ default: break; /*Default is console input*/ } Entries(); /*Do the parsing*/ } else { /*Corpus parse is desired*/ consp = FALSE; Init(); while (--argc > 0) { /*Open all the corpus files desired*/ ++argv; OpenFiles (*argv); Entries(); /*Parse them*/ CloseFiles(*argv); /*Close them and quit*/ } } return TRUE; } void alert(short n, short m) /*Error messages - Mac compatible */ /* This file uses the same error numbers as the Mac resources. n is the Mac alert type (not needed for DOS which distinguishes with Fatal or Error), and m the message number, implemented in DOS as a switch*/ { switch(m) { case 1: Fatal ("Unexpected EOF in YC1.TAB\n"," "); break; case 2: Fatal ("Little word is too long!\n"," "); break; case 3: Fatal ("Lex table full!\n"," "); break; case 4: Error ("End of string inside 'lie'-exp?\n"," "); break; case 6: Error ("Too many words in specimen!\n"," "); break; case 7: Error ("Deleted all words??\n"," "); break; case 8: Error ("MatchList: too many args or no ENDLIST!\n"," "); break; case 10: Error ("Unmatched KIE ... KIU\n"," "); break; case 11: Error ("Unmatched LI ... LU\n"," "); break; case 12: Fatal ("Out of memory!\n"," "); break; case 14: Error ("PPDelete: delete off end of string?\n"," "); break; case 15: Error ("PPJoin: right end precedes or matches left end?\n"," "); break; case 16: Error ("PPWhere: no more marks\n"," "); break; case 17: Error ("PP: invalid mark\n"," "); break; case 18: Error ("PPFindList: Warning: too many args or no ENDLIST\n"," "); break; case 21: Error ("Invalid node!\n"," "); break; case 23: Error ("Invalid Linnaean\n"," "); default: break; } } void CheckSave() /* In DOS the saving of the changed input file is automatic, but on closing the user has the option of saving it, either with the original file name, or with a new name. This routine implements that option*/ { short ch; dirty = FALSE; #ifdef DOS puts("Do you wish to save the changes you made in the input file? Y(es) N(o): "); ch = getche(); if (toupper(ch)=='Y') { puts("\n\nName a new file, or press RETURN if you wish to retain the old file name: "); gets(iline); if (!strlen(iline)) { /*Change file from tempf to olde name*/ remove(fname); rename("tempf",fname); } else if (rename("tempf",iline)<0) { /*Use the new name*/ puts("\nThat file exists! Do you wish it overwritten? Y(es) N(o): "); ch = getche(); if (toupper(ch)=='Y') { remove(iline); rename("tempf",iline); } else dirty = TRUE; } } else { /*Throw the changed file away*/ puts(""); remove("tempf"); } #endif } void CloseFiles (char *ext) /* close up shop */ /* Close all the files opened under argv (list in ext) for corpus parsing. Rename the various parsed corpus files for progress study and future reference. */ { char tfnam1[15], tfnam2[15]; IClose(&ibuf); if (fclose (obuf)) Fatal ("Disk full!"," "); strcpy (tfnam1, "parses."); strcat (tfnam1, ext); strcpy (tfnam2, "oparses."); strcat (tfnam2, ext); remove (tfnam2); /* flush existing OPARSES */ rename (tfnam1, tfnam2); /* rename PARSES to OPARSES */ rename ("parses.tmp", tfnam1); } void Command() /* process an interactive command */ /* In sentence by sentence text parsing or console input, the computer requests input. This may be a sentence for parsing, or a command beginning with '-'. If the latter, the '-' is stripped and this routine is called to process the command */ { nfputs(DS); switch (toupper (*++ic)) { case 'D': /*Delete the previous sentence from the saved text file*/ iline[0] = '\0'; puts("The previous utterance will be deleted."); fputs("\n The above utterance was deleted\n",sbuf); dirty = TRUE; break; case 'M': /*Write the machine parse of the current specimen*/ WriteString (actualprs,0); /*Write actual words*/ nfputs(DS); WriteString (actualprs,1); /*Write lexemes in place of words*/ break; case 'R': /* Display the instructions again*/ showins1(); break; case 'H': /*Write the 'humanized' parse of the current specimen*/ WriteString (humactprs,0); nfputs(DS); WriteString (humactprs,2); /*'Humanize' lexeme names before write*/ break; case 'B': /*Turn on an internal debug flag for parse tracing*/ yydebug = !yydebug; printf ("internal debug flag %s\n", yydebug ? "ON" : "OFF"); break; case 'L': /*Display the linear parse of the current specimen again*/ WriteString(humactprs,0); break; case 1: /*Display the full tree of the current specimen*/ DspString (fullprs, FALSE); break; case 'G': /*Display a 'word graph' of the current specimen*/ DspString (fullprs,2); break; case 'O': /*Write all parses and commands to a file named OUTPUT*/ switch(wallp) { /*If file not open, open it*/ case 0: IOpen("OUTPUT",&obuf,"w"); puts("OUTPUT file opened"); wallp = 1; break; case 1: /* If it is on, stop writing */ puts("OUTPUT writing suspended"); wallp = 2; break; case 2: puts("OUTPUT writing recommenced"); /*If suspended, restart*/ wallp = 1; default: break; } break; case 'S': /*Display the preparsed string with words and lexemes*/ LexWrite (); break; case 'T': /*Display a reduced tree of the parse*/ DspString (fullprs, TRUE); break; case 'X': /*Close files and return to OS */ case 'Q': if (wallp) IClose (&obuf); if (itextf && strlen(iline)) { fputs(" ",tbuf); fputs(iline,tbuf); } if (itextf) { IClose(&ibuf); IClose(&tbuf); while (dirty) CheckSave(); IClose(&ibuf); } exit (0); case '?': /*Show command list*/ Help(); break; default: /*Indicate command error*/ printf ("?? Unknown command: '-%c'\n", *ic); break; } nfputc('\n'); } void editline() /* This routine changes one string for another in the line buffer iline The strings are indicated /old string/new string/ On entry *ic points to the beginning of the edit record */ { #ifdef DOS char buf[BIGLIN],*ed,*org,*chg,*spr; chg = buf; /*Set a pointer to the output line*/ org = iline; /*The line to be edited */ repeat { ed = &tline[1]; /*The first character after the slash*/ while(*org && (*org != *ed)) *chg++ = *org++; /*Copy 1st pt */ if(!*org) { puts ("\nEdit string not found"); break; } spr = org; /* Mark our place */ while(*org++ == *ed++); /*Match the old record*/ if (*(ed-1) == '/') { /*Matched everything*/ --org; while (*ed && *ed != '/') *chg++ = *ed++; /*Copy the changed part*/ break; } else { org = spr; /*Reset to the point of match*/ *chg++ = *org++; /*Copy the matching character*/ } } while (*org) *chg++ = *org++; /*Finish copying the line*/ *chg = '\0'; /* Terminate the changed line */ strcpy(iline,buf); nfputs(DS); nfputs((unsigned char *)iline,0); nfputs(DS); dirty = TRUE ; #endif } void Entries() /* This routine does all the processing of input, by geteting a line, parsing it, and writing out the parse according to the input and output flags */ { repeat { if (GetLine()) { badparse = 0; Parse(); WriteParse(ptype); if (consp || textf) nfputs(DS); } else if (!consp && !textf) break; } } void Error (char *msg,char *arg) /* Report an non-fatal error argument when required*/ { if (!consp) printf ("Error in specimen %s: ", label); printf (msg, arg); } void Fatal (char *msg, char *arg1) /* This is similar to the above, but the error is fatal, and processing must be terminated */ { puts ("Fatal error: "); printf (msg, arg1); exit (1); } Boolean GetLine (void) /* Prompt (if input from console) and accept input. Append a period if none. Skip any lead spaces. If the line is ? show the command list. If it begins with '-' process a command. If it begins with '/' process an edit of the current line. Other options as indicated in code. This routine handles all types of line input */ { char *str; short i,ch; if (consp) repeat{ /*Console or line by line input*/ puts("\n--> "); if (wallp==1) fputs ("\n--> ", obuf); /*Write to OUTPUT*/ ngets (tline, BIGLIN); i = strlen(tline); /*Append a . if not present*/ if (i && tline[i-1] !='.') { tline[i++] = '.'; tline[i] = '\0'; } ic = tline; ISkipSpc(); /*Get rid of leading space*/ if (*ic == '?') Help(); /*Process a '?'*/ else if (*ic == '-') Command(); /*Process a command*/ else if(*ic=='/') { /*Process an edit change*/ editline(); ic = iline; return(TRUE); } else if (*ic) { if (itextf && strlen(iline)){ /*Save it in text buffer*/ fputs(" ",tbuf); fputs(iline,tbuf); } if (itextf) dirty = TRUE; strcpy(iline,tline); puts(" "); if (itextf) { /*Save in TEXTOUT as well*/ fputs("\n ",sbuf); fputs(iline,sbuf); fputs("\n ",sbuf); } return (TRUE); } else if (itextf) { /* Need new line from text file */ if (strlen(iline)) { /*Write (changed?) line to tempf*/ fputs(" ",tbuf); fputs(iline,tbuf); } str = iline; while (!isalpha((ch = getc(ibuf))) && ch>0){} /*Skip nonalpha*/ ungetc(ch,ibuf); /*Then read file till '.' found*/ while ((ch = getc(ibuf)) != '.' && ch > 0) *str++ = ch; *str++ = '.'; *str = '\0'; ic = iline; if (ch<0) { /*End of file found. Notify user*/ puts ("\nParse complete. If you wish to examine the parsed file, you may leave LIP now"); puts ("by typing -x or -q at the arrow prompt.\n"); IClose(&ibuf); IClose(&tbuf); IClose(&sbuf); while (dirty) CheckSave(); /*See if tempf to be saved*/ itextf = textopen = FALSE; return FALSE; } nfputs(DS); nfputs((unsigned char *)iline,0); nfputs(DS); return TRUE; } else { /*CR when no text file open. Ask for text file and method*/ clrscr(); puts("\nIf you do not have a text file to parse, press . Otherwise press RETURN: "); if (getche() == 0x1b) { puts(""); return FALSE; } puts("\nDo you wish your text-file parsed utterance by utterance? Answer Y(es) or N(o):"); ch = getche(); if (toupper(ch) =='N' || ch =='\r' || ch == '\n') { textf = TRUE; consp = itextf = FALSE; } else itextf = TRUE; puts(""); opentext(); return FALSE; } } else if (textf) { /*All at once text parse in progress. Get next line*/ str = iline; while (!isalpha((ch = getc(ibuf))) && ch>0){} ungetc(ch,ibuf); while ((ch = getc(ibuf)) != '.' && ch > 0) *str++ = ch; *str++ = '.'; *str = '\0'; ic = iline; if (ch<0) { /*Notify user of end of file*/ puts ("\nParse complete. If you wish to examine the parsed file, you may leave LIP now"); puts ("by typing -x or -q at the arrow prompt.\n"); IClose(&ibuf); textf = FALSE; consp = TRUE; return FALSE; } nfputs(DS); nfputs((unsigned char *)iline,0); nfputs(DS); return TRUE; } else repeat{ /*Final case for corpus parsing. Get a corpus line*/ if (!INextLine()) return (FALSE); if (!isspace (*iline)) return (TRUE); } } short getmode(void) /* Request user for type of parsing desired with a menu, and return the integer choice */ { short ch; clrscr(); puts (" You may decide now to:\n"); puts (" 1 Parse sentences entered at the keyboard."); puts (" 2 Parse a text-file all at once."); puts (" 3 Parse a text-file interactively."); puts (" 4 Receive instructions.\n"); vgotoxy(7,15); puts("Select <1 2 3 4> [or press RETURN for option 1]:"); ch = getche(); if (ch=='\n' || ch == '\r') ch = '1'; if (ch >'0' && ch <'6') { puts("\n"); return ch; } else return getmode(); } void vgotoxy(short y, short x) /* This provides for customized cursor positioning on screen. It is needed to distinguish between Turbo C and Think C commands. */ { #ifndef MAC // gotoxy(x,y); #else // cgotoxy(x,y,stdout); #endif } void Help(void) /* Help this user by displaying possible command types. */ { clrscr(); puts ("Choose any of the following parsing styles:\n"); puts (" -l Display the human parses Linearly. [Default option.]"); puts (" -s Display the specimen as a preparsed String."); puts (" -h Display the Human parse with both words and lexemes."); puts (" -m Display the Machine parse with both words and lexemes."); puts (" (Exhibits some normally invisible features of 'machine Loglan'.)"); puts (" -t Display the parse Tree of the current or previous specimen."); puts (" -g Display the word graph of the current specimen."); puts ("Other commands include:\n"); puts (" -d Delete the previous specimen."); puts (" -r Read instructions again."); puts (" -o Start or stop recording screen Output to a file named OUTPUT."); puts (" -b Toggle the internal Debug flag."); puts (" s Stop or restart scrolling.(Useful for 'tall' parse trees)"); puts (" RETURN Change to text-parsing mode."); puts (" -x(-q) Exit(Quit) this parsing session."); puts (" -? Display this page.\n\n"); } void IClose(STREAM buf) /*close file buf. Add end-of-file if open for writing */ { if (*buf != ibuf) fputc(0x1a,*buf); fclose (*buf); } Boolean INextLine(void) /* This is the routine for reading a corpus input line*/ { ic = iline; if (!fgets (iline,BIGLIN,ibuf)) { *iline = NUL; return (FALSE); } return (TRUE); } void IOpen (char *name,STREAM fdesc, char *mode) /* open an input file named name, with file descriptor fdesc, and mode mode. Inform user if file not found */ { while(!(*fdesc = fopen (name,mode))) { printf("Can't open %s!. Enter new name or RETURN to quit\n",name); gets(name); if (!name[0]) exit(1); } } void message(short n,short m, unsigned char *str) /* This is equivalent to the alert in MacLIP. These messages are all warnings. n is the alert type (not used for DOS), m the message pointer, and str any additional information which needs to be added*/ { char *strg; strg = (char *)str; switch (m) { case 5: Error ("Unknown word: '%s'\n", strg); break; case 9: Error ("Invalid compound: '%s'\n",strg); break; case 13: Error ("YYParse error: %s\n", strg); break; case 19: Error ("PPFindList: found same word twice ('%s')\n",strg); break; case 20: Error ("PPSkipList: Warning: too many args or no ENDLIST\n"," "); break; default: break; } } void nfputc (char c) /*This is a multiple-file character output message of character c. It is separated from the parse program because the Mac version is much more complex and needed to be separate*/ { if (consp) putc(c,CONOUT); else if (!textf) putc(c,obuf); if (textf || itextf ) putc (c,sbuf); if (wallp==1) putc (c, obuf); } void nfputs (unsigned char *str, short n) /*This is similar to the above for string output of string str. n is a flag, used for different fonts and sizes in Mac, and implemented also in DOS for enhancing Loglan words and lexemes on screen*/ { if (consp) { #ifdef DOS if (n==3) { textcolor(LIGHTRED); /* These are Turbo C specific - the cputs is necessary for colour*/ cputs(str); } else { textcolor(WHITE); cputs(str); } #else printf("%s",str); #endif } else if (!textf) fputs((char *)str,obuf); if (textf || itextf) fputs ((char *)str,sbuf); /* Corrected May 88 */ if (wallp==1) fputs ((char *)str, obuf); } void OpenFiles (char *ext) /* Used only for corpus parsing. Open all needed Corpus files listed in ext */ { char tfnam1[15]; printf ("Starting block %s\n", ext); strcpy (tfnam1, "strings."); strcat (tfnam1, ext); IOpen (tfnam1,&ibuf,"r"); /* RAM Jul 87Because the BDSC capability was removed, all the I/O calls were made standard C instead of passing by the Pf routines */ IOpen ("parses.tmp",&obuf,"w"); } void opentext(void) /* This routine opens text files for input and output as needed. Request parse type as well, and place it in ptype. Default names are supplied. */ { #ifdef DOS if (textopen) return; /*File is already open*/ puts("\n\nWhat parsing style do you want LIP to use? If the linear human style is "); puts("all right, just press RETURN.\n"); puts("If you want any other style, give the appropriate command. Typing '?' will"); puts("allow you to see the command list first: "); while (1) { gets (iline); if (!strlen(iline)) { ptype = GROUP; break; } ic = iline; ptype = 0; if (*ic == '?') { Help(); puts ("What parsing style do you want LIP to use? "); } else if (*ic == '-') { switch (toupper (*++ic)) { case 'M': ptype = MACHINE; break; case 'H': ptype = GPandLX; break; case 'L': ptype = GROUP; break; case 'G': ptype = FULL; break; case 'S': ptype = LEXEMES; break; case 'T': ptype = SHORT; break; default: Help(); } } if (ptype) break; } puts("\nWhat is the name of the textfile? If it's TEXTIN, just press RETURN: "); gets(fname); if (!strlen(fname)) strcpy(fname,"TEXTIN"); IOpen(fname,&ibuf,"r"); puts("\nName a file for parsed output. If TEXTOUT is all right, press RETURN: "); gets(iline); if (!strlen(iline)) strcpy(iline,"TEXTOUT"); IOpen(iline,&sbuf,"w"); iline[0] = '\0'; if (itextf) IOpen("tempf",&tbuf,"w"); textopen = TRUE; if (itextf) puts("\nPress RETURN at the arrow-prompt to start parsing."); #endif } #ifdef MACDOS void clrscr(void) /* A screen clearing routine since Think C does not provide one */ {// cgotoxy(1,1,stdin); // ccleos(stdin); } char getche(void) // Required by MAC to input unbuffered characters i.e. no CR needed before acceptance { char chr; // csetmode(C_CBREAK,stdin); chr = getchar(); // csetmode(C_ECHO,stdin); return chr; } #endif void showins1(void) /* Display some pages of instructions */ { short ch,col; fseek(rbuf,0L,0); clrscr(); while ((ch=getc(rbuf)) != '@' && ch>0) putchar(ch); col = getche(); if (col == ' ') showins2(); } void showins2() { short ch,col; clrscr(); while ((ch=getc(rbuf)) != '@' && ch>0) putchar(ch); col = getche(); if (col == ' ') showins3(); } void showins3() /*Display additional instruction pages*/ { short ch,col; clrscr(); while ((ch=getc(rbuf)) != '@' && ch>0) putchar(ch); col = getche(); if (col == ' ') showins4(); } void showins4() /*Display additional instruction pages*/ { short ch,col; clrscr(); while ((ch=getc(rbuf)) != '@' && ch>0) putchar(ch); col = getche(); if (col == ' ') showins5(); } void showins5() /*Display additional instruction pages*/ { short ch; clrscr(); while ((ch=getc(rbuf)) != '@' && ch>0) putchar(ch); getche(); } void WriteParse(short ptype) /*Write out a parse using write style ptype*/ { if (!consp&&!textf) { WriteRslt(0); return; } /*Don't try to write blank error parses, unless ptype is preparse string*/ if (!fullprs[0] && ptype != LEXEMES) return; switch(ptype) { case GROUP: /*So called linear (bracketed) parse*/ WriteString(humactprs,0); break; case FULL: /*A full tree parse*/ DspString(fullprs,2); break; case MACHINE: /*A 'machine' parse with lexemes*/ WriteString(actualprs,0); nfputs(DS); WriteString (actualprs,1); break; case LEXEMES: /*The preparsed string with lexemes*/ LexWrite(); break; case GPandLX: /*The 'humanized' parse with lexemes*/ WriteString (humactprs,0); nfputs(DS); WriteString (humactprs,2); break; case SHORT: /*A reasonable reduced tree*/ DspString(fullprs,TRUE); break; default: WriteRslt(0); break; } } char* CtoPstr(char* wd) { return wd; } void TextSize(int val) {}