#util.g /* * QPARSE.DRC - parsing routines for Quest. */ extern _scAbort(*char message)void; type DICTENTRY = struct { *DICTENTRY d_next; *char d_text; int d_id; int d_type; }, FORMTYPE = enum {REQID, REQTYPE, OPTID, OPTTYPE, MULTIPLE}, FORMLIST = struct { *FORMLIST f_next; FORMTYPE f_kind; int f_data; }, GRAMMAR = struct { *GRAMMAR g_next; *FORMLIST g_sentence; int g_id; }, WORDLIST = struct { *WORDLIST wl_next; int wl_position; int wl_type; int wl_id; }; *DICTENTRY Dictionary; *GRAMMAR Grammar; **FORMLIST WordPtr; *WORDLIST InputSentence; *GRAMMAR MatchedSentence; *char UnknownWord; *WORDLIST PrefixList; int ScanPos; ushort ScanCount; bool PrefixEnabled; /* * psInit - initialize the parser. */ proc nonrec psInit(bool prefixEnabled;)void: PrefixEnabled := prefixEnabled; Dictionary := nil; Grammar := nil; InputSentence := nil; UnknownWord := nil; PrefixList := nil; ScanPos := 0; corp; /* * psWord - add a word to the dictionary. */ proc nonrec psWord(int id; *char txt; int typ)void: *DICTENTRY d; d := new(DICTENTRY); d*.d_next := Dictionary; d*.d_text := txt; d*.d_id := id; d*.d_type := typ; Dictionary := d; corp; /* * psDel - delete a word from the dictionary. */ proc nonrec psDel(int id)void: **DICTENTRY pd; *DICTENTRY d; pd := &Dictionary; while pd* ~= nil and pd**.d_id ~= id do pd := &pd**.d_next; od; if pd* ~= nil then d := pd*; pd* := d*.d_next; free(d); fi; corp; /* * psgBegin - set up to start a new sentence in the grammar. */ proc nonrec psgBegin(int id)void: **GRAMMAR pg; *GRAMMAR g; pg := &Grammar; while pg* ~= nil do pg := &pg**.g_next; od; g := new(GRAMMAR); g*.g_next := nil; g*.g_id := id; WordPtr := &g*.g_sentence; pg* := g; corp; /* * psgWord - add a word to the current grammar sentence. */ proc nonrec psgWord(FORMTYPE kind; int data)void: *FORMLIST w; w := new(FORMLIST); w*.f_kind := kind; w*.f_data := data; WordPtr* := w; WordPtr := &w*.f_next; corp; /* * psgEnd - end of the current grammar sentence. */ proc nonrec psgEnd()void: WordPtr* := nil; corp; /* * psgDel - delete a rule from the grammar. */ proc nonrec psgDel(int id)void: **GRAMMAR pg; *GRAMMAR g; *FORMLIST f, temp; pg := &Grammar; while pg* ~= nil and pg**.g_id ~= id do pg := &pg**.g_next; od; if pg* ~= nil then g := pg*; pg* := g*.g_next; f := g*.g_sentence; free(g); while f ~= nil do temp := f; f := f*.f_next; free(temp); od; fi; corp; /* * CAP - capitalize a letter. */ proc nonrec CAP(char ch)char: if ch >= 'a' and ch <= 'z' then ch - 32 else ch fi corp; /* * psFind - look a word up in the dictionary. */ proc nonrec psFind(*char wrd)int: *DICTENTRY d; *char p1, p2; d := Dictionary; while if d = nil then false else p1 := wrd; p2 := d*.d_text; while p1* ~= '\e' and CAP(p1*) = CAP(p2*) do p1 := p1 + 1; p2 := p2 + 1; od; CAP(p1*) ~= CAP(p2*) fi do d := d*.d_next; od; if d = nil then 0 else d*.d_id fi corp; /* * _psLookup - return the DICTENTRY for the indicated word. */ proc nonrec _psLookup(int id)*DICTENTRY: *DICTENTRY d; d := Dictionary; while if d = nil then _scAbort("psLookup: can't find id."); fi; d*.d_id ~= id do d := d*.d_next; od; d corp; /* * psType - find the type of the word with the given id. */ proc nonrec psType(int id)int: _psLookup(id)*.d_type corp; /* * psGet - return the text of the word with the given id. */ proc nonrec psGet(int id)*char: _psLookup(id)*.d_text corp; /* * _delimChar - say if a character is a delimiter character. */ proc nonrec _delimChar(char ch)bool: not (ch >= 'A' and ch <= 'Z' or ch >= 'a' and ch <= 'z' or ch >= '0' and ch <= '9') corp; /* * psParse - parse an input sentence. */ proc nonrec psParse(*char sentence)int: **WORDLIST wp; *FORMLIST f; *WORDLIST w; *char wordStart; int data, position; char ch; bool bad; /* first, free the previous input sentence list: */ while InputSentence ~= nil do w := InputSentence; InputSentence := InputSentence*.wl_next; free(w); od; if UnknownWord ~= nil then Mfree(pretend(UnknownWord, *byte), CharsLen(UnknownWord) + 1); UnknownWord := nil; fi; while PrefixList ~= nil do w := PrefixList; PrefixList := PrefixList*.wl_next; free(w); od; /* turn the input sentence into a list of words: */ ScanPos := 0; wp := &InputSentence; bad := false; while while sentence* = ' ' do sentence := sentence + 1; od; not bad and sentence* ~= '\e' do if PrefixEnabled and sentence* = ':' and PrefixList = nil then /* first part was a prefix: */ wp* := nil; PrefixList := InputSentence; wp := &InputSentence; sentence := sentence + 1; else wordStart := sentence; sentence := sentence + 1; while not _delimChar(sentence*) do sentence := sentence + 1; od; ch := sentence*; sentence* := '\e'; w := new(WORDLIST); w*.wl_id := psFind(wordStart); if w*.wl_id = 0 then UnknownWord := pretend(Malloc(CharsLen(wordStart)+1), *char); CharsCopy(UnknownWord, wordStart); bad := true; else w*.wl_type := psType(w*.wl_id); fi; wp* := w; wp := &w*.wl_next; sentence* := ch; fi; od; wp* := nil; /* if an unknown word was found, don't go any further: */ if bad then -1 else /* check the forms in the grammar for a matching sentence form: */ MatchedSentence := Grammar; while if MatchedSentence = nil then bad := true; false else f := MatchedSentence*.g_sentence; w := InputSentence; bad := false; position := 1; while not bad and f ~= nil do data := f*.f_data; case f*.f_kind incase REQID: if w ~= nil and data = w*.wl_id then w*.wl_position := position; f := f*.f_next; w := w*.wl_next; else bad := true; fi; incase REQTYPE: if w ~= nil and data = w*.wl_type then w*.wl_position := position; f := f*.f_next; w := w*.wl_next; else bad := true; fi; incase OPTID: if w ~= nil and data = w*.wl_id then w*.wl_position := position; w := w*.wl_next; fi; f := f*.f_next; incase OPTTYPE: if w ~= nil and data = w*.wl_type then w*.wl_position := position; w := w*.wl_next; fi; f := f*.f_next; incase MULTIPLE: while w ~= nil and data = w*.wl_type do w*.wl_position := position; w := w*.wl_next; od; f := f*.f_next; esac; position := position + 1; od; if w ~= nil then bad := true; fi; bad fi do MatchedSentence := MatchedSentence*.g_next; od; if bad then 0 else MatchedSentence*.g_id fi fi corp; /* * pspBad - return the unknown word (if any). */ proc nonrec pspBad()*char: UnknownWord corp; /* * pspWord - return the (first or any) word which fits the indicated position * in the matched sentence form. */ proc nonrec pspWord(int pos)int: *WORDLIST w; ushort i; if pos ~= ScanPos then ScanPos := pos; ScanCount := 0; fi; w := InputSentence; while w ~= nil and w*.wl_position < pos do w := w*.wl_next; od; i := ScanCount; ScanCount := ScanCount + 1; while w ~= nil and i ~= 0 do i := i - 1; w := w*.wl_next; od; if w = nil or w*.wl_position ~= pos then 0 else w*.wl_id fi corp; /* * pspPref - return words in the prefix list. */ proc nonrec pspPref()int: *WORDLIST p; int id; if PrefixList = nil then 0 else p := PrefixList; PrefixList := PrefixList*.wl_next; id := p*.wl_id; free(p); id fi corp;