import vector import stringplus import association type Iterator= { reset->Void hasNext->Boolean get->T next->T} type Vector = { size->Number isEmpty->Boolean clear->Void contains(_:T)->Boolean addFirst(_:T)->Void addLast(_:T)->Void firstElement->T lastElement->T removeFirst->T removeLast->T removeValue(_:T)->T indexOf(_:T)->Number at(_:Number)->T setValue(_:T)at(_:Number)->T add(_:T)at(_:Number)->Void removeFromIndex(_:Number)->T iterator->Iterator asString->String forEachDo(_:Block)->Void map(_:Block)->Vector ensureCapacity(_:Number)->Void capacity->Number copyInto(_)->Void indexOf(_:T)startingFrom(_:Number)->Number setSize(_:Number)->Void trimToSize->Void} type Association = { ==(_:Association)->Boolean hashcode->Number getValue->V getKey->K setValue(_:V)->V asString->String} type StringPair = { getFirst->String getSecond->String hashcode->Number ==(_:StringPair)->Boolean asString->String} type WordStream = { addLexItems(_:String)->Void nextToken->String hasMoreTokens->Boolean resetTo(_:Number)->Void currentIndex->Number} type FreqList = { add(_:String)->Void get(_:Number)->String asString->String} //======PAIR===== method newPair(p1:String, p2:String)->StringPair is public{Pair.new(p1, p2)} class Pair.new(fst:String, snd:String){ var first:String is readable := fst var second:String is readable := snd method getFirst->String is public{first} method getSecond->String is public{second} // Won't be used, but necessary so that StringPair can be used // as key of Association method hashcode->Number is public{first.hashcode + second.hashcode} method ==(other:StringPair)->Boolean is public{ (first == other.getFirst) && (second == other.getSecond)} method asString->String is public{"<{first}, {second}>"} } //======WORDSTREAM====== method newWordStream->WordStream is public{WordStreamClass.new} class WordStreamClass.new{ // list of words and punctuation from input text var lexItems:Vector is readable := vector.new // index of next item to be returned from nextToken method var nextItem:Number is readable := 1 // characteres indicating end of word var delimiter:String is readable := " -'\";:,.!?\n\t" // @param line string containing words to be placed in list // of lexical items // @post all lexical items added to list method addLexItems(line:String)->Void is public{ var strIter := line.iter var currItem:String := "" var nxt:String := "" // while line contains more characters, parses next character // if character is a delimiter, adds current word and // delimiter (if not whitespace) to list // and starts a new word // otherwise adds character onto current word while{strIter.havemore} do { nxt := strIter.next if(stringplus.contains(delimiter, nxt)) then{ if(currItem != "") then {lexItems.addLast(currItem)} if(!isWhiteSpace(nxt)) then {lexItems.addLast(nxt)} currItem := ""} else{currItem := currItem ++ nxt} } if(currItem != "") then {lexItems.addLast(currItem)} } // @param item character from input // @return true iff item corresponds to whitespace (space, newline, or tab) method isWhiteSpace(item:String)->Boolean is confidential{ return (item == " ") || (item == "\n") || (item == "\t")} // @return next non-whitespace token from list of lexical items method nextToken->String is public{ var test:String := lexItems.at(nextItem) while{(nextItem <= lexItems.size) && isWhiteSpace(test.at(1))} do{ nextItem := nextItem + 1 test := lexItems.at(nextItem)} if (nextItem <= lexItems.size) then { nextItem := nextItem + 1 return lexItems.at(nextItem - 1)} else{ print "out of tokens" return ""} } // @return true iff there are more tokens to be returned from list method hasMoreTokens->Boolean is public{nextItem <= lexItems.size} // @post resets nextItem to specified index method resetTo(index:Number)->Void is public{nextItem := index} // @return the index of the next item to be considered method currentIndex->Number is public{nextItem} } //===============FREQLIST=============== method newFreqList->FreqList is public{FreqListClass.new} class FreqListClass.new{ // list of associations holding words and their frequencies var flist:Vector is readable := vector.new // total # of instances of words held in list var totalOccurrences:Number is readable := 0 // @param word the word to be tallied in frequency list // @post if word was not in frequency list it is added // w/ frequency 1; if already in, increase frequency by 1 method add(word:String)->Void is public{ var assoc:Association := association.withKey(word)value(0) var wordNo:Number := flist.indexOf(assoc) //location of word in list if (wordNo == -1) then { // word was not in list, insert it assoc.setValue(1) flist.addLast(assoc)} else{ // word was in list, bump frequency var element:Association := flist.at(wordNo) var newValue:Number := element.getValue + 1 element.setValue(newValue) } totalOccurrences := totalOccurrences + 1 } // @param prob probability chosen // @return word chosen tandomly from words in frequency list // The probability of a word being chosen is proportional to // its frequency strored in the list. method get(prob:Number)->String is public{ var count:Number := 0 //sum of frequencies so far //number between 1 and size of list (inclusive) var target:Number := (prob * totalOccurrences).truncate var letterNo:Number := 1 var element:Association while{(count <= target) && (letterNo <= flist.size)} do { element := flist.at(letterNo) var probOfElt:Number := element.getValue count := count + probOfElt letterNo := letterNo + 1 } return element.getKey } method asString->String is public{"Frequency List: {flist}\n"} }