| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268 |
-
- lenueiAi sjasn
- TopSpeed Modula-2
- For IBM® Personal Computers and Compatibles
- User’s Manual
- Jensen & Partners International
- LICENSE STATEMENT
- Jensen & Partners International hereby grants you a non-exclusive license to use the TopSpeed Modula-2 compiler and libraries. You may use the software on any computer, provided that the software cannot possibly be used on more than one computer at the same time. You may make copies of the software for the sole purpose of loading it into the computer on which you wish to use it, or for keeping a maximum of two backup copies.
- WARRANTY
- Jensen & Farmers International warrants the enclosed diskettes to be accurate copies of the master disks, and will replace any defective copies free of charge for a period of 60 days after purchase.
- Jensen & Farmers International hereby explicitly disclaims all other warranties whether express or implied, including without limitation, the implied warranties of merchantability and fitness for any particular purpose. Jensen & Farmers International shall have no liability for consequential, incidental, exemplary or special damages, including lost profits.
- Jensen & Partners International reserves the right to change the product at any time, without prior notice.
- TECHNICAL SUPPORT
- To qualify for technical support fill in and mail the enclosed registration card.
- TopSpeed™ is a trademark of Jensen & Partners International.
- IBM® is a registered trademark of the International Business Machines Corporation.
- Microsoft® is a registered trademark of Microsoft Corporation.
- WordStar® is a registered trademark of MicroPro International Corporation.
- Turbo Pascal® is a registered trademark of Borland International, Inc.
- Copyright © 1988 by Jensen & Partners International. All rights reserved.
- Printed in the United States of America.
- Contents
- 1 Introduction 1
- The TopSpeed Modula-2 Package 1
- How to Use This Book 2
- Typographic Conventions 2
- Structure 2
- 2 Features of the TopSpeed Modula-2 System 5
- Modules 5
- Separate Compilation 6
- Automatic Librarian 6
- Smart Linking 7
- Definition Parts Always Recompiled 7
- Automatic Make Facility 7
- Advanced Data Structures 8
- Full Segment Control 8
- Type Checking 8
- Procedures 8
- Powerful Control Statements 9
- Multitasking 9
- Program Control 9
- Programming Environment 9
- Debugging 10
- 3 Getting Started 11
- Summary of Distribution Disks 11
- Running on a Hard Disk System 12
- Running on a System with Two Floppy Disks 12
- Running on a System Using 3| Inch Disks 13
- How to Continue 13
- If You Are Patient 13
- If You Dislike Reading Manuals 13
- 4 Modula-2 Case Studies 15
- Hello 16
- iv Contents
- Pythagoras 18
- The FOR Statement 18
- Exercise 19
- Music 20
- Data Types 20
- Constant Declarations 21
- Procedures 21
- Strong Typing 22
- Library Routines 22
- Anagram 22
- More About Procedures and Parameters 24
- Variable and value parameters 24
- More About Loops 25
- Creating Modules 25
- Creating a Definition File 26
- Creating an Implementation File 26
- Open Array Parameters 27
- Puzzle 27
- Function Procedures 29
- Subrange Declarations 29
- More on Types 29
- Graphics 30
- Using Library Routines 32
- RECORD Types 32
- Sorting 33
- Command Line Arguments in the TopSpeed Modula-2 Environment 34
- Heapsort and Quicksort 36
- Implementing Quicksort 36
- Procedure Parameters 37
- Nested Procedures 38
- Recursion and the Compiler 38
- Calculator 38
- Enumeration Data Types 41
- Variant Records 42
- CASE Statements 42
- 5 The TopSpeed Modula-2 Environment 45
- TopSpeed Modula-2: Features 45
- Starting Up the Environment 47
- The Help System 47
- Help Lines 47
- The Menu System 48
- Moving Around Menus 48
- ShortCut Keys 50
- Windows in the Environment 51
- Zoom/Unzoom 52
- User Dialog Windows 52
- Single Line Input 52
- Multiple Line Input 53
- File Selection Window 53
- The File Menu 55
- Load File 55
- Pick File 56
- Save File 57
- All Save 57
- Main Module 57
- Change Dir 57
- Files Dir 57
- DOS Shell 58
- Execute 58
- Quit 58
- The Editor 59
- The Editor Menu System 59
- Pop Up Menus 59
- Loading a File 60
- Saving a File 61
- Maximum File Sizes 62
- Removing a File from an Editor Window 62
- Moving Between Editor Windows 62
- Editor Commands 62
- Insertion and Deletion 63
- Cursor Movement 63
- Block Commands 64
- Editor Options 65
- Search and Replace 66
- Other Editor Commands 66
- Compiling and Running Programs 67
- Compiling 67
- Compilation Errors 68
- The Main Module 69
- Making a Program 69
- Running Programs 70
- Run-Time Errors 70
- Linking a Program 71
- Linker Errors 72
- The Options Menu 73
- Compiler Options 73
- B - Defaults for Run-Time Checks 73
- D - Generate Debug Information 73
- E - Stop On First Error 73
- F - Filename Check 73
- J - Suppress Libraries 73
- N - Line Numbers 73
- V - Volatile Variables 74
- Linker Options 74
- M - Map File 74
- I - Initialize Segments 74
- S - Detailed Segment Map 74
- C - Case Sensitive Link 74
- W - Suppress Warnings 74
- T - Trace References 74
- Run Options 74
- C - Command Line 75
- A - Auto Make 75
- T - Timed Run 75
- F - Find Error 75
- Editor Options 75
- A - Auto Save Files 75
- F - Default Filenames 75
- E - Default Extensions 76
- N - Number Of Backups 76
- T - Top Scroll Zone 76
- B - Bottom Scroll Zone 76
- Setup Options 76
- C - CGA Snow Check 76
- B - BIOS Scrolling 76
- H - High Background 76
- X - Solid Cursor 76
- R - Load Redirection File 77
- L - Load Options/Windows 77
- S - Save Options/Windows 77
- Make All 77
- The Information Window 77
- The Redirection File 77
- The Batch Compiler and Linker 78
- Customizing the Menu 79
- Changing the Main Menu Type 80
- Changing Menu Text 80
- Changing the Menu Tree 81
- Changing ShortCut Keys 81
- External DOS Commands 82
- The Editor Keys and Menus 82
- Changing Help Lines 83
- Menu Definition File Format 83
- Menu Directives 83
- Menu Type 83
- Editor Section 84
- Help Lines 84
- ShortCut Key Definition 85
- Submenu Title 85
- Comment 85
- Menu Line Definition 86
- Menu Actions 87
- Pre-Defined Actions 87
- Global Actions 87
- Editor Actions 88
- External Commands 88
- External Command Parameters 89
- Key Sequences 89
- Changing Windows 90
- Repositioning Windows 90
- Resizing Windows 91
- Recoloring Windows 91
- Customizing the Error Messages 92
- 6 The Language 95
- Textual Topics 96
- Tokens 96
- Syntax 98
- Declarations and Visibility 99
- Types 100
- Numeric Types 100
- CARDINAL Types 100
- INTEGER Types 101
- REAL Types 101
- Ordinal Types 101
- CHAR Type 101
- Enumeration Types 101
- Subrange Types 102
- Set Types 102
- Array Types 103
- Record Types 103
- Pointer Types 104
- Type Compatibility 105
- Objects and Values 106
- Constants 106
- Set Values 107
- Designators 108
- Expressions 109
- Statements Ill
- Assignment Statement Ill
- IF Statement 112
- CASE Statement 112
- WHILE Statement 113
- REPEAT Statement 113
- LOOP and exit Statements 113
- FOR Statement 114
- WITH Statement 114
- GOTO Statement 115
- Procedures 115
- Bodies 116
- Calling Procedures 118
- Procedure Types 119
- Predefined Procedures 120
- Predefined Function Procedures 120
- Predefined Proper Procedures 121
- Modules 121
- Server Modules 122
- Importing 123
- Local module 124
- Sources for Language Examples 124
- 7 The Compiler 127
- The OBJ-file 127
- Data Representation 128
- Calling Conventions 130
- The Stack Frame 130
- Parameter Passing 131
- Function Results 132
- Options (on Command Line) 132
- Directives (in Source Text) 134
- Interface to Other Languages 136
- Controlling Run-Time Program Structure 137
- Segments, Groups and Classes 137
- Addressing Items 139
- Naming Conventions 139
- 8087 Support 140
- Interrupt Handlers 140
- 8 The TopSpeed Modula-2 Library 143
- Introduction 143
- Library Overview 144
- SYSTEM 144
- AsmLib 144
- MATHLIB 144
- Str 144
- Lib 145
- Storage 145
- Process 145
- Graph 146
- FIO 146
- IO 146
- Window 147
- FloatExc 147
- ProcTrace 147
- How to Use the Library Reference 148
- MODULE Str 148
- General String Procedures 149
- Conversion Procedures 153
- MODULE Lib 156
- Sorting 157
- Random Number Generation 158
- Environment Procedures 159
- Memory Block Operations 160
- DOS Procedures 164
- Address Arithmetic 166
- Long Jumps 168
- Error Handling 169
- Miscellaneous 171
- MODULE IO 173
- Global Variables in IO 173
- Formatted Output 174
- Formatted Input 177
- Basic Input Procedures 180
- Redirection 180
- MODULE FIO 182
- Global Variables in FIO 182
- File Handling 183
- Formatted Output 188
- Formatted Input 192
- Directory Handling 194
- MODULE Storage 197
- Global Variables in Storage 197
- Main Heap Procedures 197
- General Heap Procedures 199
- MODULE SYSTEM 202
- Low-level Processes 203
- Module Priorities in TopSpeed Modula-2 203
- Miscellaneous 208
- MODULE MATHLIB 211
- Error Handling 211
- Conversion Procedures 215
- 8087 Procedures 216
- MODULE FloatExc 217
- MODULE ProcTrace 218
- MODULE Process 220
- Scheduler 221
- Signals 222
- Miscellaneous 224
- MODULE Graph 226
- Global Constants 226
- Graphics Procedures 228
- Initialization Procedures 231
- MODULE Window 232
- Window Constants and Types 232
- Window Management 233
- Coordinate Handling 238
- Window Output Procedures 240
- Multi-Process Support 242
- Palette Windows 243
- Procedure List 246
- Index 249
- Introduction
- The TopSpeed Modula-2 Package
- Welcome to the world of Modula-2! We’re sure you’ll find it exciting and rewarding. The TopSpeed Modula-2 package is a complete Modula-2 development system with all the features you need to make your program development easier, faster, and cleaner. TopSpeed Modula-2 has a completely self-contained, menu driven environment. This environment includes: a multi-window editor; a smart, high-speed linker; an entirely automatic Make facility; and an optimizing compiler.
- The editor lets you edit up to four files simultaneously, in different windows. The compiler is not only very fast, it also produces code better than any existing C, Pascal or Modula-2 compiler. The Make facility automatically determines dependencies among module versions, and will recompile only the modules, that have changed since the last compilation. The TopSpeed Modula-2 environment even makes it possible to locate in-source compiler and run-time errors, as well as providing numerous other features that you’ll explore as we proceed.
- In addition to the environment you will find a library containing useful utilities such as a complete Window Management System, a Time-Sliced Process Manager, powerful Memory Management routines, and a complete set of I/O routines.
- How to Use This Book
- Typographic Conventions
- To set certain information apart from the surrounding text, such material will be presented using different fonts:
- Italics is used to emphasize words.
- Boldface is used to introduce new concepts.
- Typewriter is used to refer to text that may be part of a program or that may be a command to DOS.
- In some cases, the discussion will refer to individual keys on the keyboard. These will appear in a box. For example, |F1|| refers to function key Fl on your keyboard.
- Many of the commands in the TopSpeed Modula-2 environment involve the IAlt|| or |Ctrl|| keys. For such commands, you’ll need to hold down both keys simultaneously. This will be indicated by two adjacent boxes, as injAlt||R||, which means you should press and hold down the lAlt|| and then press the [r]] key.
- A space between two boxes indicates that you need to release the previous key(s) before pressing the key(s). For example, |Ctrl||K|| QT|| says to:
- 1. Press and hold down the |Ctrl|| and then press the key.
- 2. Release the flCtrl|| and ITkII keys (or release just the [k] key).
- 3. Then press the EJI key.
- Structure
- This book will take you through all the features of the TopSpeed Modula-2 system. Depending on your previous knowledge you may want to read only selected sections.
- Here is how the book is structured:
- Chapter 1 is the chapter you are reading right now. It gives you an idea about what is to come.
- Chapter 2 gives a very brief overview of some of the most important features of TopSpeed Modula-2. These features will be discussed in more detail in later chapters.
- Chapter 3 tells you how to install TopSpeed Modula-2 on your system, and how to get started right away. This chapter tells you how to install a “vanilla-flavored” Modula-2 environment. In later chapters you’ll
- Chapter 4
- Chapter 5
- Chapter 6
- Chapter 7
- Chapter 8
- learn how to customize your Modula-2 environment for your habits and needs.
- is a series of program case studies that serve to introduce Modula-2 and the TopSpeed Modula-2 environment to readers with previous programming experience. You’ll find several example programs that illustrate various features of the Modula-2 language. The examples will also show you some of the features of TopSpeed Modula-2 in action.
- explains the TopSpeed Modula-2 environment in detail. This chapter contains the main reference information for TopSpeed Modula-2 commands. You’ll also find out how to customize your TopSpeed Modula-2 environment.
- is a concise technical reference describing the Modula-2 language. This chapter contains a semi-formal summary of the Modula-2 syntax. Your TopSpeed Modula-2 package also includes a more leisurely introduction to Modula-2, in the Modula-2 Tutorial, by K. N. King.
- contains technical details relating to the compiler itself, such as data representation, calling conventions, compiler options etc.
- is a comprehensive reference for the TopSpeed Modula-2 library. It covers each library module and discusses its available procedures in detail. The chapter includes brief descriptions of each procedure, as well as examples showing how to use the procedure.
- Features of the
- TopSpeed Modula-2 System
- Modula-2 is a modem, general purpose programming language. It was designed by Niklaus Wirth, who also developed Pascal. In fact, Modula-2 is a direct descendant of Pascal. You can think of Modula-2 as a “better,” or more powerful, Pascal. Wirth designed Modula-2 to be useful for programming very low-level functions in the computer (accessing disks or I/O ports, etc.) as well as for writing high-level programs such as databases, compilers, word processors and accounting systems. (The TopSpeed Modula-2 system is actually written in TopSpeed Modula-2.)
- In this chapter we will briefly describe some of the major features of TopSpeed Modula-2. You should scan the following paragraphs and read whatever you find interesting.
- Modules
- A Modula-2 program normally consists of a series of modules. Each module is a collection of related procedures and data structures that implement a well-defined section of the total program. For example, the TopSpeed Modula-2 library contains about a dozen modules. These contain the data structures and procedures needed for such tasks as handling strings (Str module), handling I/O for screen and files (IO and FIO modules, respectively), and doing mathematical computations (MATHLIB module).
- A module consists of two parts: the definition part, which describes what the module can do, and the implementation part, which describes how it is done. These two parts are sometimes called the module definition and the module implementation. The definition part lists all the procedures and data you may access from elsewhere in your program (for example, from another module). The module definition thus contains information about the interface for each procedure. The interface specifies the parameters you need to pass when calling the procedure. The implementation part contains the actual code for each procedure.
- Any procedures and data structures included in the definition part can be made accessible to other modules in your programs. However, the implementation part may contain procedures and data structures in addition to those contained in the definition part.
- All procedures and data not listed in the definition part remain private to the implementation part and therefore “invisible” to the rest of the world. Just as a procedure is used as an abstraction to hide details, a module can be used to hide details of a whole range of associated procedures and any common data structures.
- A module that uses another module is called a client. A module that provides services to another module is called a server. A module may be both a client and a server.
- Separate Compilation
- Modules may be compiled separately and saved as object code, which may later become part of a complete program. This means you don’t need to recompile each of the modules every time you make a change in your program; you just need to recompile any modules in which you changed the source code. This greatly speeds the compilation process when your programs use existing modules.
- TopSpeed Modula-2 makes it easy for you to use the library modules in your programs. You can also create and compile your own modules for use in your programs.
- Automatic Librarian
- Modula-2 has built-in, automatic library management. The compiler produces a library file whenever it compiles a module. This makes it possible for the system to include only the procedures and data structures actually being used in programs that use the module. This makes your program file smaller.
- Smart Linking
- In Modula-2 each module has to specify what it uses from other modules. This information makes it possible to automate the linking process in the TopSpeed Modula-2 environment.
- The linker only needs to know the name of the main program. Starting from this information, the linker can gather any routines used in the program or in other modules. If you have several library modules that serve the same purpose, the system lets you specify the sequence in which the libraries should be searched.
- Definition Parts Always Recompiled
- The TopSpeed Modula-2 compiler is capable of very high-speed compilation — up to 20,000 lines/minute. Because of this speed, all visible definition parts used in a program are always recompiled. The definition parts are much shorter than the implementation parts, so this takes almost no time.
- Doing this has the following advantages:
- • It allows recompilation of implementation parts in any order. This is possible because the system knows all the interfaces specified in the definition parts.
- • It avoids the version control problems associated with definition modules that you may have experienced with other Modula-2 compilers.
- • It cuts down on the number of necessary files by avoiding “symbol-files” for the definition parts. The information in the definition parts can be compiled directly into the program, rather than requiring separate files for storing the symbol information.
- Automatic Make Facility
- In a large program the module dependencies can become very complicated. This makes it difficult to keep track of the program connections. To help overcome this difficulty, TopSpeed Modula-2 provides an automatic Make facility, which does a high-speed analysis of all module dependencies and module time-stamps.
- The system can use this dependency information to determine what modules need to be recompiled. The system recompiles only the modules affected by previous changes. The information from the Make facility makes it possible to determine automatically what modules need to be recompiled.
- Advanced Data Structures
- Both the simple and the aggregate data structures you may know from C or Pascal are fully supported in Modula-2. These include signed and unsigned integers of various sizes, floating point values, uni- and multi-dimensional arrays, records, variant records, sets up to 64K elements, short and long pointers, procedure variables and more.
- Full Segment Control
- TopSpeed Modula-2 offers a unique feature that allows you to utilize the segmented memory of the 80x86 CPU. Your program and data may be as large as 1 megabyte and still use “short calls” for selected procedures, within as well as across modules. You may also use “short pointers” to speed up execution. In contrast to some other languages that allow the use of short pointers in selected segments only, TopSpeed Modula-2 allows the simultaneous use of short pointers in any segments you choose. You may even move the segments around during program execution to achieve optimal use of the available memory. (See Chapter 6 for further details.)
- Type Checking
- Like other high-level languages, Modula-2 does type checking when you use variables — to ensure that you don’t try to assign the wrong type of information to particular variables. For safer programming, Modula-2 has even stricter type checking than its ancestor Pascal. However, Modula-2 does allow you to override type checking whenever necessary. This makes it possible to implement any “tricks” you may need use in order to accomplish exactly what you want.
- Procedures
- Modula-2 offers advanced procedure parameter handling. You may pass arrays of any size to the same procedure or even pass a procedure as a parameter to another procedure.
- Modula-2 includes a procedure type. This type lets you assign procedures to variables dynamically.
- TopSpeed Modula-2 also makes it simple to implement interrupt service procedures, so that you can specify the actions to take place if a hardware or software interrupt occurs.
- Powerful Control Statements
- Modula-2 offers all the control statements available in Pascal. In addition to this, Modula-2 offers, among other things, a LOOP . . . END construct from which you may exit using as many exit points as desired. (See Chapter 6 for the complete set of Modula-2’s control statements.)
- In Modula-2, evaluation of Boolean conditions occurs from left to right, and ends as soon as the value of the condition is known. For example, suppose you have an expression that tests whether A and B and C are all TRUE. When evaluating this expression, the system will stop as soon as it finds that one of the terms is FALSE, since that makes the entire compound expression FALSE.
- Because of this evaluation method, the use of control statements in Modula-2 is much simpler and more efficient than in languages that do not provide this feature. If you’ve programmed in Pascal, you may have experienced the difficulties you can encounter if this feature is lacking.
- Multitasking
- Modula-2 has built-in support for multitasking. In addition, the TopSpeed Modula-2 Library includes an advanced time-sliced scheduler, which makes it easy to implement concurrent processes.
- Program Control
- You have complete control over all aspects of your program. There is a minimum of “built-in” procedures and there are no implicit type conversions to confuse you.
- Programming Environment
- The TopSpeed Modula-2 system is a state-of-the-art program development system that you may tailor to your own requirements. Moreover, you can even change the menu structure and the command sequences in your TopSpeed Modula-2 environment.
- For example, you may have frequent need to use a command that has a long command sequence in the “vanilla version” of TopSpeed Modula-2. You can change the command sequence associated with the command to a shorter one. If you need to give the command thousands of times, saving even one keystroke in executing the command will make a difference — both in time and in accuracy.
- TopSpeed Modula-2 includes the complete Modula-2 source text to the library. This means that you can change even these modules if you wish or must, so that you can control the way library work in your programs.
- The Assembler source code for the start-up code and for the TopSpeed Modula-2 run-time library is available separately, in the TechKit. This package also includes the JPI TopSpeed Assembler, technical information, as well as communication drives and a module for creating terminate-and-stay-resident (TSR) programs.
- Debugging
- Because Modula-2 is a strongly typed language, a lot of potential errors are detected at compile time. All “normal” run-time errors (array index out of bounds, using a NIL pointer, overflow, etc.) also can be trapped by the system. If you are running the program under the environment, the system will position the cursor at the point in your source code where the error was detected. This occurs almost instantaneously.
- There is of course much more to Modula-2; Chapter 4 will reveal additional features by presenting a series of interesting examples. If you need more complete information, Chapters 6 and 7 explain Modula-2 in greater detail.
- Getting Started
- Summary of Distribution Disks
- Your TopSpeed Modula-2 package includes three 51 inch diskettes. The first of these is labeled System Disk, the second diskette is labeled Library Objects and the third is labeled Library Source. (You can also get TopSpeed Modula-2 on two 31 inch diskettes. In this format, the TopSpeed Modula-2 System and the TopSpeed Modula-2 Library Objects are combined on one diskette, and the second diskette contains the TopSpeed Modula-2 Library Source.)
- First, make working copies of these diskettes. Then put the master diskettes in a safe place, and work only with the working copies. For information on making copies of disks, see your DOS documentation.
- The disk labeled System contains the main TopSpeed Modula-2 program and related files. These files are:
- M2 . EXE The main program for TopSpeed Modula-2.
- M2 . OVL Overlay file for main program.
- M2 . ERR Compiler error messages.
- M2 . MNU Reconfigurable menu definition.
- M2. HLP Help text.
- Only the first three files are essential when running TopSpeed Modula-2. The others are needed only if you want to use special features, such as on-line help or a customized menu configuration.
- The disk labeled Library Objects contains the following files:
- *.DEF
- *.OBJ DEMO.MOD WINDEMO.MOD
- PROG*.MOD
- Definition modules.
- Object code for library modules.
- A short demonstration program.
- A short demonstration of the Window module.
- Source code for several example programs. These are named PR0G1 .MOD through PR0G8 .MOD.
- Only the *. DEF and *. OBJ files need to be present in order to use the TopSpeed Modula-2 library.
- The disk labeled Library Source contains the source code for the library modules.
- You do not need this disk to run the system.
- Running on a Hard Disk System
- Here is how to get started on a hard disk system in four easy steps:
- 1. Make a directory on your hard disk, for example: C:\JPIM2
- 2. Copy the contents of the System and Library Objects disks to the directory you just made.
- 3. Log in the directory you created and start the system by entering M2 at the DOS prompt.
- and answer DEMO when TopSpeed Modula-2 prompts for the Main
- 4. Press lAltllgJI; ~
- file. Press I Enter || and watch the demo program compile, link and execute.
- Running on a System with Two Floppy Disks
- Here is how to get started in three easy steps on a floppy disk system using
- 1. Place the copy of the System Disk in drive A and the copy of the Library Objects disk in drive B.
- 2. Log in drive B and start the system by entering A: M2 at the DOS prompt.
- HUI tail
- 3. Press _
- and answer DEMO when TopSpeed Modula-2 prompts for the Main
- file. Press |Enter|| and watch the demo program compile, link and execute.
- Running on a System Using 3| Inch Disks
- _
- To use TopSpeed Modula-2 on a system with 3| inch diskettes, you just need the disk containing the System and the Library Objects.
- 1. Place the copy of the disk in drive A and prefix to that drive.
- 2. Enter M2 at the DOS prompt.
- and answer DEMO when TopSpeed Modula-2 prompts for the Main
- 3. Press IAlt||Bj|; ' ~
- file. Press |Enter|| and watch the demo program compile, link and execute.
- How to Continue
- Once you’ve got a working Modula-2 environment installed, you can proceed by whatever method best suits your style. Chapters 4 and 5, along with Chapters 7 and 8, contain information about the TopSpeed Modula-2 environment — the compiler, linker, library, etc. For information about the Modula-2 language, refer to Chapter 6 and to the Modula-2 Tutorial by K. N. King, included in your package.
- If You Are Patient
- To get as much out of the system as possible, we suggest that you read through the case studies in Chapter 4. Before using the environment any further, you may find it a good idea to browse Chapter 5 about the TopSpeed Modula-2 environment.
- If You Dislike Reading Manuals
- Then you’re probably not reading this anyway. If you are, we’re sure you’ll find IfFlU most useful.
- Try pressing |IfTI| and then find out for yourself how to compile and execute the example programs named PROG* . MOD.
- Modula-2
- Case Studies
- This chapter presents a series of case studies that serve as an informal introduction to the Modula-2 language and to the TopSpeed Modula-2 environment. The chapter does not go into sufficient detail to serve as a tutorial on either the language or the TopSpeed Modula-2 environment. See the Modula-2 Tutorial, for such an introduction to Modula-2, and later chapters (especially Chapter 5) for a discussion of the environment.
- The examples will use the default TopSpeed Modula-2 configuration that comes on the diskettes in your package. For example, we’ll assume the Modula-2 program and library files are in the same directory. We’ll also assume that the source files for the programs are in this same directory. You may want to change this setup. In that case, simply make the appropriate adjustments as you work through the examples.
- Each study serves to illustrate individual aspects of the language rather than the construction of complex algorithms; it is not necessary to fully understand how the programs work. In addition, the examples illustrate the use of TopSpeed Modula-2 commands and features.
- We’ve tried to make the examples interesting, but still possible to follow. Note, however, that the level of programming knowledge assumed increases sharply from one study to the next. You should work through at least some of the examples and study the source code for the simpler examples.
- TopSpeed M2 Files Edit Compile Make
- Link
- Run
- Run ii
- Togl HI
- B-se 1 ect L^j-cance 1
- FIGURE 4-1 TopSpeed Modula-2 screen after specifying file to run
- Hello
- To run the first program, type M2 and press |lEnter||. After a few seconds, the main TopSpeed Modula-2 menu will appear. Press [E] to specify that you want to Run an example. You’ll be asked to enter the name of the main program module in a box on the screen. Type progl in this box. (You don’t need to include the . mod extension.) After you type this, but before you press ||Enter||, the screen will look like the one in Figure 4-1.
- The program will be compiled and then executed, and the word “hello” will appear on your screen. After you press |lEsc||, the main menu will again be available. You can either press |[ATt]|[Xl] to quit, or you can look at the source file.
- To edit the source file, select File from the main menu (type 0 or move the cursor to Files and then press |lEnter]|), Select Load File, and specify progl as the file to edit in window 1, then press |(Enteri|. To leave the TopSpeed Modula-2 environment — even from the editor — press IAlt|fx]|.
- In the text window, you’ll find the following source code:
- MODULE progl;
- (* This program writes 'hello' on the screen *)
- FROM IO IMPORT WrStr;
- BEGIN
- WrStr ('hello') ;
- END progl.
- Although this is just about the simplest program possible, there are several important points to understand before going on.
- The program consists of only the main module, named progl. The body of the program — the material between BEGIN and END — consists of a single statement. The program calls a library procedure to write the word “hello” on the screen.
- The following features of Modula-2 are illustrated in the program:
- • Upper and lower case letters are not equivalent. Words that have a special meaning to the compiler are always written in upper case (capital letters). In this example, there are six words of this sort. Thus, the program would not compile if the last line had begun with End instead of END in uppercase letters.
- • MODULE progl; says that this program is called progl. The file in which the program text is stored must be given the name progl. mod to match the module name.
- • Comments start with (* and are terminated by *). Comments do not change the meaning of the program but are included to help explain it to a reader. (However, comments beginning with (*$ are interpreted as instructions to the compiler, as you’ll see later.)
- • FROM IO IMPORT WrStr; makes the procedure WrStr in the library module IO available for use by the rest of the program. IO is a standard library module supplied with the TopSpeed Modula-2 system.
- • The BEGIN marks the start of the executable statements. Statements are the parts of the program that actually do something when you run the program.
- • The statement WrStr ('hello'); causes the string ‘hello’ to be output. In Modula-2 there is no built-in ‘print’ statement. Instead, input/output (I/O) is done by invoking library procedures such as WrStr.
- • The line, END progl., marks the end of the program. Notice the period, which must be included at the end of every program.
- This first program is illustrative but not at all useful. Here is something a bit more interesting.
- Pythagoras
- To run the second program, simply go through the same sequence of steps as for progl. Enter prog2 instead of progl, however. The source code for prog2 . mod is shown in the following listing:
- MODULE prog2;
- (* This program writes out some Pythagorean triples *)
- FROM IO IMPORT WrStr, WrLngCard, WrLn;
- VAR a,b,o:LONGCARD;
- BEGIN
- FOR c := 1 TO 100 DO
- FOR b := 1 TO c DO
- FOR a := 1 TO b DO
- IF a*a + b*b = c*c THEN
- WrLngCard(a,1);
- WrStr(', ');
- WrLngCard(b,1);
- WrStr (', ');
- WrLngCard(c,1) ;
- WrLn;
- END;
- END;
- END;
- END;
- END prog2.
- This program searches for positive numbers a, b, c satisfying the equation a2+b2 = c2. For example 3*3 + 4*4 = 9 + 16 = 25 = 5* 5, so a = 3,6 = 4, c = 5 is a solution to the equation. If the sides of a triangle have these lengths, the triangle is right-angled. According to legend (probably untrue), the ancient Egyptians used this fact to help build the pyramids.
- The method used by the program is the “brute force” approach — try possible values for a, b and c, checking to see if the equation is satisfied, a, b and c need to be represented by variables — that is, objects that take on different values as the execution of the program progresses. Each variable is declared before it is used.
- The FOR Statement
- To do its work, the program loops through possible values for a, b, and c. Each of these values is handled in a separate loop. For example, the statement
- FOR c := 1 TO 100 DO
- END;
- causes the statements between DO and the END in the second-to-last line of the program to be executed repeatedly. The variable c is set, successively, to 1, 2,..., 100. The other FOR statements are similar, and, because they are ‘nested’, the variables take on all the possible combinations of values such that a <= b <= c. With such
- nested loops, the outermost loop changes most slowly and the innermost loop changes most quickly.
- To make it easy to see which END corresponds to which FOR, we use the convention that the END is written directly beneath the corresponding FOR, and the statements in between are indented. This convention also applies to other statements that require an END.
- The statement
- IF a*a + b*b = c*c THEN
- END;
- says that the statements between THEN and the ‘matching’ end are to be executed only when the current values of a,b, c satisfy the equation. Thus we only write out the triples in which we are interested. The matching END will be the one at the same level of indentation as the IF statement.
- Exercise
- As an exercise, you might like to try to find some solutions to the equation a3+63+c3 = d3. The following steps provide one way to do this:
- 1. Copy PR0G2 .MOD to PR0G2A.M0D to put the modified program in a separate file.
- 2. Type M2 to call up the TopSpeed Modula-2 system.
- 3. Select File, then Load from the Main menu and the File menu, respectively.
- 4. Type PR0G2A as the file to load, and press lEnter||.
- 5. Make the necessary changes in the program file.
- 6. Once you’ve made the changes, press II Ait|||Rll to compile and execute the modified program.
- 7. Once the program works to your satisfaction, press ||ALT||x|| to leave the Modula-2 system. You’ll be asked whether you want to save PR0G2A.M0D. Answer Y to this question.
- You’ll find that this program takes quite a while to execute, since it needs to search through so many values. If you want to interrupt the program, press ICtrI||Break]|. The |Break|| key is the same as the one often marked [Scroll Lock| Once the program is interrupted, press lEsc|[ to continue.
- How about some music? The next example shows how to use sound capabilities in your programs.
- Music
- The following program uses the loudspeaker in your computer to play a couple of musical scales. The example shows how to define and include a procedure in a module, and shows how to construct new data types.
- MODULE prog3;
- (* This program plays musical scales *)
- FROM Lib IMPORT Sound, NoSound, Delay;
- FROM MATHLIB IMPORT Exp,Log;
- CONST MiddleC = 131.0;
- TYPE NoteType = SHORTINT;
- TYPE ScaleType = ARRAY [1..8] OF NoteType;
- CONST major = ScaleType(0,2,4,5,7,9,11,12);
- CONST minor = ScaleType(0,2,3,5,7,8,11,12);
- PROCEDURE PlayScale(mode : ScaleType; key : NoteType);
- VAR
- i:[1..8];
- note:NoteType;
- freq:LONGREAL;
- BEGIN
- FOR i := 1 TO 8 DO
- note := key + mode[i];
- freq := MiddleC * Exp(LONGREAL(note) * (Log(2.0)/12.0));
- Sound(CARDINAL(freq));
- Delay(200);
- END;
- NoSound;
- Delay (500);
- END PlayScale;
- BEGIN
- PlayScale(major, 0); (* C major *)
- PlayScale(minor, 2); (* D minor *)
- END prog3.
- Data Types
- Data types are used to specify which values a variable can take. Modula-2 has a number of built-in data types, such as SHORTINT, LONGREAL, CARDINAL, LONG- CARD, CHAR, BOOLEAN. Notice that there are several ways to represent a number value. A representation should be chosen that ensures that the value of each expression falls within the range of numbers represented.
- There are also several ways of constructing new data types. For example, Scale- Type is an array of values. The line
- TYPE ScaleType = ARRAY [1..8] OF NoteType;
- defines a new data type, called ScaleType, whose values consist of 8 independent components (cells) numbered 1,2 .. 8. In the program, mode is declared to be of type ScaleType. The components of mode are referred to as mode [e], where e is some expression. Thus the assignment
- note := key + tnode[ij;
- sets the value of note to the sum of the value of key and the value of the ith component of mode.
- Constant Declarations
- In the program, there are also some constant declarations.
- CONST MiddleC = 131.0;
- says that wherever the name MiddleC occurs in the program, the value 131.0 is to be substituted.
- CONST major = ScaleType(0,2,4,5,7,9,11,12);
- says that where the name major occurs, the value is of type ScaleType, and the components are the eight values listed. That is, major is an array, with eight cells. For example, major[7] would have the value 11.
- Procedures
- A procedure called PlayScale has been defined to “play” the actual sequence of notes. The procedure plays the (eight) notes in a particular musical scale, starting with a specified note. To make it possible to specify the scale and the starting note, the procedure takes two parameters. In PlayScale, the first parameter determines the intervals in the scale, and the second determines the first note of the scale. The scale intervals are passed in an array of values, and the starting note is passed as a small number.
- Procedure definitions are similar in form to a complete program: they contain declarations followed by a list of statements.
- There are two calls to PlayScale:
- PlayScale(major, 0);
- plays a C major scale, and
- PlayScale(minor, 2);
- plays a D minor scale.
- A statement of the form
- variable :« expression
- says that the value of the variable is to be set equal to the value of the expression. Where a variable appears in an expression the current value of that variable is used.
- Strong Typing
- Modula-2 is a ‘strongly typed’ language. This means that the type of each expression must be ‘correct’ for the context in which it occurs. In particular, the types of the operands of a binary operator must match. An expression can be converted to another type by enclosing it in parentheses and placing the required type name in front. In the example, the variable note is converted from SHORTINT to LONGREAL.
- Library Routines
- The two IMPORT lines at the beginning of prog3 enable the program to use several procedures from two library modules. From the Lib module, the program uses three functions for producing and spacing sounds. From the MATHLIB module, the program uses the Exp and Log procedures.
- The next program also uses an array, but in a more complicated way.
- Anagram
- The following program finds and displays all the permutations of a string of characters. A permutation is a rearrangement — in this case, of characters — where the order of the characters is taken into account. For example, there are six permutations of the letters, ‘a,’ ‘b,’ and ‘c’
- abc bac cab
- acb bca cba
- The program displays these permutations, or anagrams, of the string in an order based on the ASCH character codes. Procedure NextPerm does the real work in the program. This procedure illustrates several new features about procedures and parameters.
- The following listing contains the source code for prog4:
- MODULE prog4;
- (* This program displays the permutations of a string in alphabetic order *)
- IMPORT IO, Str;
- TYPE StringType = ARRAY [0..9] OF CHAR;
- PROCEDURE NextPerm(n:CARDINAL;
- VAR s:StringType;
- VAR wrap:BOOLEAN);
- (* This procedure updates s to the next permutation of the first n characters of s. The sequence of permutations generated by successive calls is in 'dictionary' order. If s is the last string in the sequence, the first is returned. The boolean result wrap is used to indicate this event *)
- VAR
- i:CARDINAL; (* s[i-l] is the most significant char changed *) j:CARDINAL; (* s[j] is the char to be swapped with s[i-l] *) tmp:CHAR;
- BEGIN
- IF n = 0 THEN
- wrap := TRUE;
- RETURN;
- , END; <
- 1 := n - 1;
- LOOP
- IF i = 0 THEN
- wrap := TRUE;
- EXIT;
- END;
- IF s[i-l] < s[i] THEN
- j := n - 1;
- WHILE s[j] <= s[i-l] DO
- tmp := s[j]; s[j] := s[i-l]; s[i-l] := tmp; (* swap *) wrap : = FALSE;
- EXIT;
- END;
- i := i - 1;
- END;
- (* s[i]..s[n-l] are in reverse order, reversing them yields the minimum permutation we require *)
- j := n - 1;
- WHILE i < j DO top := s[j]; s[j] := s[ij; s[i] := tmp; i := i + 1; j := j - 1;
- END;
- END NextPerm;
- VAR Inputstring:StringType; wrap:BOOLEAN;
- online:CARDINAL; (* number of strings in output line *) len:CARDINAL;
- BEGIN
- 10.WrStr('Enter string : ');
- 10.RdStr(Inputstring);
- len := Str.Length(Inputstring); REPEAT
- NextPerm(len,InputString,wrap);
- UNTIL wrap; online := 0; REPEAT
- 10.WrStr(Inputstring);
- I0.WrStr(' '); online := online + 1; IF online = 6 THEN lO.WrLn; online := 0;
- END;
- NextPerm(len,InputString,wrap);
- UNTIL wrap;
- END prog4.
- This program uses an array of characters to represent a string. The definition,
- TYPE StringType = ARRAY [0..9] OF CHAR;
- specifies a 10 element array, with each cell containing a CHAR value.
- More About Procedures and Parameters
- NextPerm is another example of a procedure. The list of parameters that follows the declaration of the procedure name is known as the formal parameter list. This list specifies the slots through which information can be passed. When the procedure is called, a matching list of actual parameters, or arguments, must be supplied.
- In this case, there are 3 formal parameters declared:
- n:CARDINAL
- VAR s:StringType
- VAR wrap:BOOLEAN
- Variable and value parameters You can always pass information into a procedure through a parameter, but you can only pass information back out through a parameter under certain conditions. Where a formal parameter is preceded by the keyword VAR (as in the second and third parameters for NextPerm), the following points apply:
- • the parameter is described as a variable parameter
- • you must specify a variable of the appropriate type as an argument (actual parameter) when calling the procedure
- • if the parameter is assigned a value within the procedure, the value of the corresponding variable in the actual parameter list is updated; thus variable parameters can be used to return results from a procedure
- On the other hand, if a formal parameter is not preceded by the keyword VAR, then:
- • the parameter is described as a value parameter
- • when calling the procedure, you can use any expression that evaluates to a value of the ‘correct’ type as the corresponding actual parameter
- • assigning a value to the parameter does not affect the value of the corresponding actual parameter; thus value parameters cannot be used to return results from the procedure
- Explaining how procedure NextPerm actually works is quite tricky and beyond the scope of this chapter, which is about the TopSpeed Modula-2 language and environment, rather than complex algorithms. You might like to try to figure it out for yourself. The material in this manual doesn’t depend on your doing this, however.
- More About Loops
- Program 4 makes use of several different kinds of loops. You’ve already seen the FOR loop in earlier examples. The current example uses a more general form of loop. A statement of the form
- LOOP
- END;
- says that the enclosed statements are to be executed repeatedly until an EXIT statement is executed.
- Modula-2 also has WHILE and REPEAT statements to control looping. These constructs can both be expressed using LOOP as the following listings show. In each case, the WHILE or REPEAT loop on the left is equivalent to the LOOP construct on the right:
- WHILE expression DO
- END;
- REPEAT
- UNTIL expression;
- LOOP
- IF NOT expression THEN EXIT;
- END;
- END;
- LOOP
- IF expression THEN EXIT;
- END;
- END;
- Notice that for a REPEAT loop the enclosed statements are always executed at least once, since nothing is tested until the end of the loop is reached. For a WHILE loop, on the other hand, the statements in the loop may not be executed at all, because the system checks up front whether expression is still TRUE.
- Creating Modules
- The next example program will also need to use NextPerm. Such reuse of procedures occurs frequently in programming, so Modula-2 allows you to make your own ‘library’ module. To make such a module, you need to create two files. One is the definition file, which specifies what the module does, the other is the implementation file, which specifies how it is to be done. The following discusses how you could make a module for the procedure NextPerm.
- Creating a Definition File The definition file will contain the parameter list for the procedure, as well as any data structures needed for the procedure. Definition files have the extension . def. The following listing contains the code for a definition file, which we’ll call perms. def:
- DEFINITION MODULE perms;
- PROCEDURE NextPerm(n:CARDINAL; VAR s:ARRAY OF BYTE;
- VAR wrap:BOOLEAN);
- (* This procedure updates a to the next permutation of the first n bytes of s. The sequence of permutations generated by successive calls is in 'dictionary' order. If s is the last string in the sequence, the first is returned. The boolean result wrap is used to indicate this event *) END perms.
- Creating an Implementation File The implementation file actually specifies the details of the procedure — in this case, the individual statements that accomplish the permutation task. Implementation files have the same name as the definition files, but have the extension .mod.
- IMPLEMENTATION MODULE perms;
- PROCEDURE NextPerm(n:CARDINAL; VAR s:ARRAY OF BYTE;
- VAR wrap:BOOLEAN);
- VAR i:CARDINAL; (* s[i-l] is the most significant byte changed *) j:CARDINAL; (* s[j) is the byte to be swapped with s[l-l] *) toy:BYTE;
- BEGIN IF n = 0 THEN wrap :■ TRUE; RETURN;
- END;
- i :■ n - 1;
- LOOP
- IF i - 0 THEN
- wrap :» TRUE; EXIT;
- END;
- IF s[i-1] < s[i] THEN j := n - 1;
- WHILE s[j] <= s[i-1] DO
- j := j - 1;
- END;
- tmp := s(jj; s[j] := s[i-l); s[i-l] :■ tmp; (* swap *) wrap : = FALSE;
- EXIT;
- END;
- i := i - 1;
- END;
- (* s[i]..s[n-l] are in reverse order, reversing them yields the minimum permutation we require *) j := n - 1;
- WHILE i < j DO trap := s[j]; «[j] .[!]; s[i] := tmp;
- i := 1 + 1; j := j - 1;
- END;
- END NextPerm;
- END perms.
- Notice that the identical line (END perms.) completes both the definition and implementation parts.
- Although in this example the module perms implements only one operation (procedure), it is more usual for a module to implement a whole group of related procedures. (Note that TopSpeed Modula-2 implements true libraries in the sense that only the procedures that are actually used will be included in the complete program ).
- Open Array Parameters
- A small change has been made in procedure NextPerm, to make it more generally useful.
- VAR s:StringType;
- has been changed to
- VAR s:ARRAY OF BYTE;
- This causes the compiler to relax the type checking rules. This type of parameter is called an open array parameter, and is useful because it allows you to pass arrays of different sizes. The elements of s are numbered 0,1,..HIGH (s). HIGH is a predefined procedure that returns the index of the highest cell possible for an open array of the specified type. (The use of BYTE rather than CHAR allows you to pass arrays of SHORTCARD as well as arrays of CHAR.)
- Here is a program that makes use of the perms module to solve a puzzle.
- Puzzle
- The next program illustrates another type of procedure in Modula-2 — one which returns a value. This type of procedure is similar to a function in Pascal.
- MODULE prog5;
- (* this program lists the 9-digit numbers, containing every digit from 1 to 9 which are a product of three 3-digit numbers, which also contain every digit from 1 to 9 *) IMPORT IO;
- FROM perms IMPORT NextPerm;
- PROCEDURE check(n:LONGCARD):BOOLEAN;
- (* Checks if the digits of n are a permutation of 1..9 *) VAR i: [1. .9];
- digit: [0. .9] ;
- seen:ARRAY [0..9] OF BOOLEAN;
- BEGIN seen[0] := TRUE; FOR i := 1 TO 9 DO seen[i] FALSE;
- END;
- FOR i := 1 TO 9 DO
- digit : = CARDINAL(n MOD 10); (* n MOD 10 is the remainder when n is divided by 10 *)
- IF seen[ digit ] THEN RETURN FALSE;
- ELSE seen[ digit ] :- TRUE;
- END;
- n := n DIV 10; (* DIV means whole number division *) END;
- RETURN TRUE;
- END check;
- VAR d: ARRAY[0..8] OF SHORTCARD; a,b,c:CARDINAL; n:LONGCARD; i:CARDINAL;
- wrap:BOOLEAN;
- BEGIN FOR i := 0 TO 8 DO d[i] :- SHORTCARD(i) + 1;
- END;
- PRP17.LT
- a := CARDINAL(d[0])*100 + CARDINAL( d[l]*10 + d[2] );
- b := CARDINAL<d[3])*100 + CARDINAL( d[4]*10 + d[5] );
- c := CARDINAL(d[6])*100 + CARDINAL( d[7]*10 + d[8] );
- n :■= LONGCARD (a) * LONGCARD (b) * LONGCARD(c);
- IF check(n) THEN
- IO.WrStr('A solution is ');
- IO.WrCard(a, 1);
- IO.WrStr(' x ');
- IO.WrCard(b, 1) ;
- IO.WrStr(' x ');
- IO.WrCard(c, 1);
- IO.WrStr(' -');
- IO.WrLngCard(n, 1);
- IO.WrLn;
- END;
- NextPerm(9,d,wrap);
- UNTIL wrap;
- END prog5.
- Function Procedures
- The procedure check is an example of a function procedure (often referred to simply as a function). Functions are called from within expressions, and the value they return is substituted in the expression. Every function returns a value. The type of the result is indicated after the formal parameter list. For example
- PROCEDURE check(n:LONGCARD):BOOLEAN;
- indicates that check is a function which returns a BOOLEAN result. The result actually returned is specified by a statement of the form
- RETURN expression
- within the function body.
- This statement can appear anywhere among the statements of a function, and causes the execution of the function to terminate, yielding the value of the expression as the function result.
- Subrange Declarations
- The declaration
- VAR digit:[1..10] ;
- needs careful explaining. In fact, this expression is a short form of
- VAR digit:CARDINAL[1..10];
- The second version of the statement declares digit as a variable of type CARDINAL, but one which takes on values only between 1 and 10, inclusive. In the second statement, each of these points is explicit. In the first statement, only the variable name and the range of possible values are explicit; the variable type is implicit, and is assumed to be CARDINAL.
- A declaration in which a variable is allowed to take on only some of the possible values normally allowed for the type is called a subrange declaration. In the example, CARDINAL is known as the base type. It is this base type which determines whether a value is ‘correct’ for the context in which it is being used.
- More on Types
- This issue of type correctness may seem confusing, but an example should make things clear. Suppose procedure check was changed, to contain the (incorrect) statement:
- digit := n MOD 10;
- The type of n is LONGCARD, so n MOD 10 is also of type LONGCARD. Thus, the statement would be assigning a LONGCARD value to a variable. However, the base type of digit is CARDINAL, so the compiler would report that the assignment is illegal because of incompatible types. The correct statement is
- digit := CARDINAL(n MOD 10);
- as in the program.
- TopSpeed Modula-2 supplies a selection of libraries. The next few examples will make use of several of them, while giving examples of other features of the Modula-2 language.
- Graphics
- The next program, prog6, uses the TopSpeed Modula-2 graphics module, Graph, to do its task. This module provides some basic procedures for accessing the screen through various graphics boards, including the CGA (default), EGA, VGA, Hercules. The module includes procedures to let you do graphics with any of these boards.
- Notice that in this example Width and Depth are variables imported from Graph. So far, we’ve only imported procedures in the examples. In fact, Modula-2 allows procedures, constants, variables and types to be imported.
- If you haven’t got a CGA board, then before you compile and run this program, add a procedure call to initialize the system to use the graphics routines appropriate for your graphics board. By default, the initialization code for the CGA is run. The available initialization procedures are: InitCGA InitHerc
- InitEGA InitATT
- Init VGA
- To execute the appropriate initialization code, call the required procedure before the call to RANDOMIZE in the main program.
- MODULE prog6;
- (* This program draws patterns on the screen *) FROM Lib IMPORT RANDOM, RANDOMIZE;
- FROM Graph IMPORT Circle,Disc,GraphMode,TextMode,Width,Depth;
- IMPORT IO;
- TYPE
- FunnyType = RECORD q : INTEGER; (* value *) d : INTEGER; (* rate of change *) min : INTEGER; max : INTEGER;
- END;
- PROCEDURE init(VAR v:FunnyType);
- BEGIN
- v.q := v.min;
- v.d := INTEGER(RANDOM(v.max-v.min));
- END init;
- PROCEDURE bounce(VAR v:FunnyType);
- (* Update v.q, 'bouncing' when it goes out of range *) BEGIN
- WITH v DO
- q := q + d;
- IF q < min THEN
- q := 2*min-q;
- d := -d;
- END;
- IF q > max THEN
- q := 2*max-q;
- d := -d;
- END;
- END;
- END bounce;
- VAR
- x,y : FunnyType;
- color,radius : CARDINAL;
- BEGIN
- (* Initialization call for your graphics board here. For example: *) (* InitEGA; *)
- RANDOMIZE;
- x.max := Width-1; x.min := 0;
- y.max := Depth-1; y.min := 0;
- 10.WrStr('Press space to continue, any other key to stop'); lO.WrLn;
- WHILE NOT lO.KeyPressed() DO
- END;
- GraphMode;
- WHILE I0.RdKey() = ' ' DO
- init(x);
- init(y);
- REPEAT
- color := RANDOM (16);
- UNTIL color MOD 5 <> 0; (* fill using 2 colors *)
- radius := 2 + RANDOM(5);
- WHILE NOT lO.KeyPressed() DO
- bounce(x);
- bounce(y);
- Disc(x.q, y.q, radius, color);
- Circle(x.q, y.q, radius, color MOD 4);
- END;
- Disc(0,O,Width+Depth, 0); (* clear screen *)
- END;
- TextMode;
- END prog6.
- Using Library Routines
- The line:
- IMPORT IO;
- tells the system to make all the public procedures and data defined in module IO available. This makes over three dozen procedures available. Procedures from a module imported in this global manner must be referred to by a name that includes the module name. For example,
- IO.WrLn;
- is used in the main program body for prog6, as opposed to WrLn, as we had in earlier examples.
- The program uses ‘low-level’ keyboard input:
- • IO.KeyPressed() tells whether a key has been pressed
- • IO. RdKey () reads a single character from the keyboard without echoing it or performing any other processing
- Note that functions without parameters must be called using an empty parameter list.
- The function RANDOM (n) returns a ‘pseudorandom’ whole number in the range 0 .. n-1. RANDOMIZE causes a different sequence of numbers to be generated each time the program is run (by using the time and date as a seed to start the number generator).
- RECORD Types
- The program declares a record type called FunnyType. Record types are useful for grouping related variables together, regardless of whether each of these variables is of the same type.
- The components of a record variable, known as fields, can be accessed either by using a ‘.’ and the field name, as in procedure init, or by using a WITH statement, as in procedure bounce. Although WITH statements may make your programs easier to type, they can also make programs more difficult to follow — since it may not always be easy to determine which assignments refer to fields of the record. For this reason, WITH statements are best used in moderation (if at all).
- Sorting
- Here is a program to sort the lines of a text file into order. This program makes extensive use of library procedures, and even circumvents Modula-2’s strong typing to accomplish parts of its task.
- MODULE progl;
- (* Sorts lines of a file into order, deleting duplicates *) IMPORT IO, FIO, Lib, Storage, Str;
- TYPE
- StringType - ARRAY [0..255] OF CHAR;
- StringPointerType = POINTER TO StringType;
- VAR
- p : ARRAY [1..10000] OF StringPointerType;
- PROCEDURE Less(i,j:CARDINAL):BOOLEAN; BEGIN
- RETURN Str. Compare (p[i]A, p[ j]A) < 0 ;
- END Less;
- PROCEDURE Swap(i, j :CARDINAL);
- VAR tmp:StrlngPointerType;
- BEGIN
- tmp := p[i]; p[i] := p[jl; p[j] :» tmp;
- END Swap;
- VAR s: StringType;
- len:CARDINAL;
- i,n:CARDINAL;
- InFile,OutFile:FIO.File;
- buffer:ARRAY [1..512+FIO.BufferOverhead] OF BYTE;
- BEGIN
- (* check parameters *)
- IF Lib.ParamCount() <> 2 THEN
- IO.WrStr('Try again : prog7 input-file output-file');
- lO.WrLn;
- HALT;
- END;
- (* read file in *)
- Lib.ParamStr(s, 1); InFile := FlO.Open(s);
- FIO.AssignBuffer(InFile, buffer);
- n := 0; LOOP FIO.RdStr(InFile, s); IF FIO.EOF THEN
- EXIT;
- END;
- IF n - HIGH(p) THEN
- IO.WrStr('Too many lines!');
- lO.WrLn;
- EXIT;
- END;
- INC (n) ;
- len := Str.Length(s);
- Storage.ALLOCATE(p[n], len + 1);
- Lib.Move(ADR(s), ADR(p[n]A), len + 1);
- END;
- FIO.Close(InFile);
- (1 2 sort file in memory *) Lib.HSort(n, Less, Swap);
- (* write file out *)
- Lib.ParamStr(b, 2); OutFile :« FIO.Create(s);
- FIO.AssignBuffer(OutFile, buffer);
- FOR i := 1 TO n DO
- IF (i = 1) OR (Str.Compare (p[i]A, p[i-l]A) <> 0) THEN
- FIO.WrStr(OutFile, p[i]A);
- FIO.WrLn(OutFile);
- END;
- END;
- FIO.Close(OutFile);
- END prog7.
- Function Lib. ParamCount () returns the number of parameters on the command line when the program was invoked. Lib. ParamStr (s, n) is used to copy the nth parameter into s. If you run a program from the TopSpeed Modula-2 environment, you can set up the command line by using Options Run Command-Line.
- Command Line Arguments in
- the TopSpeed Modula-2 Environment
- TopSpeed HZ Files Edit Compile Hake Link Run
- Options
- Compiler Linker
- Run
- C - Connand line
- I1 Run Command line1
- stest.rau stest.srt |
- To enable each line from the input file to be stored in exactly the right amount of space, the library procedure Lib. Move is used. A straightforward assignment could not be used to copy the input line into the allocated storage, because only len+1 bytes have been allocated to hold the string. The assignment
- p[n]A := s;
- would copy 256 bytes (the length of a variable of type StringType). The library procedure Lib.Move, in which you can specify the number of bytes to be copied, has been used instead. The built-in function ADR, which yields the address of a variable, should be used with great care, because its parameter is not type checked.
- Heapsort and Quicksort
- PROCEDURE QSort(n:CARDINAL; Less:CompareProc; Swap:SwapProc);
- PROCEDURE Sort(1,r:CARDINAL);
- VAR i, j : CARDINAL;
- BEGIN
- WHILE r > 1 DO
- i :» 1+1;
- j := r;
- WHILE i <= j DO
- WHILE (i <= j) AND NOT Less(1,1) DO INC(l) END;
- WHILE (1 <= j) AND Less(l,j) DO DEC(j) END;
- IF 1 <= j THEN Swap(i,j); INC(i); DEC(j) END; END;
- IF j # 1 THEN Swap(j,l) END;
- IF j+j > r+1 THEN (* small one recursively *)
- Sort (j+1, r) ;
- r := j-1;
- ELSE
- Sort(1,j-1);
- 1 := j+1;
- END;
- END;
- END Sort;
- BEGIN
- Sort (1, n) ;
- END QSort;
- END Lib.
- The Quicksort algorithm works by partitioning the file on the basis of a chosen element (in this case the first), and then recursively calling itself to sort the two arrays that result. Essentially, the right array will come to contain the larger values and the left array will come to contain smaller values. By repeating this process on smaller and smaller arrays, the entire array is eventually sorted.
- Procedure Parameters
- Nested Procedures
- Notice that the procedure Sort is declared within the procedure QSort — it is nested in Quicksort. Sort can access both its own parameters and local variables, as well as the parameters and local variables of the enclosing procedure.
- In the implementation here, the call to sort the larger half has been replaced with a loop back to the start of the procedure. This is a form of ‘tail-recursion’ optimization, which ensures that the amount of stack needed for recursive activations is small.
- Recursion and the Compiler One of the problems of using recursion is that the amount of stack needed will vary with the size of the input. The stack check compiler directive (3$S+*) can be used to detect stack overflow (which could otherwise give very unpredictable effects), although of course it will result in some run-time overhead.
- Calculator
- TreeRecordType = RECORD CASE kind:TokenType OF | number :
- NumberValue : LONGREAL;
- | add,sub,mul,div : left : TreeType; right : TreeType;
- END;
- END;
- VAR
- c:CHAR;
- token:TokenType;
- TokenNumberValue:LONGREAL;
- PROCEDURE error(s:ARRAY OF CHAR); BEGIN
- 10.WrStr(s);
- lO.WrLn;
- HALT;
- END error;
- PROCEDURE readtoken; VAR s:ARRAY[0..99] OF CHAR; i: [0..99];
- done:BOOLEAN;
- oldc:CHAR;
- BEGIN
- LOOP oldc : = c; o := 10.RdChar ();
- CASE oldc OF
- • '+' : token := add; EXIT;
- • : token := sub; EXIT;
- • : token := mul; EXIT;
- | : token := div; EXIT;
- I ' (' : token := LeftParen; EXIT;
- | ')' : token := RightParen; EXIT;
- | CHAR(10),CHAR(13),CHAR(26) : token end; EXIT;
- | '0'..'9' : (* read a real number *) i := 1; s[0] := oldc;
- WHILE (c >= '0') AND (c <= '9') DO
- s[i] c;
- INC(i) ;
- c := IO.RdChar();
- END;
- IF c<>'THEN (* add decimal point if none in input *) s[i] INC(i);
- ELSE
- REPEAT (* read fraction part *) s[i] c;
- INC(i);
- c := IO.RdChar ();
- UNTIL (C < '0') OR (c > '9'),’ END;
- s[i] := CHAR(O);
- TokenNumberValue :« Str.StrToReal(s, done); IF NOT done THEN
- error('Bad number?');
- END; token :« number; EXIT;
- ELSE error('Bad character');
- END;
- END;
- END readtoken;
- PROCEDURE read(what:SyntacticType):TreeType;
- VAR t,tl:TreeType;
- BEGIN CASE what OF | factor :
- IF token = LeftParen THEN readtoken; t := read(exp);
- IF token « RlghtParen THEN readtoken;
- ELSE error("Missing ')'");
- END;
- ELSIF token = number THEN
- Storage.ALLOCATE(t, SIZE(tA)); tA.kind := number; tA.Numbervalue := TokenNumberValue; readtoken; ELSE
- error('Missing number?'); END;
- | term: t : = read(factor); WHILE (token = raul) OR (token = div) DO tl := t;
- Storage.ALLOCATE(t, SIZE(tA));
- tA.kind := token;
- readtoken;
- tA.left := tl;
- tA.right := read(factor) ; END;
- I exp: t := read (term); WHILE (token = add) OR (token = sub) DO tl := t;
- Storage.ALLOCATE(t, SIZE(tA)); tA.kind := token; readtoken; tA.left := tl;
- tA.right := read(term); END;
- | main :
- c IO.RdChar();
- readtoken;
- t := read(exp);
- IF (token <> end) THEN
- error('Missing operator?');
- END;
- END;
- RETURN t;
- END read;
- PROCEDURE eval(t:TreeType):LONGREAL; BEGIN
- CASE tA.kind OF
- | number : RETURN tA.Numbervalue;
- | add : RETURN eval(t*.left) + eval(tA.right);
- | sub : RETURN eval(tA.left) - eval(tA.right);
- | mul : RETURN eval(tA.left) * eval(tA.right); | div : RETURN eval(tA.left) / eval(tA.right); END;
- END eval;
- VAR
- t:TreeType;
- result:LONGREAL;
- BEGIN
- LOOP
- 10.WrStr('Enter expression : ');
- t :■» read (main);
- result : = eval(t);
- I0.WrStr(' =');
- 10.WrLngReal(result, 4, 0) ;
- 10.WrLn;
- END;
- END prog8.
- Enumeration Data Types
- The declarations:
- TokenType = (number, add, sub, mul, div, LeftParen, RightParen, end);
- SyntacticType = (main, exp, term, factor);
- declare enumeration data types. The possible values of an enumeration type are just the names listed. Thus, any variables of type SyntacticType can take on four different values — main, exp, term, or factor.
- Variant Records
- A variant record is one with fields that may contain different types of information at different times. The template for a variant data structure is large enough to hold values associated with the largest type of information you’re using. See your Modula-2 Tutorial for more information about variant records.
- The declarations:
- TreeType = POINTER TO TreeRecordType;
- TreeRecordType = RECORD
- CASE kind: TokenType OF
- I number :
- NumberValue : LONGREAL;
- | add,sub,mul,div :
- left : TreeType;
- right : TreeType;
- END;
- END;
- define a ‘recursive’ data type. This definition says that a tree is made up of a field, kind, which is of type TokenType. Depending on the value of kind, a particular tree has either a real number (stored in field Numbervalue), or a left and right sub-tree (stored in fields left and right, respectively). The CASE keyword indicates this variant situation. In fact, the TreeRecordType also could be declared as:
- TreeType = POINTER TO TreeRecordType;
- TreeRecordType = RECORD
- kind:TokenType;
- NumberValue : LONGREAL;
- left : TreeType;
- right : TreeType;
- END;
- but this does not convey the sense as well. This version also requires more storage.
- CASE Statements
- There are several CASE statements in the program, used to select one of a group of statements for execution. The statements selected depend on the expression which follows the CASE keyword.
- The case labels must be constant, but ranges are allowed, as in ' 0' . .' 9'. The CASE statement in procedure readtoken has an else part, which is executed if none of the case labels are matched.
- This concludes the case studies. We hope you found the examples interesting. Obviously in the space available many points could not be fully explained. You should
- look at the Modula-2 Tutorial for a more thorough introduction to Modula-2, or check Chapter 6 of this manual for a concise, but complete, definition of the language. The definitive book is Niklaus Wirth’s Programming in Modula-2 (third, corrected edition). In addition, there are several good books on Modula-2 that explain the Modula-2 language at greater length. For example, K.N. King’s Modula-2: A Complete Guide, (D.C. Heath, 1988), provides a very complete explanation of the language and how to use it.
- Chapter 5
- The TopSpeed Modula-2 Environment
- In this chapter, you will learn about the TopSpeed Modula-2 environment. You’ll find brief summaries of the major environment features, the commands, and the options available in the Modula-2 environment.
- The first part of the chapter discusses general features of the TopSpeed Modula-2 environment, including how to get started, the Help and Menu systems, and the use of Windows in the environment. The core of the chapter summarizes the commands available under the menus — including the File and Editor menus, as well as the other menus available. The last portion of the chapter describes how you can customize the TopSpeed Modula-2 environment to suit your needs and tastes.
- TopSpeed Modula-2: Features
- The TopSpeed Modula-2 development environment is a multi-window integrated development system. Within the environment, you can enter and edit your program, compile the text into executable code, and then run your completed program.
- You can do all this without leaving the environment, and without long or complicated command sequences. The environment will also detect errors when you compile or run your program, and will take you to their exact position within the editor.
- The environment is designed especially for developing programs that contain more than one compilation module, as is usually the case with a Modula-2 program. Four Editor Windows are provided, so you can view and edit up to four separate files simultaneously. Thus you can enter the text of an implementation file using one Editor Window, while viewing the relevant definition file in another. In addition to the four user windows, the environment provides an extra Editor Window, in which compile or run-time errors are pointed out in the source text.
- To ensure that each component module of a program is compiled and up-to-date, the environment provides an automatic Make facility. Thus if any part of a program is changed, all modules affected by that change are automatically recompiled and a new executable file is generated.
- The menu system and key setups are all fully reconfigurable to your own personal preferences, by editing a simple text file (M2 .mnu). This allows you to change the text and structure of the menu tree, and the Shortcut keys that invoke environment functions. You can even assign your own programs to menu and key commands.
- The multiple window editor is also fully configurable; you can easily make it resemble your own favorite editor. It is initially configured to be WordStar-compatible, familiar to users of Turbo Pascal or SideKick, although with the ability to edit up to five files simultaneously (including the Error Window) and with a much larger file capacity. As well as editing multiple files in multiple windows, the environment also allows you edit the same file at different positions in the text. For example, you could view the global variables for a module in one window, while editing another part of the module in another window.
- Whenever you leave the environment, the current environment state is recorded, including which files are being edited and the position within each file. Also the window layout and all user options are saved. When you reenter the environment it will automatically start up from where you left it, allowing you to continue immediately. (If you do not want to continue your previous session, you can use the /N command line option when starting a TopSpeed Modula-2 session, as described below.)
- The hierarchical directory system in DOS can be very helpful in keeping your files in order. For example, you might put all your files with . OBJ extension into a separate directory; you might also keep all your source (. MOD) files in a separate directory.
- In the TopSpeed Modula-2 environment, you can assign search paths specifying the directories in which various types of files can be found. With this useful feature, you can keep all files of a given kind (e.g. . OBJ files or library . DEF files) in a particular directory. In this way you can organize your filing system tidily and consistently, without having cluttered work directories.
- To set up the intended location of files, you need to edit the text file that defines file-to-directory redirection, (M2.RED). See “The Redirection File,” page 77, for more details.
- Starting Up the Environment
- To start up the environment, enter the command M2 at the DOS prompt. The environment will run, first clearing the screen, then displaying the TopSpeed Modula-2 title banner, and then the Main Menu.
- Files used by the environment include the following:
- M2 . EXE The TopSpeed Modula-2 Environment
- M2 . OVL Overlay file used by M2 . EXE
- M2 . MNU Menu system definition (see “Menu Definition File Format,” page 83 )
- M2. ERR Modula-2 error messages (see “Customizing the Error Messages,” page 92)
- M2 . HER Help text
- All of the above may be located in the start-up directory, i.e. the directory in which you keep M2 . EXE.
- In addition the following files also may exist:
- M2 . RED Redirection file (see “The Redirection File,” page 77)
- M2 . SES Session file (see “Quit,” page 58)
- M2 . SES contains details of your last session in the environment. If this file is present when you type M2, the environment resumes in the same state as when you left. This is true unless you use the /N compiler option, in which case the system ignores the M2 . SES file, and a new session starts instead. To use this option, type
- M2/N
- The Help System
- Press ED] to get context sensitive on-screen help at any time while within TopSpeed Modula-2 the environment. You will get specific information related to your current location in the environment. You can also move around within the help system to look at other topics of interest. Press within the Help System for an index to all help topics available.
- Help Lines
- On the bottom line of the screen a single line is displayed, showing a summary of key functions for the current context. This information can help you use an unfamiliar function, without resorting to the help system or manual.
- You can configure the Help line for the Main Menu and for the Editor Windows. You can also disable the display of help lines. See “Changing Help Lines,” page 83, for details.)
- The Menu System
- You can use pop-up menus to invoke all the facilities of the TopSpeed Modula-2 Environment. This is one of the two major ways in which you can invoke TopSpeed Modula-2 commands — the other being through use of Shortcut key sequences. Generally, you need only a few keystrokes to find and activate any function through menus. The menu system is fully reconfigurable to your own requirements (see “Customizing The Menu,” page 79).
- Although you may have several menus visible on your screen at any given time, only one of these menu windows will be active at a time. The active menu has a double frame and highlighted command characters.
- Menu commands always act upon the active menu. You can select a command by moving to the command you want, and then pressing || Enter|[ As you move, your cunent line will be in inverse video. This inverted line is called the menu bar, and is used to identify the command you wish to select. You can also select a command by typing the highlighted character in the command’s name. This form of the command will override the menu bar selection.
- Moving Around Menus
- The TopSpeed Modula-2 menu system is very detailed and thorough. The structure is organized as a tree, with the main menu at the top, and various submenus branching off from this one. The default Main Menu tree is shown in Figure 5-1. Several keys are useful for moving through the menu structure.
- Q Moves the menu-bar down one line.
- 0 Moves the menu-bar up one line.
- |lEnter|| Opens a submenu if one exists, or activates the command at the menu bar if there is no submenu.
- |[Esc|| Closes the current menu.
- liHomell Moves the menu bar to the first line.
- ||End]| Moves the menu bar to the last line.
- Letter Pressing a letter that is highlighted in the active menu moves the menu bar to the line containing that letter, then activates the associated function or submenu.
- PTopSpeed M2 Files
- Edit Canpile Make
- Link
- Run Options Info assemble
- == Files
- Load file Pick file Save file ail save Main module Change dir Files dir Dos shell Execute Quit
- ===== Load file
- Windew 1: *.M® Window 2: *.DEF
- Windew 3: *.MOD
- Windew 4: *.DEF
- = Pick file :
- C:\DATABASE\TEST\TRACE.MOD C: \DATABASE\TEST\TRACE.DEF
- C: \DATABASE\READKEY. MOD
- C:\M2\LIB\STR.DEF
- C:\M2\LIB\IO.DEF
- C: \M2\LIB\FIO.DEF
- C:\DATABASE\TRACE.TXT
- — Load file —
- 1 Ccnpiler Options =
- := Options
- Ccnpiler ■
- Linker
- Run
- Editor
- Setup
- Make all
- E - Stop on 1st error : OFF
- F - Filename check : ON
- N - Line numbers : OFF
- F - Volatile variables : OFF
- D - Generate debug info : OFF
- B - Runtime checks default : OFF
- J - Suppress libraries : OFF
- == Linker Options 1
- M - Map file : ON
- I - Initiali ze segments : OFF S - Detailed segment map : OFF T - Trace module references : OFF C - Case sensitive link : CM W - Suppress warnings : OFF
- — Run Options =~:—r
- C - CCmmand line a - Auto make : CN
- T - Timed run : OFF
- F - Find error
- ===== Editor Options =
- a - Auto save files : OFF F - Default filenames E - Default extensions
- N - Number of backups : 1
- T - Top scroll zone : 0
- B - Bottom scroll zone : 1
- Environment Options
- C - OGA snow check : OFF B - Bios scrolling : OFF H - High background : OFF X - Solid cursor : OFF
- R - Load redirection file
- L - Load opticns/windcws S - Save opticns/windcws
- FIGURE 5-1 TopSpeed Modula-2 main menu structure
- ||F10|| Returns to the Main Menu from wherever you are in the menu system. This is also the key that activates the Main Menu from outside the menu system, for example if you are in an Editor Window.
- In addition to the above, there are also global Shortcut keys that you can use to invoke menus and commands. These are independent of the menu windows, and can be used even with no menu active on the screen. For example, in the preceding list ||F10|| is the ShortCut key that invokes the main menu. Shortcut keys are discussed in the next section.
- Thus, there are three ways to activate any environment function:
- • Use the menu to select the required function and press ||Enter||
- • Type the character which is highlighted in the line for the desired command
- • Press the appropriate ShortCut key (if one exists for this command)
- ShortCut Keys
- Many frequently used functions have predefined ShortCut keys assigned to them. Some of these commands are function keys and others consist of a key prefixed by ||Alt||. You can change or add to these commands by editing the menu configuration file, M2 .MNU (see See “Changing ShortCut Keys,” page 81). Initially, the following Shortcuts are defined:
- ||F10|| Invokes the Main Menu.
- |[Ait]|[X]| Exits the TopSpeed Modula-2 environment, returning to the DOS command line. This is equivalent to the Files Quit menu command. Note that before you exit, you will be given a chance to save any edited text. The state of the environment also is saved.
- ||Ait|||E|| Invokes the Editor. If you’re editing in more than one Editor Window, then llAitlllEll will take you to the Editor Window you last used. This is equivalent to invoking the Editor command from the Main Menu. See “The Editor,” page 59, for more details.
- Invokes Editor Window 1
- EEEH Invokes Editor Window 2
- l(Ait]|[3|l Invokes Editor Window 3
- ||Alt|||4|| Invokes Editor Window 4
- Invokes the Error Editor Window, if it is active.
- |[F5|| ‘Zooms’ the current Editor Window, making it the full size of the screen. If the window is already at full size, pressing EJI returns the window to its original size.
- HU
- EjjHI
- HI
- EE
- Cycles through the currently open Editor Windows, making each active in turn.
- Reviews the DOS screen. This allows you to review the last output produced by a program or DOS Shell. This is useful for examining the results of a program after you have returned to the environment. On entry to the environment the review screen is loaded with the screen previously visible. Compile, Make and Link all automatically clear the review screen, ready for the next time you run a program.
- Activates the Information Window that contains useful information on the status of the environment. This is equivalent to the Info Main Menu command. See “The Information Window,” page 77.
- Compiles a single file.
- Makes an up-to-date executable program, compiling and linking as necessary.
- Links already compiled files into an executable program.
- Makes an executable program and then runs it. The above four are equivalent to the main menu commands Compile, Make, Link and Run, which provide the interface to the TopSpeed Modula-2 Compiler and Linker. See “Compiling and Running Programs,” page 67, for more details.
- Creates a DOS Shell in which you can execute DOS commands and programs. On exit from the shell (by typing exit) the environment will be restored to its original state. This is equivalent to the Files DOS-Shell command. See “DOS Shell,” page 58.
- Windows in the Environment
- All interaction between the user and the TopSpeed Modula-2 Environment occurs within overlapping windows. These windows can be dynamically positioned, sized and colored according to your taste and requirements.
- Generally, each window is associated with a single task or function. Fbr example, an Editor Window allows you to edit text, while the Compiler Window will contain messages from the compiler.
- Each window is bounded by a frame. This, together with the coloring of the window, makes it clear where each window begins and ends, even when they overlap.
- Whenever you are in the environment, there is always a single active window. As mentioned above, this window contains the task currently being performed — whether it involves an editor, a compiler, a menu or any of the other environment functions. You can always identify the active window by its double-lined frame, as opposed to the single frame of an inactive window.
- The overlapping windows of each function are stacked on top of one other, according to the order in which the functions were invoked. The top window in the stack is always the active window. The active window is always fully visible, on the screen — that is, it is never obscured by other overlapping windows.
- Throughout the environment, |lEsc|| always removes the active window from the screen and makes the next window in the stack active.
- See “Changing Windows” on page 90 for details on how to reposition, resize, and recolor your windows.
- Zoom/Unzoom
- You can make each of the Editor Windows as large as the entire screen by pressing R|. This “zooms” you in so that the entire screen is now filled with the Window. Zooming removes the right and left edges and the bottom frame edge (except in the ErrorEdit window where the bottom line is reserved for error messages). Zooming in is convenient for full screen editing, allowing the maximum area possible for showing text.
- You can move back out (“unzoom”) by pressing IF5|| again. This will restore the window to its original size. The zoom state of each window is saved in the configuration and session files.
- User Dialog Windows
- When the environment needs some input from you, it opens a dialog window. These windows have three forms:
- • Single line input
- • Multiple line input
- • File selection
- Single Line Input Whenever it needs a one line response, the environment opens a single line input window — for example, when prompting for a filename.
- This input window contains a description of the expected input (e.g. Filename:),
- followed by an Editing Field in inverse video. Type your response in this field, and then press
- to indicate that you have finished your input. Table 5-1 shows the
- keys you can use when editing such a response.
- TABLE 5.1.
- Editing Commands for Dialog Windows
- o or HI Character left
- or rails Character right
- I MTflj a P or ICtrl|||A|| Word left
- or Mini Word right
- ||BackSpacc|| or wra)i:i ■ Delete character to left
- or Delete character to right
- ItTabll or KWllJll Tab
- || Ins || or ICtrI|||V|| Toggle insert/overwrite
- IlHomell Start of field
- |[EndJ| End of field
- ICtrlHITII Delete word
- |Ctrl|||Y|| Clear field
- When the editing field first appears, either the default text or the last text entered is already in the field. To accept this text, just press ||Enter||. To edit the entry, use the cursor keys, and to clear the entry, just type over it.
- The editing field may be larger than the input window. In this case the field will scroll to the right or the left during editing.
- To abort input, press I Esc II. This closes the input window and aborts the function requiring input.
- Multiple Line Input Whenever the environment needs more than one line of text (for example, the Search command in the editor) or requires you to choose and ||£tril|[X]|). You can then edit the fields, just as above. Again you can press either IIEsc|| to abort the function, or IIEnterH to accept the input and continue.
- from several alternatives (for example, Load file), it opens a multiple line window with several input fields. You can select these fields by using [t] and Q (or |Ctrl||E||
- ma
- File Selection Window Whenever the environment prompts for a file to read, (for example, in Load file) you can enter a wild filename. A wild filename is one that contains one or more of the characters *?’ or **’. The '?’ character is used to match any single character, and is used to match any sequence of characters. When a wild filename is entered, a file selection window is opened. Such a window has one of two formats, as shown in Figure 5-2. The wide format, shown at the top of the figure, contains just file names and extensions, arranged with several entries
- |, = C:\NIGEL\MOD\OORE\*.* n
- ASCII.DEF ASCII.MOD ASCII.OBJ CORE.TXT
- OORELIB.EXE OORELIB.MOD CORELIB.OBJ DB.BAT
- EXEC.RED INOUT.DEF INOUT.MOD INOUT.OBJ
- REALINOU.DEF REALINOU.MOD REALINOU.OBJ STRINGS.DEF
- STRINGS. MOD STRINGS2.DEF STRINGS2.M0D TERMINAL.DEF
- TERMINAL. MOD TERMINAL.OBJ \. .
- C:\NIGEL\MOD\CORE\*.*
- ASCII.DEF 509 8-19-87 12:46pm
- ASCII.MOD 78 8-02-87 4:10pn
- ASCII.OBJ 444 10-27-87 1:02am
- CORE.TXT 325 8-05-87 5:44pn
- OORELIB.EXE 8412 10-27-87 1:12am
- OORELIB.MOD 1269 10-27-87 12:05am
- CORELIB.OBJ 2861 10-27-87 1:02am
- DB.BAT 48 8-19-87 8:32am
- EXEC.RED 165 4-14-87 l:37pn
- INOUT.DEF 826 10-14-87 10:59am
- INOUT.MOD 4030 10-27-87 1:02am
- INOUT.OBJ 6650 10-27-87 1:03am
- REALINOU.MOD 2096 10-27-87 1:03am
- FIGURE 5-2 File selection window formats
- on each line. The detailed format displays one file or directory entry per line, and includes various types of information about the entry.
- You can toggle between the two formats. Just press the Space bar.
- To select a file, move the menu bar to the required file name and then press |l Enter ||. To move the bar, you can use either cursor movement keys or press the first letter of the file required. Subdirectory entries and the parent (..) directory are preceded by *\’ and highlighted. To move into a subdirectory (or the parent) you should move to the directory using the cursor keys or *\’ and then press lEnter||. This will open a new directory window and allow you to select a file from here. You can press lEsc|| to cancel file selection.
- EES-cance
- FIGURE 5-3 Load File Window
- The File Menu
- The File menu contains commands to load and save files, to view DOS directories, to change the current directory, to execute a DOS command or Shell, and to exit from the TopSpeed Modula-2 Environment. In this section, we’ll summarize the File Menu commands.
- Load File
- ShortCut iF3||
- Loads a file into one of the four Editor Windows and then opens that window for editing.
- When Load file is selected, the Load file window (as shown in Figure 5-3) is opened.
- TopSpeed M2
- Files
- I, 1 ~ Pick file ||
- III C:M12M)OOM¥TSH.HOD III
- C: ^H2^DOOHODS'TEST6. non CAM2M>B0G6.M0D CAM2MX)C\MRUT.M0D C AHZSDOOTESiriAUG .MOD — Load file —
- HJ-help g}-choose fl-select i^-close
- FIGURE 5-4 Pick List Window
- To load a file,
- 1. Use the Q and Q keys to select the Editor Window you want.
- 2. Enter the name of the file to load.
- If you used wildcards in your file name, a file selection window is opened (see “File Selection Window,” page 53). Simply move the cursor to the desired file and press ||Enter||. Once a file is selected it is loaded into the Editor Window and you can start editing. If the file requested does not already exist a new file is automatically created.
- Pick File
- ShortCut IAItllF3B
- This command allows you to pick the name of a file to load from a list of recently loaded files. Such a list is shown in Figure 5-4. Up to eight file names are remembered in a Pick List. The cursor is also restored to the point where you last edited the file.
- To pick a file, move the selection bar to the file required and then press I Enter ||. The file is loaded into the active editor ready for you to continue at the point you last edited the file.
- The Pick List is automatically saved in the session file and will be loaded when re-entering the environment. Use ICtrl|||Y|| to delete an entry within the Pick List.
- Save File
- Shortcut [H
- Saves the file currently being edited to disk. This command is equivalent to the Save command (|ctrl|||K|| |Q) that can be issued from the editor (see “Saving a File,” on page 61).
- All Save
- Saves all files being edited that have been changed since they were last saved. This command is a convenient way of ensuring all changes you have made are saved to disk.
- Main Module
- Sets the name of the Main Module. This name is used by Run, Make, Make All and Link (see “The Main Module,” page 69). You can clear the Main Module name by entering a blank name.
- Change Dir
- Changes the current DOS directory. The command prompts for a new directory and displays the current directory name ready for you to edit. If you enter a blank directory name, a selection window opens, allowing you to select a new directory by moving the cursor.
- Files Dir
- Displays a directory listing of files after prompting for a file mask. All files in the specified directory that match the specified mask (e.g. *. MOD) will be listed. If you don’t specify a path, then matching files from the current directory will be displayed.
- There are two forms of the directory window, the detailed directory, which displays the size and last modification date of each file, and the short directory, which only displays the filename. You can toggle between the two displays by pressing the SpaceBar.
- To display other directories, you can move the selection bar to the required directory and then press ||fcnter||. The new directory is then displayed.
- DOS Shell
- ShortCut IAltHDII
- Enters a DOS shell from which you can execute DOS commands and run programs. To exit the DOS shell you must type EXIT. You will then return to the environment at the point where you left.
- If you would like all edited files to be automatically saved before entry to the DOS shell (for example, if you will need to look at these files in the shell), you should have the Options Editor AutoSave option set (see “Auto Save Files,” page 75).
- Execute
- Allows you to enter a single line DOS command, and then immediately return to the environment. This is a convenient way of quickly executing a program without leaving the environment.
- As with the DOS Shell, you can use the AutoSave option to ensure that all edited files are saved.
- Note that if you often need to execute a particular DOS command or program, you may want to place the command directly in the environment menu. Then you can run the program by menu selection, or ShortCut key.
- Quit
- Shortcut ESE
- Leaves the TopSpeed Modula-2 Environment and returns to the DOS command line prompt.
- If you have set the AutoSave option, your files are saved automatically. Otherwise, the environment will ask whether you wish to save edited files before exiting.
- The environment also saves details of your session in the file M2. SES. The environment then uses this file to restart your work in exactly the same state the next time you call M2. The information saved includes the window layout and coloring, all options set, the files loaded in each Editor Window, the Main Module, and the contents of the pick list.
- You can delete the session file if you want to ‘forget’ the previous session and start anew. You can also accomplish this by starting your current session using
- M2 /N
- The Editor
- The TopSpeed Modula-2 Editor is a multi-window editor in which you can edit up to four text files simultaneously. The editing commands are initially configured to be WordStar compatible but you can customize them easily by altering the m2 .mnu file (see “Customizing the Menu,” page 79).
- The following description of commands and facilities available within the editor assumes the supplied default configuration.
- The Editor Menu System
- You can invoke editing functions through ShortCut key sequences or through pop-up menus. Whenever you are in one of the Editor Windows, OSl will invoke the Editor Menu.
- From this menu you can invoke editor functions in the same way as in the main menu. The Editor-Menu tree is illustrated in Figure 5-5.
- Pop Up Menus
- If you can only remember part of a longer editor command, just enter the first part of the command. After a short delay, editor submenus will automatically pop up. For example,
- Pressing
- Pressing
- Pressing
- pops up the Block Menu pops up the Quick Menu pops up the Options Menu
- If you enter the complete key sequence (e.g. ||CtrlllKll fob. the command will be executed immediately. The menu will not pop up in this case.
- == Editor Menu
- L - load new file
- S - save file W - write to ...
- Q - quick commands K - block commands 0 - editor options
- —■— Quick Menu =====
- F - find
- A - replace
- E - top of window
- X - bottom of windew
- R - top of file
- C - bottom of file
- S - start of line
- D - end of line
- B - beginning of block
- K - end of block
- P - previous position
- Y - delete to end of line
- L - restore line
- G - goto line
- Block Menu ==n
- — D - save file
- B - begin block K - end block H - hide block T - mark word L - mark line C - copy block V - move block Y - delete block
- —■" Options Menu == V - insert node : OFF I - auto indent : OFF T - hard tabs : OFF W - tab width : 8
- R - read block W - write block G - get block P - print block I - indent block Q - quit file
- FIGURE 5-5 Editor Menu Tree
- Loading a File
- You can start editing a file one of four ways:
- • Using the Load File command on the Files menu, or the ShortCut IF3||. This is described in “Load File,” page 55.
- • Using the Pick File command on the Files menu, or using the ShortCut ||Alt||F3||. This is described in “Pick File,” page 56.
- • Invoking the Editor command on the Main Menu, or using the ShortCut I Alt||E||.
- This invokes the active Editor Window (initially 1).
- • Entering one of the Shortcut keys |Alt|||l|| - |[Alt]p1|, to open Editor Windows 1-4, respectively (see “Moving Between Editor Windows,” page 62).
- Whenever you invoke an ‘empty’ Editor Window (i.e. one that has not previously been loaded), you are prompted for the name of the file to edit. If you enter the name of a file that does not already exist, the file will be created.
- You can load a new file into an Editor Window either by pressing |F3||. or by selecting the Load New File command, on the Editor Menu (|F9||), If you were already editing a file in the window, you will be asked whether you want to save changes to that file before the new file is loaded.
- The Error Editor Window is loaded whenever you edit a file as a result of errors produced by compiling or running a program.
- If the same file is loaded into two or more Editor Windows, then this file is shared between the windows. Any edits performed in one window will be reflected in all other windows sharing the same file. This powerful feature allows you to edit a file at more than one position simultaneously. The Error Editor Window is also shared with any of the other windows that contain the file being edited.
- Saving a File
- You can save the file being edited to disk by doing any of the following:
- • pressing llF2ll
- • typing the command ICtrl|||K||
- • selecting the Save File command on the Editor Menu
- You can also save to a file with a different name by selecting the Write To command on the Editor Menu
- The environment will always ensure that you never unwittingly lose changes made to a file by either prompting on exit from the environment or, if the AutoSave option is set, by automatically saving the files (see “Auto Save Files,” page 75). You can also ensure that all changed files are saved before quitting. To specify this, select the Files Menu All Save option.
- Whenever you save a file to disk a backup is created containing the previous contents of the file. If you don’t want to save such a backup version, set the Number-Of-Backups Editor Option to 0.
- Maximum File Sizes The editor is a disk-paged editor and can therefore edit files with total size larger than the available RAM. Individual files being edited can be up to 500K characters long provided the total of all files loaded is less than 1MB. The swapfile used to hold temporary data is called M2. $$$. This file should not be deleted during an editing session. The swapfile will automatically be deleted on exit from the environment.
- The environment will warn you if you should approach either of the two size limits. At that point, you will not be allowed to increase the file size.
- Removing a File from an Editor Window
- The command ||Ctrl||[K|| Hq]] will stop editing the file in the currently active Editor Window, and will close that window. If the file has unsaved edits, you will be asked whether you wish to save these changes.
- Moving Between Editor Windows
- You can use the ShortCut keys — lAltlhlL |Alt|||2||, |Alt||3|| and |Alt||4|| — to move to Editor Windows 1-4, respectively. In addition, you can move to the Error Editor Window, if it is active. Just press |Alt|||O||.
- You also can move between Editor Windows in sequence. Press |F6|| to cycle through any open Editor Windows.
- Editor Commands
- The editor for the TopSpeed Modula-2 environment provides a rich variety of commands for editing. Each command can be invoked either by a key sequence or by a menu selection. As mentioned above, you can customize all keys and menus to your own preferences (see “Customizing the Menu,” page 79).
- The initial configuration, described below, resembles WordStar commands, with some useful extensions to assist with program editing.
- Insertion and Deletion Table 5-2 summarizes the keys that enable you to insert or overwrite characters and to delete characters, words, and lines.
- TABLE 5.2.
- Insertion and Deletion Commands
- |[Del1|
- || BackSpacej]
- or |ctrl|||V|| Toggles insert/overwrite
- or |Ctrl|||M|| Inserts line
- iCtriUNl Inserts line below
- or |ctrl|||l|| Inserts a number of spaces,
- or a hard tab character
- (see “Editor Options,” page 75)
- or |Ctrl|||G]| Deletes character to right
- or Deletes character to left
- Deletes word to right
- Deletes line
- |Ctrl|||Q|| El Deletes from the cursor to end of line
- |ctrl|||P|| Prefixes a |ICtrl|| character allowing it to be entered as text and displayed graphically
- Cursor Movement Table 5-3 summarizes the keys that allow you to move the cursor around the file you are editing.
- TABLE 5.3.
- Cursor Movement Commands
- |TA| or
- II—>11 or
- [3 or
- a or
- [ctrilh=ni or
- IctriW or
- ICtrll||W||
- or
- or
- IIHome or
- Il End || or
- |lCtrl|||Home|| or
- fCtdj [Ctrli H 0
- ICtrll loll |s]|
- |Ctrl| l0l||D||
- |Ctrl|||Q|| Je|]
- ICtrllllQH [X|]
- ICtrlllPgUnll or
- or
- ICtrlljlQll |R|| ^0
- ICtrllllQH fBll
- |Ctrl|||Q|| FU
- iMri'oK
- Moves cursor left
- Moves cursor right
- Moves cursor up
- Moves cursor down
- Moves cursor to previous word
- Moves cursor to next word
- Scrolls up
- Scrolls down
- Moves one page up
- Moves one page down
- Moves to start of line
- Moves to end of line
- Moves to top of screen
- Moves to bottom of screen
- Moves to top of file
- Moves to bottom of file
- Moves to start of block
- Moves to end of block
- Moves to the previous cursor position
- Prompts for a line number and then moves to that line
- Block Commands The block commands enable you to define an area of text that you can then copy, move, delete, write to a file, indent or import from another Editor Window. When a block is defined and on display, its text is highlighted. You can change the foreground and/or background of the block text. Use ||ScrollLock|| ||Enter|| to enter the recoloring mode (see “Recoloring Windows,” page 91).
- The available block commands are:
- EEE |Ctrll|Kl| ictriiiKii rn ||Ctrl||K|| in |Ctrl||K|| rctr-iiKiin ICtrlllKlI llvll EEE Marks the start of the block.
- Marks the end of the block.
- Marks a single word.
- Marks a single line.
- Toggles whether the block is displayed.
- Copies the block to the current cursor position. Moves the block to the current cursor position. Deletes the block.
- ||Ctrl||K|| |W|| |ICtrl|JK|| ||R]| EEi Writes the contents of the block to a file.
- Read the contents of a file into a block.
- Gets a block from a different Editor Window, copying it to the current cursor position. This is a convenient way of importing text from other Editor Windows.
- WEE
- IICtrlllKII |Ij] Prints the contents of the block to the standard printer device.
- Indents the text of the block. If the indent specified is positive then the block will move to the right, If negative the block moves to the left. This is a convenient way of fixing indentation in your program. Only spaces are removed when moving left.
- IlCtrlJlKjl toll Quits file. This removes the file from the current active Editor Window and closes the window. You can save any changes before quitting, if you wish.
- Editor Options The Editor Options commands set modes for editing. These commands are as follows:
- ILctrlJIoJI |[v]| Toggles between Insert and Overwrite modes. (Same as llns|| and |Ctrl||[V||).
- Hctrl||o|| ||l|| Toggles Auto Indent on and off. If auto indent is set ON then inserting a new line will automatically indent the new line to match the indent of the line above. Also |ITab|| moves to match the start of words in the line above.
- ICtrlljQlllLT.il Toggles whether spaces or a single tab character will be inserted, whenever ||Tab|| is pressed.
- ||Ctrl||O|| |1W]| Sets the width between tab stops.
- In addition to the options listed above, there are also editor system options that can be found on the Editor Options menu under the Main Menu. These options allow you to set AutoSave mode, default file names and extensions, the number of backup files kept, and the top and bottom scroll zones within the editor window. The latter options are described in the sections: “Top Scroll Zone” and “Bottom Scroll Zone,” page 76. Search and Replace Search lets you search through the file for a specific string, while Replace allows you to replace occurrences of one string with another.
- mH
- |Ctrl||L||
- Prompts for a string to find, and then searches for this string, moving the cursor to its first occurrence, if found. See below for details of the Search options.
- Prompts for a string to find and for a replacement string, then searches for the string, replacing any occurrence found. See below for details of Replace options.
- Repeats the last Find or Replace command, with the same strings and options.
- When seeking or replacing text, you may specify one or more of the following options:
- B Search or replace backwards from the cursor towards the beginning of the file
- U Ignore whether the string is in upper or lower case when matching
- W Only match the search string with whole words
- G Replace globally throughout the file
- L Replace locally within the currently marked block
- R Replace globally from the cursor to the end of the file or, if the B option is set, from the cursor to the beginning of the file
- N Replace without prompting for confirmation
- number Searches or replaces the specified number of times
- You can combine the above options. For example, the option GUN replaces globally without case sensitivity and without asking for confirmation. In a search string, the |lctrl||A|| character is wild and matches any character. To enter a wildcard character into the search string, type lCtrl]||P|| [|Ct'rl||A||.
- Other Editor Commands Other commands available within the editor include uppercase word conversions and correction, marker setting and movement.
- The keys to invoke these commands are as follows:
- mull
- Converts the word at the current cursor position to uppercase. This
- is useful for Modula-2 reserved words.
- [Shift |||F7|| Sets the alphabetic case of the word to be the same as the previous occurrence of the word in the file. This can be used to correct Modula-2 uppercase/lowercase errors.
- |Ctrl||Q|| |0] Sets location marker 1 at the current cursor position.
- |Ctrl||Q|| |2|] Sets location marker 2 at the current cursor position.
- |Ctrl||K|| |E] Goes to location marker 1.
- |Ctrll|K|| J2|| Goes to location marker 2.
- The markers can be used to mark postions in the file for editing and moving between different positions in the file.
- In the Error Editor Window, which is invoked by compilation or run-time errors, you can move to the next and previous error positions as follows:
- ffFSIl Move to the nearest error after the current cursor position
- EzJ Move to nearest error before the current cursor position.
- Compiling and Running Programs
- Within the TopSpeed Modula-2 Environment you can instantly compile your program source into object files, link those objects into an executable program and then run that program. You can do all these things with simple menu selections, or by using ShortCut keys.
- Compiling
- To start compiling a file, do either of the following:
- • Select Compile from the Main Menu
- • Type the ShortCut command, ||Alt|||C||
- If you are currently in an Editor Window and the file you are editing has a .MOD extension, the compiler will start compiling that file. Otherwise you will be prompted for the name of the file to be compiled. After the compiler has finished, the window in Figure 5-6 is displayed.
- During compilation, the compiler window indicates the file being compiled, the current definition file and the line currently being compiled. The thermometer style indicator shows the proportion of the file that has already been compiled, and the disk activity indicator in the top right-hand comer, shows whenever the disk is accessed. At any stage, you can abort the compilation by pressing |lEsc||.
- TopSpeed H2 Files Edit
- Conpile
- flake Link Run Options Info
- - JPI ttodula-2 Uer 1.05 -°i
- Conpiling N2L0CATE.I10D
- Line 512 ■■■
- Conpilation ample ted
- No errors found
- Press any key.
- iBS-abort
- FIGURE 5-6 Compiler Window
- You can set various compiler options to generate debugging information, and to modify the behavior of the compiler. These options are described in “Compiler Options,” page 73.
- Compilation Errors As compilation proceeds the number of errors found Sited. When an error is reported, you can edit the file immediately by pressing This will start editing within the Error Editor Window — at the position of the first error. The bottom line of the window displays any errors present in the current line. To move between multiple errors, use |F8|| to move to the next, and ||F7|| to move to the previous error. Error positions will be adjusted as text is edited, allowing you to correct all the errors found. The compiler will keep up to about 50 error messages, aborting compilation after this limit, but ready for you to start editing. (The exact number of errors the compiler can keep track of depends on the length of the individual error messages.) See “The Editor,” page 59, for details on editing the Error Editor Window file.
- After you have made corrections to the error file, you can continue compilation by either pressing lEsc|| or lAlt|[Cl|. Compilation will restart immediately.
- To abort compilation immediately after the first error is found, set the Options Compiler Stop-on-1st-Error option (see “Stop On First Error,” page 73).
- TopSpeed M2 Files Edit Conpile
- flake
- Link Run Options Info
- - JPI Modula-2 Uer 1.0S -
- Making TSRCALC
- TSRCALC Mo errors found
- TSR Mo errors found
- Make conpleted
- Linking TSRCALC Link conpleted Press any key,
- jSSzabort
- FIGURE 5-7 Make Window
- The Main Module
- The functions Make, Run and Link each need the name of the Main Module. You are prompted for this at the start of each command. The last Main Module name entered is the default choice presented in the prompt window.
- Making a Program
- ShortCut |Alt||M||
- TopSpeed Modula-2 has an automatic Make facility within the compiler. This calculates dependencies and automatically recompiles all out-of-date modules within your program. Then, if all compilations were successful, an executable (. EXE) file is created by linking the program objects together.
- For example, if you change a particular definition file, then Make will automatically ensure that all modules importing the changed definition will be recompiled to make a consistent program.
- To invoke the Make command, select Make from the Main Menu or press the ShortCut key, | A It |l MIL After you enter the Main Module name, the Make window in Figure 5-7 will be displayed and the Make process will commence.
- The Make window shows all files being compiled. Then, if all files compile with no errors, the window shows the link taking place. If errors are found then the Make is aborted and you can immediately correct the errors by pressing I Enter II When you have finished your corrections, press either ||Esc|| or ||Alt|||Nl|| to restart the Make process. You can abort the Make at any time by pressinglTEscll.
- Once the Make has completed with no errors, you can run the completed program — now in an . EXE file — either inside or outside the environment.
- To compile all component modules of a program, you can also use the Options Menu Make All command. This will recompile all files needed by a program regardless of whether they seem to need recompilation. See “Make All,” page 77.
- Running Programs
- (*$R+*) Subrange Value Out Of Range
- Checks for out-of-range assignment.
- (* $R+ *) Enumeration Value Out Of Range
- Checks for out-of-range enumeration values.
- (* $ Z+*) Dereference Of NIL Pointer
- Checks for the dereferencing of pointers containing the value NIL — that is, uninitialized pointers.
- If any of the above errors occur when running under the environment, you are prompted to specify which of the following you wish to do:
- • Continue the program
- • Abort, returning to the environment
- • Find the position of the error in the source program
- If you select Find, then the Error Editor Window will be loaded with the source file containing the error and the cursor will be positioned at the location of the first error.
- If you are running the program outside the environment, then a run-time error will cause an error message in the form of:
- Run Time Error [AAAA/SSSS:OOOO] Error Type. Continue (y/n).
- Where Error Type is one of the run-time errors listed above, AAAA is the absolute segment of the error, SSSS is the relative segment (which can be seen in the link map), and OOOO is the offset of the error. To find the run-time error within the source, the Options Run Find Error command can be used. This prompts for the Main Module name and for the error address (SSSS: OOOO), then finds and displays the error within the source (see “Find Error,” page 75).
- Linking a Program
- Shortcut ran
- The TopSpeed Modula-2 Linker is an extremely fast, ‘smart’ linker. This means that only code actually used by the program is included in the link, and the linker needs no other information than the Main Module name to link a program.
- You’ve already learned how the linker is invoked as part of the Make and Run sequences. You can also invoke the linker separately. To run the linker you should select the Link main menu option. This will prompt for the Main Module and start linking. The component object files are linked together to produce an executable (. EXE) file, as well as a map (. MAP) file — if the Options Link Map-File option is set to ON. The other options that govern the actions of the linker are described in “Linker Options,” page 74.
- Linker Errors If there are any errors detected while linking your program, they will be reported at the end of the link within a scrollable error window. To exit the error window, press I Esc II Error messages are also output within the map. If any errors are detected, then no . EXE file is produced. Some non-fatal errors can be suppressed by the Options Linker Suppress-Warnings option. Possible linker errors include the following:
- Error message output
- Date/time error Probable cause
- This implies that you have date/time inconsistencies between modules within your program. You can use Make, or Make All to remove these inconsistencies (see “Making a Program,” page 69).
- Non-main module This message is output if you attempt to link an implementation module in place of a main module.
- Bad object file This can occur if you have a corrupt or invalid object file.
- Unexpected segment def This can occur if you have a corrupt or invalid object file.
- Unexpected group def This can occur if you have a corrupt or invalid object file.
- Not enough memory This means the environment hasn’t enough space to link your program. Try using the batch linker instead (see “The Batch Compiler and Linker,” page 78).
- Group/Segment exceeds 64K This can occur if you have used the $M or $D compiler directives and have created segments larger than 64K.
- Definition duplicated
- Fixup overflow
- Symbol is Unresolved Multiple definition of symbol.
- Incorrect fixup.
- Unresolved symbol definition.
- The last three errors will not happen within normal Modula-2 programs but may occur when linking to other languages or assembler objects.
- The Options Menu
- ShortCut |Alt|jo||
- The TopSpeed Modula-2 system is designed to be extremely flexible. It was designed to enable you to adapt it to your own particular needs and preferences wherever possible. Toward this aim, each of the major components has a set of options you can change. These options are saved in the session file and the configuration file, allowing you to set options that will be remembered after leaving the environment.
- You can invoke the Options Menu from the Main Menu or by using the |Alt|||O|| ShortCut command. The Options menu contains five submenus: Compiler, Linker, Run, Editor and Setup. The menu also contains the Make All command.
- Compiler Options
- This section summarizes the options for the compiler described in “Compiling” on page 67.
- B - Defaults for Run-Time Checks This option lets you specify whether compiler directives that do checking at run-time are ON or OFF. This setting affects $1, $0, $R, $S, and $Z. This option affects only the default settings. You can still use directives within your source text to override the default.
- D - Generate Debug Information If ON, the compiler generates a debug information file for the module being compiled. This file is required by the TopSpeed Modula-2 source level debugger, which will be available separately.
- E - Stop On First Error If ON, this causes compilation to stop after the first error is found. You can correct the error immediately, and restart compilation. If the option is OFF, then about 50 errors will be stored, ready for correction.
- F - Filename Check This option is normally ON and causes the compiler to check for module names that do not match the source file name. If OFF, the compiler does not report file and module name inconsistencies.
- J - Suppress Libraries If ON, the compiler suppresses the automatic creation of libraries (smart linking). You may need to use this option when linking TopSpeed Modula-2 OB J-files using linkers other than the TopSpeed Modula-2 linker.
- N - Line Numbers If ON, the compiler will generate line numbers in the .MAP file. You can use these line numbers to locate the line being executed while debugging a program. The line information also can be used by source level debuggers.
- V - Volatile Variables If ON, the compiler will keep all variables in memory. If OFF, machine registers are used wherever possible — because they can be accessed more quickly than memory. This option is useful when debugging a program, as variables can be examined in memory. Otherwise, the option is generally OFF.
- Linker Options
- The following options govern the operation of the linker described in “Linking a Program,” page 71.
- M - Map File If ON, the linker generates a text Map File that contains segment information, the location of procedures and global variables, line number information, run-time error check locations and any linker errors messages generated. The map file has the same name as the main module, but has extension .MAP. If the option is OFF, then no map file is generated.
- The map file generated is compatible with Microsoft map formats and can be used with source level debuggers such as Microsoft Symdeb.
- I - Initialize Segments If ON, then the linker will generate zero filled segments for data not initialized in the program. This is not required for Modula-2 programs as data are not assumed to be initialized. The option is generally OFF, resulting in smaller . EXE files.
- S - Detailed Segment Map If this option is ON, then a complete segment map is generated for every component segment included in the link. This provides extra debugging information, but is generally OFF as a great deal of information can be generated.
- C - Case Sensitive Link If this is ON the linker differentiates identifiers that differ in case. Since Modula-2 is case sensitive, you will need to have this option ON. However, you can turn the option OFF when linking to case insensitive languages or to assembly code.
- W - Suppress Warnings If this is turned ON, the linker suppresses non-fatal error messages. See “Linker Errors,” page 72, for details of the linker error messages.
- T - Trace References If ON, the linker traces the first reference to each module. The linker reports the date/time record for each module linked. This can be useful when analyzing module version conflicts.
- Run Options
- The run options modify the operation of the Run command, described in “Running Programs,” page 70. These options are described in this section.
- C - Command Line Allows you to enter a DOS command line that is passed to the program when it is executed from within the environment. You’ll be prompted for the command line.
- A - Auto Make If this option is ON, then an automatic Make will be performed before any program is run. This is to ensure that the program uses the most recent versions of all the modules.
- T - Timed Run If this option is ON then the execution time of your program is displayed when the program completes. The format of the time displayed is H:M:S:HS indicating Hours, Minutes, Seconds and 1/lOOths of seconds. The value excludes the time taken to load the program from disk. (The actual precision with which these measurements can be taken depends on your particular DOS implementation. Normally, the precision is about 0.06 seconds, since the clock is checked about 18.2 times per second.)
- F - Find Error This prompts for a program name and a run-time error address. The system then finds and displays the error within the source. This option can be used to find errors when they are reported outside the environment. Such errors have the following format:
- Run Time Error [AAAA/SSSS:OOOO]. Continue (y/n).
- where SSSS :OOOO is the error address.
- You don’t need this command when running a program from within the environment, since the error is located automatically in that case. Note that a map File is required to find the run-time error.
- Editor Options
- The editor options modify the operation of the environment editor which is described in “The Editor,” page 59.
- A - Auto Save Files When ON, this option causes the editor to save all changed files automatically whenever you run a program, enter a DOS shell, or exit the environment. This ensures that no edits will be lost, even if a program should crash. This option also enables programs run under the environment to read the latest version of files being edited. If the option is OFF, the environment will ask whether to save edited files when exiting, but will not automatically save files when running programs.
- F - Default Filenames This option lets you set the default file names supplied when you enter an Editor Window for the first time. The default filenames are initially set to * . MOD, but may be changed to be different for each Editor Window, depending on your use of that window. For example, you may want to set the default file names of windows 2 and 4 to *. DEF so you can quickly select a definition file for editing within those windows.
- E - Default Extensions This allows you to specify the default extensions that are added to file names entered without an extension. Again, you can have different extensions for each Editor Window, if you wish. The default extensions are all initially set to . MOD.
- N - Number Of Backups This lets you specify the number of backup files that are retained by the editor whenever a file is saved. This value must be between 0 and 9, inclusive. 0 means that no backup file is created. 2 means that the two most recent previous versions of your file are kept. The first, most recent, backup file has the extension .BAK, the second .BK2, the third .BK3 and so on. This option is initially set to 1.
- T - Top Scroll Zone This sets the number of lines from the top at which the Editor Window begins to scroll when moving up. For example, if this is set to 2, then the screen will scroll if you move the cursor to the second line from the top. The initial default value is 0. Increasing it above this value allows you to ensure that there are always lines visible above the cursor.
- B - Bottom Scroll Zone This sets the number of lines from the bottom at which the Editor Window begins to scroll when moving down. The initial default value is 1. Increasing it above this value allows you to ensure that there are always lines visible below the cursor.
- Setup Options
- The Setup Options allow you to specify various aspects of the environment. You can also save and restore configuration files, and you can load a new redirection file if you wish.
- C - CGA Snow Check This should be set to ON if your CGA monitor “snows” when displaying windows in the environment. However, be warned that the display of windows is considerably slower when this option is on. The default setting is OFF.
- B - BIOS Scrolling If ON, this option sets a mode in which the scrolling of Editor Windows is performed by calling the IBM BIOS. This mode can result in quicker scrolling when the CGA snow check is ON but can also cause the screen to flicker when scrolling. The mode is thus usually set OFF.
- H - High Background This specifies whether the high background colors available with the IBM CGA should be enabled. See “Recoloring Windows,” page 91, for details.
- X - Solid Cursor If this option is ON, then the cursor will be a solid flashing block; if OFF, the cursor is the normal flashing underline.
- R - Load Redirection File This loads a new redirection file replacing all previous redirections. See “The Redirection File,” on this page.
- L - Load Options/Windows This loads a . CFG file that has previously been saved using Save options/windows. The command loads each window’s color, position and size, and all Option values.
- S - Save Options/Windows This saves the options and window setup to a . CFG file. You can load this file using the Load options/windows command described above. With this option, you can quickly swap between different configurations of the environment.
- Make All
- Make All performs a make in exactly the same way as Make described in “Making a Program,” page 69, except that all component modules whose source can be found are recompiled, not just the out-of-date ones. This command can be useful in resolving date/time linker errors.
- The Information Window
- ShortCut I Alt||I||
- The Information Window contains useful information about the current state of the environment. The window contains the following information:
- • Date and time
- • Current logged drive and directory
- • File names and current size of files being edited
- • Available memory within the environment
- • Disk free space
- The Redirection File
- Within the TopSpeed Modula-2 environment you can define a search path by which files are located in the DOS file system. This allows you to put different kinds of files in different subdirectories. The file that defines these search paths is a simple text file, M2 . RED. This file contains one or more lines with the format:
- MatchName = DirectoryPath { ; DirectoryPath }
- MatchName is a file name specification that can contain wild (**’ and '?’) characters, and DirectoryPath is the location for those files that match the MatchName. You can specify multiple Directory Paths by separating them with a semicolon
- If there is more than one Directory Path specified, each path will be searched in sequence until the file is found.
- This is best demonstrated by an example. Suppose the file M2. RED contains the following text:
- *.DEF * . OBJ M2. ERR M2.$$$ M2.0VL M2.MNU
- . ; \M2\LIB ; \NIGEL\MOD
- \M2\0BJ \M2\EXE \M2\EXE \M2\EXE \M2\EXE
- Whenever a file name that matches * . DEF is specified, the environment first tries to search the directory (current directory). Then, if the file is not found, \M2\LIB is searched, and then finally \NIGEL\MOD. Similarly, all files that match * .OBJ will be sought in the directory \M2\0BJ.
- Whenever a new file is created, it is always created in the first directory that matches the file name. This means that in the above example all .DEF files will be created in the current directory and all . OBJ files will created in \M2 \OBJ.
- Note that whenever you input a full path name (i.e. a complete directory path) to the environment, redirection does not occur. This allows you to override redirection if required.
- The redirection file is always searched from the top until the file is found. This allows you to specify individual file redirection as well as general default cases. For example
- TESTDB.MOD = \M2\TESTING
- READDB.MOD = \M2\TESTING
- • .MOD = . ; \M2\W0RK
- tells the system to search certain directories for general files with a . MOD extension, but to search in different directories for two specific files with this extension. The current directory should always be specified as since Null entries are ignored.
- A word of warning about using file redirection (M2 .RED): It can be rather confusing if there are several versions of a file in the search path. If you seem to be having a problem, check each directory to make sure that the files present are those you expect.
- The Batch Compiler and Linker
- You can invoke the TopSpeed Modula-2 Compiler and Linker from the DOS command line, or from a . BAT command file.
- The command format to run the batch compiler is:
- M2/C filename /options
- The command format to run the batch linker is:
- M2/L filename /options
- For example, to compile the program wptest enter the command:
- M2/C wptest
- at the DOS prompt. To link the program enter the command:
- M2/L wptest /M
- The batch compiler options are described in Chapter 7.
- The batch linker options are:
- /M Generate map file
- /I Initialize all segments
- /S Detailed map of segments
- /N No default libraries
- /T Trace first reference to module
- /W Suppress warning messages
- /C Lower case significant in symbols
- See “Linker Options,” page 74, for a more complete description.
- Customizing the Menu
- The Menu Definition File (M2. MNU) contains text that defines the structure of the TopSpeed Modula-2 Environment Menu System, and of the ShortCut and Editing keys.
- The Menu Definition File is a simple text file that is read whenever the environment is entered. The exact format of the file is described later in “Menu Definition File Format,” page 83. To get an idea of the layout for the definition, you should examine the default M2. MNU supplied.
- You are encouraged to experiment by changing the Menu Definition File to discover the setup that best suits you. However, before you edit M2 . MNU, you should save a copy of the file, in case you later want to go back to the default definitions supplied with the TopSpeed Modula-2 system.
- The following sections describe changes you can make within the Menu Definition File.
- Changing the Main Menu Type
- You can use three types of menus: pop-up, pull-down, and bar. The type of the main menu is defined by the line
- ! PopUp [ TopSpeed M2 ] | <F10>
- which defines a vertical “Pop-Up” style menu. If you wish to have a horizontal “Pull-Down” menu, you should change PopUp to PullDown. If you want a “Bar” style menu (i.e. a Pull-Down menu with no frame), you should change PopUp to LinePull.
- If you wish to change the title displayed at the top of the menu, you can edit the “TopSpeed M2” between the square brackets (‘[’ and *]’). For example, you may want to change it to
- !PullDown [ My TopSpeed M2, Hands Off! ] | <F10>
- You can also change the key that invokes the main menu by changing the <F10> after the ‘ . For example, if you need |Shift|||F10|| to invoke the main menu you
- might have the line
- !PullDown [ My TopSpeed M2, Hands Off! ] | <ShiftF10>
- For information on changing other ShortCut keys, see “Changing ShortCut Keys,” page 81.
- Changing Menu Text
- In the Menu Definition File, you can change the text displayed in the menu by editing the appropriate line. For example, if you want to change Files to read PcDos on the Main Menu you can change the line:
- {FJiles | <AltF>
- to
- (P)cDos | <AltF>
- Note that the character enclosed in the braces (*{’ and *}’) defines the command character that invokes the menu line. This command character may be in the middle of the word — for example, Pc{D}os — or left out all together if not required.
- The number of leading spaces before the menu text defines the Level of the menu within the menu tree. Don’t change this unless the menu tree is to be changed, as described in the next section.
- Changing the Menu Tree
- In addition to changing the text of the menu, you can also change the actual structure of the menu tree. This means you can reorder menus, create new submenus or even delete unwanted commands.
- To illustrate how to change the menu tree, suppose you wish to group the “Compilation Functions” together in a single menu. To do this, the lines containing:
- {EJdit
- {CJompile
- {M}ake
- {L)ink
- {R)un
- {OJptions
- could be changed to: | Editor
- | Compiler
- | Make
- | Linker
- | Run program
- 1 <AltE> <AltC> <AltM> <AltL> <AltR> <AltO>
- {E}dit
- {CJompilation | Editor <AltE>
- {CJompile | Compiler <AltC>
- {MJake Make {A}11 | Make
- | Make All <AltM>
- {L}ink | Linker <AltL>
- (R}un {0}ptions I Run program 1 <AltR>
- <AltO>
- This creates a new submenu under the command Compilation. The indentation of the menu text (i.e. number of leading spaces) determines the start and end of each menu. In the above example, this means that the the extra spaces added in front of Compile cause a new submenu to be started. This submenu continues until Options where the indentation returns to its previous level. Look at the Options Menu for further examples of “nested” submenus. Notice that one of the options under Compilation — Make All — uses a letter other than the first letter of the option to invoke it.
- Changing ShortCut Keys
- At the end of a Menu Definition Line, there also may be a ShortCut key sequence defined. This sequence activates that function or submenu. You may change or add to these key definitions to change the ShortCut keys. For example, to assign the key [0| to the Options Run Command-Line function, you would change the line:
- {C} - Command line | Command Line
- to
- {C} - Command line
- | Command Line <F4>
- You can specify multiple keys after the line, if you need more than one key to activate the same function. See “Key Sequences,” on page 89, for a complete description of ShortCut key specification.
- You can also define keys independently of the menus. An example of this is the Review Screen function, which is defined as follows:
- (Key | Review Screen <AltF5>
- You can change, add to, or delete these key definitions in the same way as changing the Menu Definition lines.
- External DOS Commands
- As you may have already noticed, there is an Action Name after the * | ’ and before the ShortCut keys in Menu and Key Definition lines. This name defines the action that is performed when the menu line is selected, or the ShortCut key is pressed.
- In addition to the pre-defined environment actions (which are listed in the sections “Global Actions,” page 87, and “Editor Actions,” page 88) you can also install a LMDS Command String which will be executed under a DOS shell whenever the Menu Line is selected. In this way, you can attach your own programs to the environment menus and keys. For example, if you required the DOS command
- locate *.mod
- as a menu function, then you might add the line
- {LJocate | 'locate *.mod' <AltF3>
- to the menu definition. The DOS command required should be enclosed by single or double quote characters, and may prompt for parameters by placing ‘%M’ or *%P’ within the command string. See “External Command Parameters,” page 89, for more details.
- The Editor Keys and Menus
- The Environment Editor has its own specific keys and menus. These are separated from the rest of the Menu Definition by the line
- !Editor
- Everything after this line is only valid when within the Editor. If you want to add or change Editor keys or menus, the you should edit the lines after ! Editor.
- Changing Help Lines
- You can change two of the Help Lines within the environment. The first is the Main Menu Help Line, which is defined before the lEditor line, and the second is the Editor Help Line, which is defined after. See “Help Lines,” page 84, for the format of the Help Lines.
- Menu Definition File Format
- The Menu Definition file contains lines of text that may be either Menu Directives or Menu Text. Blank lines are not significant, and can therefore be used for clarity. Menu Directives inform the menu system of Menu Types, Menu Titles, Help Line Text and ShortCut Keys. The Menu Text defines the structure of the menu tree and the associated functions.
- Menu Directives
- Menu Directives always begin with an T. Following the T is the directive name, together with any parameters required. Directives can be global to the entire environment, or they can be restricted to the editor.
- The directives, together with some examples, are as follows
- Menu Type You can have three forms of Menu Type directives
- !PopUp [ MenuTitle ] | KeySequences or
- !PullDown [ MenuTitle ] | KeySequences
- or
- !LinePull | KeySequences
- Such a directive defines the type and title of a top level menu and any ShortCut keys that should invoke the menu. The menu title and shortcut keys are optional.
- The type of the top menu can be one of the following
- • Pop Up (default), which has vertical menu selections
- • Pull Down, which has horizontal menu selections
- • Line Pull, which is a Pull Down menu with no frame or title
- The menu title is text — enclosed by square brackets ( [ and ] ) — and will appear in the top center of the frame enclosing the menu.
- You can define one or more KeySequences to invoke the menu. The KeySequence format is described in “Key Sequences,” page 89.
- Example:
- IPullDown [ TopSpeed M2 } | <F10>
- specifies that the menu named “TopSpeed M2” is to be a pull down menu, and is to be activated by pressing 1F1OIL
- Editor Section
- !Editor
- Generally, your directives will apply to the entire environment. Sometimes, however, you may have a directives that should apply only to the editor. For example, you might want to use a different Help Line for the editor.
- To make this possible, the menu definition is split into two distinct sections. The first section contains general menus and keys, available from anywhere within the environment. The second section contains editor menus and keys that are only available while editing. To split the two sections, the directive ! Editor must be included in the menu definition. Everything above this directive is global to the environment, and everything below is local to the editor.
- Help Lines
- !Helpline [ help line text ]
- You can define two different user Help Lines. The first is the Help Line displayed when any menu is active. This definition should be located anywhere before the ! Editor directive. The second Help Line is displayed while editing. This must be located after the ! Editor directive.
- Example:
- !HelpLine [ {F10}-main menu {Esc}-close {Alt-X}-exit ]
- Within the Help Line text, { and } can be used to indicate highlighted text, and the escape sequence “nnn can be used to specify the character with ascii value nnn. For example, "26 is the right arrow character.
- Thus, the directive in the example specifies that FIO, Esc and Alt-X should be highlighted and that these should be associated with the commands “main menu,” “close” and “exit,” respectively.
- ShortCut Key Definition
- !Key | Action KeySequences
- You can use the ! Key directive to define ShortCut keys that invoke commands not found on any menu. This directive assigns the specified action to one or more key sequences. The format of actions (which can be a DOS command) is described in the section: “External Commands,” page 88, and the format of key sequences is described in “Key Sequences,” page 89.
- Whenever a sequence of keys is pressed, the appropriate action will be invoked. Keys defined before the ’Editor directive will be active anywhere within the environment, and keys defined after will be active only while editing. An example of an Editor Key is the Case Correct Key (see “Other Editor Commands,” page 66), which is defined as follows:
- !Key | Ed Case Correct <ShiftF7>
- Submenu Title
- ![ submenu title text ]
- This directive allows you to specify the title text displayed in the frame of submenus. The directive should appear immediately before the indented Menu Text for the submenu. Note that the directive must be indented the same number of spaces as the submenu.
- Example:
- {Q} - quick commands | <CtrlQ>
- ![ Quick Menu ] {F} - find | EdFind CCtrlQ F>
- {G} - goto line j EdGotoLine <CtrlQ G>
- This directive specifies that the submenu invoked by pressing
- should be
- called “Quick Menu.”
- Comment
- !! <comment text>
- A line beginning with *!! ’ serves as a comment on other material. The line is ignored by the environment, but will be useful to you or someone else trying to get an overview of the file’s contents. You can include comment lines anywhere in the file.
- Example:
- !! TopSpeed Default Modula-2 Menu Definition
- Menu Line Definition
- A menu line defines the menu level, the menu text, the command character, and the function to be invoked, as well as any ShortCut keys.
- The format of a menu line definition is:
- MenuText | Action KeySequences
- The menu text specifies what will appear on the screen when the menu is invoked. The level of the menu is determined by the number of leading spaces before the menu text.
- When a new submenu definition begins, its text is indented further to the right. When the submenu definition ends, the text is indented to the left to the same indentation as the parent menu.
- Example:
- {OJptions
- | <AltO>
- I
- | CompOptF <AltO F>
- | CompOptE
- j CompOptN
- I
- | CommandLine <AltO C>
- I RunOptA
- | RunOptT
- (C}ompiler
- {F} - Optimize
- {E) - Stop on 1st error
- {N} - Line numbers
- {R}un
- {C} - Command line
- {A} - Auto make :
- {1} - Timed run :
- This declares a menu invoked by selecting Options (or pressing |Alt][[O||), and two submenus that are invoked by selecting Compiler and Run, respectively.
- The Action is the name of the function to be invoked and is described in the following section, “Menu Actions”.
- Note that menu lines that invoke submenus (Options, Compiler and Run, in the above example) should not have an Action defined. They can have associated ShortCut keys, however.
- Within the menu text, you can define a single command character (which invokes that menu line) by enclosing that character within braces — for example, {E}. A command character defined in this way should be unique for that particular menu.
- Trailing and leading spaces are ignored within the menu text (except that leading spaces serve to define the menu level, as described above). If you need actual spaces at the beginning or end of the text, you should use the underscore (_) character. This will be translated into actual spaces in the displayed menu text.
- A number of the pre-defined actions require 3 underscores (i.e. ) to represent
- spaces at the end of the menu text. This space is used to display an option state (e.g. ON/OFF). The actions that require this space are listed below.
- Menu Actions
- The menu actions are invoked either by a key or by menu selection. There are two different kinds of actions, Pre-Defined Actions and External Actions. Pre-Defined Actions invoke an environment command, while External Actions run an external program under DOS.
- Pre-Defined Actions These actions are specified by name. The first eight non-space characters in the name are significant. The following lists specify the pre-defined actions, together with the page number of the section that describes their function. The first list shows the global actions and the second list shows the actions accessible in the editor.
- Global Actions The Global Actions, which may be invoked throughout the environment, are as follows:
- Load File (55)
- Pick File (56)
- Save File (57)
- Save All Files (57)
- Main Module (57)
- Change Dir (57)
- Directory (57)
- DOS Shell (58)
- Execute (58)
- Quit (58)
- Editor (59)
- Compiler (67)
- Make (69)
- Linker (71)
- Comp Opt B * (73)
- Comp Opt E * (73)
- Comp Opt F * (73)
- Comp Opt N * (73)
- Comp Opt D * (73)
- Comp Opt V * (74)
- Comp Opt J * (73)
- Link Opt I * (74)
- Link Opt S * (74)
- Link Opt M * (74)
- Link Opt T * (74)
- Link Opt C * (74)
- Link Opt W * (74)
- Command Line (75)
- Run Opt A * (75)
- Run Opt T * (75)
- Auto Save Files * (75)
- Default Filenames (75)
- Default Extensions (76)
- No Of Backups * (76)
- Top Scroll Zone * (76)
- Bottom Scroll Zone * (76)
- Env Opt B * (76)
- Env Opt S * (77)
- Env Opt H * (76)
- Env Opt C * (76)
- Load Red File (77)
- Load Config File (77)
- Save Config File (77)
- Make All (77)
- Info (77)
- Editl (62)
- Edit2 (62)
- Edit3 (62)
- Edit 4 (62)
- EditO (62)
- Zoom Window (52)
- Cycle Windows (62)
- Review Screen (50)
- Run Program (51)
- Editor Actions The Editor Actions, which may be invoked throughout the editor but not elsewhere, are as follows:
- Ed Load File (60) Ed Opt Indent * (65)
- Ed Write File (61) Ed Opt Hard Tabs * (65)
- Ed Find (66) Ed Opt Tab Width * (65)
- Ed Replace (66) Ed Word Left (63)
- Ed Start Screen (63) Ed Page Down (63)
- Ed End Screen (63) Ed Move Right (63)
- Ed Start File (63) Ed Move Up (63)
- Ed End File (63) Ed Word Right (63)
- Ed Start Line (63) Ed Del Forward (63)
- Ed End Line (63) Ed Del Backward (63)
- Ed Goto Begin Block (63) Ed Tab (63)
- Ed Goto End Block (63) Ed Find Again (66)
- Ed Prev Position (63) Ed Ins Line (63)
- Ed Del End Line (63) Ed Ins Below (63)
- Ed Restore Line (63) Ed Prefix (63)
- Ed Goto Line (63) Ed Page Up (63)
- Ed Begin Block (64) Ed Move Left (63)
- Ed End Block (64) Ed Del Word (63)
- Ed Hide Block (64) Ed Upper Case (66)
- Ed Mark Word (64) Ed Scrl Down (63)
- Ed Mark Line (64) Ed Move Down (63)
- Ed Copy Block (64) Ed Del Line (63)
- Ed Move Block (64) Ed Scrl Up (63)
- Ed Del Block (64) Ed Next Error (66)
- Ed Read Block (64) Ed Prev Error (66)
- Ed Write Block (64) Ed Case Correct (66)
- Ed Get Block (64) Ed Goto Ml (66)
- Ed Print Block (64) Ed Goto M2 (66)
- Ed Indent Block (64) Ed Set Ml (66)
- Ed Insert * (65) Ed Set M2 (66)
- Ed Quit (66)
- Editor Actions can only be used as the action within the Editor section of the menu definition, while Global Actions can be used in either section.
- The functions marked with an **’ require space for a three character field left at the end of the menu text, as described in “Menu Line Definition,” page 86.
- External Commands Within the environment menu system it’s possible to attach an external DOS command or program to any key or menu entry. This can be done by enclosing the command line in either single or double quotes and using it as an Action in the Menu or Key definition described above.
- For example, suppose you have the following menu lines defined:
- {B)ackup Files | 'copy *.mod a:' !Key | "find 'Version' *.MOD" <AltZ>
- If you select the Backup Files menu entry, then the DOS command line
- copy *.mod a:
- is executed. Similarly, when you press lfAJt]([Z]| the command line
- find 'Version' *.MOD
- is executed.
- External Command Parameters Suppose you need to pass the Main Module name to the command you want to execute. You can do this, by including %M in the command at the spot in which you want the name.
- If this name has been specified, the system will use the name. If no name has been specified, you’ll be prompted for a name. Similarly %P (prompt string) in the command string will prompt for a parameter, while displaying the prompt string. The %P will then be expanded to the entered string.
- For example, suppose you define:
- {E}xase | 'del %P (File to delete: )'
- (D)ebug | 'debug %M.EXE'
- Selecting Erase prompts for
- File to delete:
- After you type a file name (let’s say, FTODEL) and press |Enter|, the command line del £todel
- is executed. Similarly selecting Debug will prompt for the Main Module name and will then execute the command
- debug mainfile.exe
- You can include as many *%P’s as you need in the command string.
- Key Sequences
- The ! Key directives and menu entries can have one or more KeySequences attached. These key sequences consist of key names enclosed by the characters *<’ and *>’. Examples of key sequences include:
- <AltA> Alt A
- <CtrlZ> Control Z
- <CtrlQ D>
- <CtrlK M 1> Control Q followed by D
- Control K followed by M then 1
- <ShiftF2> F2 Shifted
- <Home End> Home followed by End
- The following keys are valid and represent the names to use:
- Fl - FIO ShiftFl - ShiftFlO CtrlFl - CtrlFlO AltFl - AltFlO
- AltO - Alt9 AltA - AltZ
- UpArr CtrlUpArr DownArr CtrlDownArr LeftArr CtrlLeftArr RightArr Ct rIRightArr
- PageDown CtrlPageDown PageUp CtrlPageUp Home CtrlHome End CtrlEnd
- Del Ins AltEqual ShiftTab
- If ambiguous key sequences are defined in the menu definition (for example, <CtrlK> and <CtrlK B> and <CtrlK K>), then the menu system will wait a short interval after the initial sequence has been typed. If the remainder of a longer sequence is typed, within this time then the long sequence will be executed. Otherwise, the shorter sequence will be assumed. This can be used to create automatic “pop-up” menus in the menu definition.
- To remove the automatic Pop-Up facility from the standard menu configuration, remove the “short” key sequences — that is, remove the lines in M2. MNU containing the sequences <CtrlQ>, <CtrlK> and <CtrlO>.
- Changing Windows
- At any time you can change the position, size, and coloring of the active window. This is achieved by pressing RScrollLockl] which enters the Window Control Mode. In this mode you can resize and reposition the window. You can even recolor the window, by pressing |Enter||. To exit the Window Control Mode, press |ScrollLock|| again. As you s-aw earlier, in addition to the Window Control Mode, there is also instant Zoom/Unzoom using the |F5|| key.
- Repositioning Windows
- To reposition a window, use the cursor keys on the numeric keypad after pressing IIScrollLockjl. These move the window to the required position, uncovering any windows that may lie beneath. Of course full-sized, or Zoomed, windows cannot be repositioned as they have no room to move. Provided that the environment doesn’t need to reposition a window for a specific context, the new window position will be saved in the Configuration and Session files. You can customize the layout of the Editor Windows by placing them, for example, side-by-side or above each other.
- Resizing Windows
- You can resize each of the Editor Windows wtoi in the Window Control Mode. To do this, use Shift Cursor keys — that is, IShift||[T||, UShiftl^ri], and so forth.
- When resizing a window the top leftjiand comer remains fixgd, and the bottom and right edges move. In this way, the window. Similarly, IlShlft ||m| contracts and I Shift window. The size of each window is saved in the session file and restored when
- contracts and |IShift||UJ| expands the height of expands the width of the
- re-entering the environment.
- Recoloring Windows
- You can recolor the active window by pressing UScrollLockl] then H Enter j. To recolor different areas:
- • Select the area by pressing the |PgUpl| or IPeDnll keys until the text in the required area flashes
- • Use FH1 and FH] to change the background and Q and Q to change the foreground colors
- When you find the desired color, you can either select a new area or you can exit Window Control Mode by pressing |IScrollLockJ| again. If you want to abort recoloring, press |iCtrl||[U|| to restore the original colors.
- The Help Line at the bottom of the screen (see “Help Lines,” page 84) can be recolored by pressing [ScrolILockl | Enter||
- The color of each window is saved in the Configuration and Session files.
- If Options Setup High-Background (see “High Background,” page 76) is ON and you are using an IBM or compatible CGA display, then you can set the background to any of the 16 colors available including the bright backgrounds. Otherwise only eight backgrounds are available on the CGA, together with 16 foreground colors.
- Note that to make recoloring of the environment easier, windows having similar uses are grouped together into Window Classes. Recoloring any window of a window class will automatically recolor all other windows in that class.
- Window classes include the following:
- • Menu windows
- • Error/Waming windows
- • Prompt windows
- • Input windows
- • Directory/File selection windows
- • Compiler/Make/Link windows
- • Each Editor Window
- Customizing the Error Messages
- You can customize or translate the error messages produced by the compiler, by editing the file M2 . ERR.
- This is an ASCII text file, with one line per error message. Each line should start with the error number, followed by the error message text. You can define macros for commonly occurring text by starting a line with %A—%Z, followed by the macro text.
- For example
- %Z File system error
- defines a macro %Z that will be expanded to “File system error” whenever %Z occurs in either Error or Macro definition text.
- The following macros are predefined by the compiler
- %A Used to define the Line/Column string used by the batch compiler. The macro definition is actually as follows:
- (%F %L %C)
- When expanded, this macro displays the following information within parentheses: file name (%F), number of line on which error was found (%L) and column in which error was found (%C).
- %C Filled in to be the Column of the error.
- %L Filled in to be the Line of the error.
- %F The file name in which the error occurred.
- %N The name the compiler was processing when the error occurred.
- Other macros also have been defined in the M2. ERR file included with your TopSpeed Modula-2 system. These include:
- %E Writes the Line/Column string followed by the string “Error:”
- %I Writes the Line/Column string followed by the string “Internal Error:”
- %X Writes the Line/Column string followed by the string “Compiler Limit:”
- %Y Writes the Line/Column string followed by the string “Lexical Error:”
- %Z Writes the Line/Column string followed by the string “File System Error:”
- See the M2. err file for the exact format of these macros. You can redefine these macros if you wish; you cannot redefine the macros that are predefined by the compiler. The %A macro is actually defined in the M2 . ERR file, as described above. Since it is used in many of the error messages, you should be very careful about redefining it.
- Chapter 6
- The Language
- This chapter gives a concise definition of the TopSpeed Modula-2 language. The language definition is kept compact and should be read with care. This style of presentation is in contrast to the case studies, which give a more informal and explanatory description.
- Programs must conform to the syntax of Modula-2. The syntax specifies the basic textual structure of valid programs. Only syntactically correct programs are accepted by the compiler.
- Secondly, programs must conform to the compile-time (static) semantics of Modula-2. This concerns the meaning associated with program identifiers, and the way they are used. It involves, among other things, type-checking. Errors in these matters are detected by the compiler.
- Finally, programs should conform to the run-time (dynamic) semantics of Modula-2. This involves the actual behavior of an executing program. It is required, for example, that array-index values stay within certain ranges. It is optional whether these constraining rules are enforced during program execution. If not, violating them will generally produce undefined results, but can be used to achieve certain devious effects.
- The underlying machine architecture is the 8086-family with an address space of 220 (IM) bytes of 8 bits. A physical address is formed from a 16-bit segment and a 16-bit offset; the absolute byte-address is: (16 * segment) + offset. Therefore, address arithmetic is handled differently than specified by Wirth (in Programming in Modula-2). See the discussion of pointer constructors later in this chapter (page 109).
- Boldface will be used when new concepts are introduced, or when an ordinary phrase is given a special well-defined meaning.
- Examples will be used to illustrate each of the concepts described; some will refer to entities declared in previous examples.
- Textual Topics
- Tokens
- Tokens are the basic textual elements on which the structure of Modula-2 is based. A token is a sequence of characters from the ASCII set. The tokens fall into four classes: keywords, delimiters, generic tokens, and separators. The keywords and delimiters consist of fixed sequences of characters, whereas for each generic token a multitude of character sequences are possible.
- The keywords are:
- AND FOR OR
- ARRAY BEGIN
- BY
- CASE
- CONST
- DEFINITION DIV
- DO
- ELSE
- ELSIF
- END
- EXIT EXPORT FORWARD FROM GOTO IF
- IMPLEMENTATION IMPORT
- IN LABEL LOOP MOD MODULE NOT OF POINTER
- PROCEDURE QUALIFIED RECORD REPEAT RETURN SET
- THEN TO TYPE UNTIL VAR WHILE WITH
- The delimiters are:
- + * / : = &
- : ( ) [ 1 { } * ~
- = # <> < ■<— > >= « »
- The generic tokens are:
- Identifier: a list of letters (‘A’ to ‘Z’, ‘a’ to ‘z’ and and digits (‘0’
- to ‘9’) starting with a letter; the 43 keywords are excluded. Uppercase and lowercase letters are considered distinct.
- Examples:
- HelloThere Agent_007
- main
- Decimal literal: a list of digits.
- Examples: 12345 0 255
- Octal literal: a list of octal digits (‘0’ to ‘7’) followed by ‘B’.
- Examples:
- 10B (=8) 377B (=255)
- Hex literal: a list of digits and hexadecimal letters (‘A’ to ‘F’) followed by ‘H’; it must start with a digit.
- Examples:
- 10H (=16) OFFH (=255)
- Real literal: a list of digits, followed by optionally followed by a list of digits, optionally followed by an exponent part consisting of an ‘E’ followed by an optional sign, *+’ or followed by a list of digits.
- Examples:
- 3.14 12.3E-3 (=0.0123)
- String literal: a list of characters enclosed in quotes (’) or double-quotes (”). The enclosed list cannot contain the enclosing character, nor can the list extend over line breaks. A string of length one is alternatively called a character. A character can also be specified by its octal ASCII value as a list of octal digits followed by ‘C’.
- Examples:
- 'Hi' "that's ok" 101C (='A')
- The separators are:
- White-spaces: any list of blanks, tabs and line breaks.
- Comments: any list of characters enclosed in ‘ (*’ and **) ’. Comments can
- be nested and can extend over line breaks.
- The tokens *#’ and ‘O’ can be used interchangeably, as can *&’ and AND. The tokens and NOT can also be used interchangeably.
- Identifiers are used to denote user-defined entities.
- The decimal, octal, and hex literals denote whole numbers.
- Real literals denote real numbers. The exponent part denotes multiplication by the specified power of 10.
- As many characters as possible are fitted into each token: 123 is one three-digit literal, not three one-digit literals.
- Separators, except comments starting ‘ (*$’ (see Chapter 7), have no influence on the meaning of the program except to separate tokens.
- Syntax
- The syntax of Modula-2 describes how sequences of tokens are grouped to form valid program text. The syntax contains a set of syntactical constructs and productions. The productions specify how constructs and tokens are combined to form new constructs. Each construct can have several alternative productions, each specifying a possible expansion of that construct. The alternatives will be shown where relevant, rather than being shown collectively.
- The following meta-symbols are used in the productions:
- square brackets ([ and ]) are used to enclose optional parts.
- curly braces ({ and }) are used to enclose parts that can be repeated zero
- or more times.
- bar (I) is used to separate alternatives.
- definition symbol (: : =) separates the syntactical construct being defined from its expansion.
- Mixed case is used for names of constructs, upper case for keywords. Delimiters are shown in single quotes. The generic tokens are named: Id, WholeNumber, RealNumber and String.
- The productions form the backbone of the language definition, and should be ‘read’ like ordinary statements; the text following each production will implicitly refer to its constituents. Thus
- • IdLlst ::= Id { Id }
- defines a list of one or more identifiers separated by commas.
- Examples:
- HelloThere, _main , X
- Agent_007
- Declarations and Visibility
- Every identifier must either be declared or predefined. Declarations introduce programmer-defined entities and establish their properties. After an identifier is declared, it is used to name the declared entity:
- • Name ::= Id
- Declarations come in lists:
- • Del List ::= { Declaration }
- Identifiers must be declared before they are used. The only exception is types designated by pointers (see “Pointer Types,” page 104), which must be declared by the end of the same declaration list. Before the declaration, operations requiring knowledge of the designated type are illegal — for example, anything involving de-referencing.
- All identifiers declared in a declaration list must be distinct.
- A declaration remains in effect throughout the scope of the declaration. The scope extends from the declaration itself, throughout the rest of the declaration list, and throughout a possible list of statements associated with the declaration list.
- Declaration lists can be nested by means of procedure bodies and modules (see “Bodies,” page 116 and “Modules,” page 121), and it is legal to re-declare identifiers in such inner scopes. WITH-statements are another way of making nested scopes. A particular instance of an identifier denotes the entity declared previously in the innermost enclosing scope; it hides entities denoted, by the same identifier in outer scopes.
- Example:
- / /
- MODULE M;
- VAR I,J: CARDINAL; (* Two variables belonging to M *) PROCEDURE P;
- VAR I,K: INTEGER; (* Two variable^ belonging to P *) BEGIN
- I := 7; (* P's I *)
- J := 8; (* M's J *)
- K := 9; (* P's K *)
- END P;
- BEGIN
- I := 10; (* M's I *)
- J := 11; (* M's J *)
- (* no K is visible here *) END M;
- Alias declarations do not declare new entities, but introduce alternative names for existing ones:
- • Declaration ::= const { id Name }
- The name can denote any entity.
- Example: CONST VisibleVersion : := AboutToBeHidden;
- The predefined identifiers, listed below, are considered to be declared in an (outermost) scope, which is all-enclosing The meaning of individual identifiers is explained later.
- ABS DEC LONGCARD ORD WORD
- ADDRESS DISPOSE LONGINT PROC VSIZE
- ADR EXCL LONGREAL REAL
- BITSET FALSE LONGWORD SHORTADDR
- BOOLEAN FLOAT MAX SHORTCARD
- BYTE HALT MIN SHORTINT
- CAP HIGH NEW SIZE
- CARDINAL INC NIL TRUE
- CHAR INCL NULLPROC TRUNC
- CHR INTEGER ODD VAL
- Types
- A type defines a set of values. Modula-2 contains a number of predefined types, and constructs for defining new types. New types can be given names in type declarations:
- • Declaration type { Id '=’ TypeDef}
- Some types are called simple types:
- • TypeDef ::= SlmpleType
- A type can be just the name of a type:
- • SimpleType ::= Name
- Note: this syntactical construct is used for naming any type, not just simple ones.
- If the definition of a type declaration is just the name of a type, the defined type is identical to the named one.
- Example: TYPE O'ustCardinal = CARDINAL;
- Numeric Types
- CARDINAL Types M'odula-2 has three predefined cardinal types, whose values are unsigned whole numbers in the specified ranges:
- CARDINAL: SHORTCARD: LONGCARD:
- 0 to 65535
- (0 to 216 - 1)
- (0 to 28 - 1)
- (0 to 232 - 1)
- 0 to 255
- 0 to 4294967295
- INTEGER Types Similarly, there are three predefined integer types, whose values are signed whole numbers in the specified ranges:
- INTEGER: -32768 to +32767 (-215 to 215 - 1)
- SHORTINT: -128 to+127 (-27 to 27 - 1)
- LONGINT: -2147483648 to+2147483647 (-231 to 231 - 1)
- Collectively, the integer and cardinal types are called whole number types.
- REAL Types There are two predefined real types, whose values are the real numbers to a certain precision:
- REAL: +/- 1.2E-38 to 3.4E+38 6 digits precision
- LONGREAL: +/- 2.3E-308 to 1.7E+308 15 digits precision
- Collectively, the integer, cardinal and real types are called numeric types.
- Ordinal Types
- CHAR Type The predefined type CHAR contains 256 values. The first 128 are the characters of the ASCH set, the last 128 are special graphic characters.
- Enumeration Types Modula-2 provides a mechanism for defining enumeration types by giving a complete list of the values in the type. The values, enumeration literals, are represented by identifiers, which are declared by the type definition:
- • SimpleType ::= '(’ IdList')’
- Example:
- TYPE Color = (Red,Yellow,Green,Brown,Blue,Pink,Black); Gender = (Male,Female);
- Modula-2 has one predefined enumeration type containing truth values:
- TYPE BOOLEAN = (FALSE, TRUE) ;
- Collectively, the integer, cardinal, character, and enumeration types are called ordinal types; they have whole-number ordinal values. Enumeration literals are numbered consecutively starting from zero. Likewise for the character type. The short ordinal types exclude LONGCARD and LONGINT.
- Subrange Types
- Given an ordinal type, it is possible to define a subrange type of that base type:
- • SlmpleType ::= [Name ] ‘[’ Expr Expr ']’
- The two expressions must be constant and of the same type. They restrict the values of the type by specifying a lower and upper bound (lower <= upper). If the Name is present it names the base type; otherwise, if the expression values are of unspecified whole-number type, the base type is assumed to be INTEGER if the first expression is negative, otherwise CARDINAL.
- Examples:
- TYPE Year = [1900..2001]; (* Base is CARDINAL *)
- Mylnt = [-1000..+1000]; (* Base is INTEGER *)
- Digits = ['0'..'9']; (* Base is CHAR *)
- IntYear = INTEGER [1900..2001]; (* Base is INTEGER *)
- LongYear = LONGCARD[101900..102001];
- HighColor = [Blue..Black]; (* Base is Color *)
- Subrange types are themselves ordinal types.
- Set Types
- Given any short ordinal type, it is possible to define a set type whose values are (unordered) sets of values of that short ordinal type:
- • TypeDef ::= set of SimpleType
- A set type contains any subset of values of the set element type.
- Example:
- TYPE Chars = SET OF CHAR;
- There is one predefined set type:
- TYPE BITSET = SET OF [0..15];
- Array Types
- Array types provide mappings from a short ordinal index type onto any array element type:
- • TypeDef ::= array IndexLIst of TypeDef
- • IndexLIst ::= SlmpleType { ’ SlmpleType }
- An array type definition with more than one index type is equivalent to the expanded type definition:
- ARRAY Indexl OF ARRAY Index2 ... OF TypeDef
- All explanations assume a single index type.
- A value of an array type contains an ordered collection of values of the element type — one for each value in the index type.
- Examples:
- TYPE Namestring = ARRAY [0..24] OF CHAR; (* A person's name *) IntArray » ARRAY BOOLEAN OF INTEGER;
- Record Types
- Record types provide an aggregation of individual fields:
- • TypeDef ::= record FleldDefLIst end
- • FleldDefLIst ::= FieldDef { Field Def }
- • FieldDef ::= [ Id ListTypeDef ]
- All the identifiers, called field names, must be distinct, but they are local to the record type definition and need not be distinct from other identifiers.
- A record value contains one value of the relevant type for each field.
- Examples:
- TYPE Person = RECORD
- First,Last: Namestring;
- Age: SHORTCARD [0..125];
- END;
- AdrPair = RECORD Ofz,Seg: CARDINAL; END;
- Variant record types allow for alternative groups of fields, variants, to be present in a record value. Variant parts can be arbitrarily nested.
- • Field Def ::= Variant Part
- • VariantPart ::= case [ Id] Name of Variant { '|' Variant} /■else FieldDefUst J end
- • Variant ::= [ CholceList FieldDefUst ]
- • CholceList ::= Choice { Choice }
- • Choice ::= Expr [ ’ Expr ]
- The optional tag identifier after CASE is followed by the name of a short ordinal tag type. If the tag identifier is present, it defines an actual field of that type.
- The variants and the optional ELSE part each specify a list of field definitions, but only the fields of one of these variants are present in any value of the variant record type.
- The choice expressions must be constant and of the tag type, and must not have overlapping values. A choice with two expressions denotes all values in the range. Each choice list should specify the tag values for which the corresponding variant is present; the ELSE-part covers any remaining values.
- The presence or absence of variant fields is merely logical; they are always all accessible, but they share storage.
- Example:
- TYPE Location =
- RECORD
- Value: BYTE;
- CASE Simple: BOOLEAN OF
- | TRUE: ByteOfz: LONGCARD;
- I FALSE: SegOfz: AdrPair;
- END;
- END;
- Pointer Types
- The values of a pointer type are access paths to objects of a designated type:
- • TypeDef ::= pointer [ Expr ] to TypeDef
- If the expression is omitted, an absolute pointer type is defined; the values of the type are complete 32-bit segment/offset physical addresses.
- By including a CARDINAL expression (after POINTER), a based pointer type is defined. Such values only contain the offset part of a physical address. The segment part is obtained by evaluating the expression every time the designated object is accessed. Based pointers are thus short, 16-bit.
- Note: Based pointers allow relocated objects to be referenced by just modifying the base (segment) value (leaving the offset unaffected).
- Examples:
- TYPE ListPtr = POINTER TO ListNode; (* Note: ListNode not defined yet *) ListNode = RECORD
- Value: CARDINAL; (* element value *)
- NextNode: ListPtr; (* next element *) END;
- ShortPtr = POINTER Base TO ListNode;
- There are two predefined pointer types:
- TYPE ADDRESS = POINTER TO WORD;
- SHORTADDR = POINTER 0 TO WORD; (* Zero base segment *)
- The values in a pointer type either are obtained as the (absolute) addresses of existing objects of the designated type, or they can be raw storage addresses obtained from a storage manager (see Chapter 8).
- Array, record and pointer types are collectively called compound types; the rest, except for set types, are the simple types.
- Type Compatibility
- Numerous situations require types to be compatible; there are three levels of compatibility, each of decreasing strength.
- The most restrictive — and hence, the strongest — is to require types to be identical; that is, they must denote the same type definition.
- Next comes compatible. This includes subrange types being compatible with their base types and other subrange types of the same base type. ADDRESS is compatible with any absolute pointer type, and SHORTADDR with any based pointer type.
- Finally assignment compatibility also holds between the pairs CARDINAL / INTEGER, SHORTCARD / SHORTINT and LONGCARD / LONGINT.
- There are three predefined types called BYTE, WORD and LONGWORD. They correspond to 1, 2 and 4 bytes of memory, respectively, and are assignment compatible with all other types of equal size.
- Special compatibility rules apply to formal parameters (see “Calling Procedures,” page 118).
- Objects and Values
- Objects have types and hold values exclusively of that type. There are two kinds of objects: variables and formal parameters (see page 115). Objects of array and record types can contain several component objects.
- Variables have to be declared:
- • Declaration ::= var { Varld { Varld } TypeDef }
- • Varld ::= id
- Each declaration declares all the identifiers of the list to be variables of the specified type. Their initial values are undefined.
- Examples:
- VAR CARDINAL;
- Base: CARDINAL;
- L: LONGCARD;
- X,Y: LONGREAL;
- P: POINTER TO INTEGER;
- S: ARRAY [1..100] OF CHAR;
- R: RECORD X,Y: INTEGER; END;
- C: CHAR;
- Z: Chars;
- Bad : BOOLEAN;
- Loc: Location;
- Persons: ARRAY BOOLEAN OF POINTER TO Person;
- A variable can be placed at a fixed physical address, by specifying constant expressions of type CARDINAL for the segment and offset:
- • Varld ::= Id ‘[’ Expr Expr ']’
- Example:
- VAR ColorScreen [0B800H:0] : ARRAY [1..25] OF
- ARRAY [1..80] OF
- RECORD
- Chr: CHAR;
- Atr: SHORTCARD;
- END;
- Constants
- Constant literals denote the most basic values:
- • Value ::= WholeNumber
- • Value ::= String
- The whole numbers are possible values for the integer and cardinal types, the real numbers for the real types, and strings for the character type (in which case, the string must have length 1) and for types of the form: ARRAY ... OF CHAR.
- Constant record and array values are formed with aggregates:
- • Value ::= Name ‘(’ Expr Expr { Expr } ')’
- The expressions, of which there must be at least two, are constant and give the component values for the named type.
- For array types, one value must be given for each value in the index range.
- For record types, one value is given for each field present. Values must be specified even for absent tag fields, in order to determine to which variant the following values belong.
- Named constants can be declared, introducing identifiers that represent constant values:
- • Declaration const { Id '=’ Expr }
- There is a predefined constant, NIL, compatible with any absolute pointer type.
- Neither literals nor named constants are objects.
- Examples:
- CONST Pi = 3.14159;
- Ratio = 360.0 / (2.0 * Pi) ;
- K = 1024;
- P = Person("Donald","Duck", 50) ;
- LastLoc = Location(0,FALSE,AdrPair(0FFFFH,0FH));
- X = IntArray(-12345,16*K);
- S = Chars { 'a', ' e', 'i', 'o', 'u'};
- Set Values
- Set values are formed with a set constructor:
- • Value ::= [ Name ] '{’ [ CholceList ] *} ’
- The expressions of the choices are values of the set element type; they need not be constant. The name denotes the set type; omitting it means BITSET.
- Example:
- Chars { 'A'..'2' , 'a'..'z' , '_' }
- Designators
- Designators are used to denote objects. Component objects of a compound object are designated by supplying suffixes to the designator of the compound object. Suffixes are also used to designate components of named aggregate constants.
- Using a designator as a value means the value of the designated object:
- • Value ::= Designator
- The simplest form of designator is just the name of an entity:
- • Designator ::= Name
- This is also the way to use enumeration literals and named constants as values — just name them.
- Indexing is used to designate components of objects of array types:
- • Designator ::= Designator ‘[’ Expr { Expr} “]’
- A list of index expressions is equivalent to a list of separate indices: X [A,B, C] is equivalent to X[A] [B] [C]. All explanations assume a single index expression.
- The value of the expression must have a type assignment compatible with the index type; the designator selects the corresponding component object.
- Example:
- S[I+7]
- Field selection is used to designate components of objects of record types:
- • Designator ::= Designator Id
- The identifier is any field identifier of the record type; the resulting designator designates that field of the record object.
- Example:
- R.Y
- Dereferencing is used to designate the object pointed at by objects of pointer types:
- • Designator ::= Designator ‘A ’
- If the pointer type is based, this includes evaluation of the base expression.
- Example:
- PA
- Indexing, field selection and dereferencing can be mixed.
- Example:
- Persons[TRUE]A.Last[0] (* First letter of last name *)
- A pointer constructor is provided to combine CARDINAL segment and offset values into a physical address:
- • Designator ::= '[’ Expr Expr [ Name ] ']’
- The name specifies the resulting absolute pointer type; omitting it means ADDRESS.
- Example:
- [ListSeg:FirstNode+N ListPtr]A.Value]
- Expressions
- Expressions specify the computation of values. Within expressions, operators are used to combine operands, which are themselves expressions.
- Expressions, as well as values, have types unless all the operands are numeric literals; in that case, determination of types for such expressions is deferred until the context requires a specific type. This is how the same numeric literals (or named constants) can be used for the different numeric types. Until a context is introduced, the only distinction is between whole numbers and real numbers.
- When the operands of an operator or predefined function are constant, the result is also constant, and is calculated at compile-time.
- Precedence of operators is described in the syntax below; association is left-to-right. Parentheses can be used to enforce any grouping:
- • Expr ::= SimpleExpr [ RelOp SimpleExpr ]
- • SimpleExpr ::= [ SignOp ] Term { AddOp Term }
- • Term ::= Factor { MulOp Factor }
- • Factor ::= '(’ ExPr ')’
- • Factor ::= not Factor
- • Factor ::= Value
- • RelOp ::= '=’ | '#’ | '<’ | '<=' | S’ | *>=’ | in
- • SlgnOp |
- □ AddOp ::= '+ ’ | | or
- • MulOp ::= '*’ | 7’ I div | mod | and | '«’ | “»’
- The operation indicated by an operator depends both on the operator and on the operand types.
- All operators, except IN, require operands of compatible types.
- The relational operators and IN deliver a result of type BOOLEAN. The rest deliver a result of the same type as the operand(s).
- The operators *=’ and '#’ are defined for all types, and compare for equality an inequality, respectively.
- Operators *<’, *<=’, *>’ and *>=’ are defined for the ordinal and real types, and compare for relative ordering. *<=’ and *>=’ are defined for set types, and compare for subset and superset.
- The sign operator *+’ is defined for numeric types; it does nothing. The sign operator is defined for integer and real types, negating the operand.
- The adding operators *+’ and are defined for numeric types and indicate addition and subtraction, respectively. They are also defined for set types and indicate set union and set difference, respectively. Finally, *+’ is also defined for any combination of constant characters and string literals, concatenating them to produce one string constant. The OR operator takes BOOLEAN operands and computes the logical sum; the right operand is only evaluated if the left is FALSE.
- The multiplying operators DIV and MOD are defined for integer and cardinal types, computing product, quotient (truncated towards zero) and remainder (after division). *«’ and *»’ are defined for cardinal types, computing logical left and right shift of the left operand by the amount of the right operand. '*’ and ‘/’are defined for real types, computing (approximate) product and quotient. **’ and ‘/’are defined for set types, computing set intersection and symmetric set difference. The AND operator is defined for BOOLEAN operands, computing the logical product; the right operand is only evaluated if the left is TRUE.
- The NOT operator takes a BOOLEAN operand and complements it.
- The IN operator takes values of set types as right operands and values of the set element type as left operands; it tests whether the element value is in the set value.
- Note: Sets are represented as bitmaps with one bit for each possible element value (indicating its presence), so the set operators ‘+’, **’, ‘/’ and correspond to bitwise boolean operations OR, AND, XOR and AND NOT, respectively.
- Examples:
- (J = 0) OR (I MOD J = I - (I X * Y / Ratio
- R.X + 1
- S[l] IN Z * (Chars{'A'..'F'} 'Line terminated with cr/lf'
- DIV J)*J) (* Always TRUE *)
- + Charsf'0'..'9' ))
- + CHR(13) + CHR(10)
- Statements
- Programs achieve their effect by executing (possibly nested) statements. Statements come in lists and are executed one at a time.
- • StmtList ::= [ Stmt ] { [ Stmt] }
- The after the last statement is optional.
- Assignment Statement
- The assignment statement is used to change the value of an object:
- • Stmt ::= Designator Expr
- The expression is evaluated, and its value replaces the old value of the designated object. The expression must be assignment compatible with the designated object’s type.
- String literals are a special case: they can be assigned to any object whose type is array ... OF CHAR and is long enough to contain the string; if the object is longer than the literal being assigned, a null character (0C) is included after the string value.
- Examples:
- X := 0.0;
- I := J + 1;
- Z := Z - Chars{' a' . .' z' ) ;
- Persons[NOT Bad]A.First := "Kurt";
- IF Statement
- The IF statement is used to select a statement list conditionally depending on BOOLEAN expressions, conditions:
- □ Stmt ::=
- if Expr then StmtList { elsif Expr then StmtList } [ ELSE StmtUSt ] END
- At most one of the statement lists is executed, namely the one following the first expression evaluating to TRUE, where ELSE is treated as ELSIF TRUE THEN.
- Example:
- IF I > J THEN
- M := I;
- ELSIF I < J THEN
- M := J;
- ELSE (* I must be = J *)
- B := TRUE;
- M := I;
- END;
- CASE Statement
- The CASE statement selects between alternative statement lists depending on the value of a case expression of short ordinal type:
- □ Stmt ::= case Expr of Case { ' | ’ Case } [ else StmtList ] end
- • Case ::= [ ChoiceListStmtList ]
- The ‘ | ’ before the first case is optional.
- The types of the choice expressions must be compatible with the case expression type; they must be constant and their values must not overlap.
- The statement list executed is the one whose choice list includes the value of the case expression. If none do, and there is an ELSE, that statement list is executed; otherwise, execution continues with the statement following the case statement.
- Example:
- CASE S[I] OF
- • ': I := 999;
- • 'A' . .'Z' : L := L + 1;
- U := U + 1;
- L := L + 1;
- X := X + 1;
- ELSE END;
- TheEnd := TRUE;
- WHILE Statement
- The WHILE statement is used to execute a statement list zero or more times depending on the value of a condition:
- • Stmt ::= while Expr do StmtLIst end
- The expression is evaluated before each execution of the statement list; repetition stops as soon as the expression is FALSE.
- Example:
- WHILE (I > 0) AND (I MOD 2=0) DO
- I := I DIV 2;
- END;
- REPEAT Statement
- The REPEAT statement is used to execute a statement list one or more times, depending on the value of a condition:
- • Stmt ::= repeat StmtList until Expr
- The expression is evaluated after each execution of the statement list; repetition stops as soon as the expression is TRUE.
- Example:
- REPEAT
- I := I MOD N + 1;
- UNTIL S[I] = '
- LOOP and EXIT Statements
- The LOOP statement is used to execute a statement list repeatedly, with several exit points possible:
- • Stmt ::= loop StmtList end
- • Stmt ::= exit
- An EXIT statement is only legal inside LOOP statements; it terminates the innermost enclosing LOOP.
- Example:
- LOOP
- IF I = J THEN EXIT; END;
- WHILE I < J DO
- I := (I * J) MOD N;
- IF I = 0 THEN
- I := J;
- EXIT; (* exit LOOP, not just WHILE *) END;
- END;
- I := I DIV 2;
- END;
- (* The LOOP has now been EXITed *)
- FOR Statement
- The FOR statement is used to execute a statement list a precalculated number of times, with an ordinal control variable taking on a progressing series of values:
- • Stmt ::= for Id Expr to Expr [ by Expr ] do StmtLlst end
- The first two expressions are evaluated to obtain the start and stop values; they must have types compatible with the ordinal type of the identifier. The expression after BY, the step value, must be a constant whole number; omitting it means +1.
- The control variable takes on ordinal values beginning with the start value and spaced by the step value. The FOR statement terminates when the next value would exceed the stop value. If the start value exceeds the stop value, the statement list is not executed at all. The direction of progression is determined by the sign of the step value.
- The value of the control variable should not be changed inside the statement list, and it is undefined after the FOR statement.
- Example:
- FOR Ball :» Black TO Yellow BY -2 DO
- LastBall := Ball; (* Takes on: Black, Blue, Green *) END;
- WITH Statement
- The WITH statement is used to create a local scope wherein the field names of a record type can be used directly to denote the fields of a particular designated record object.
- • Stmt ::= with Designator do StmtLlst end
- Example:
- WITH Persons[TRUE]A DO
- IF Age < 4 THEN First := "baby";
- ELSIF Age < 15 THEN
- First := "junior";
- END;
- END;
- GOTO Statement
- The GOTO statement is used to alter the flow of execution explicitly:
- • Stmt ::= goto Id
- The target of the jump is indicated by the label identifier, which must be located somewhere in the same body (see “Bodies,” page 116):
- • Stmt ::= Id [ Stmt ]
- Labels must be declared in the body in which they are used:
- • Declaration ::= label IdLlst
- Procedures
- Procedures are used to group commonly performed operations into isolated blocks. Proper procedures are used like statements, whereas functions compute values and are used in expressions.
- Procedures:
- • are declared like other entities, and are subsequently invoked by calls
- • can have parameters which are objects or values supplied at the call
- • finish execution by returning
- Procedures can also be handled without being called; they can be valid values of a procedure type and can be manipulated as such.
- The characteristics of a procedure are specified in a procedure heading:
- • ProcHead ::= procedure Id [ FormalLIst [ Name ] ]
- • FormalLIst ::= '(’ [ FormalSectlon { FormalSectlon } ] “)’
- • FormalSectlon ::= £var ] IdLlst Formallype
- • Formaliype ::= [ array of ] Name
- A procedure heading declares the identifier denoting the procedure. It has a (possibly empty) list of formal parameters declared similarly to variables. The absence of the and the name in the procedure heading indicates a proper procedure; their presence indicates a function, in which case the name states the return type (which can be a structured type).
- Each formal section does the following:
- • declares a list of formal parameters
- • states their formal type
- • indicates whether they are variable, or VAR parameters or value parameters by the presence/absence of the keyword,VAR
- All the parameter identifiers in a formal list must be distinct.
- Examples:
- PROCEDURE NewLine;
- PROCEDURE PrintNumber ( N: INTEGER; Width: SHORTCARD );
- PROCEDURE Accumulate ( VAR X: LONGREAL; Delta: LONGREAL );
- PROCEDURE HypSquare ( A,B: LONGREAL ): LONGREAL;
- PROCEDURE PrintMessage ( M: ARRAY OF CHAR );
- PROCEDURE GetChar (): CHAR;
- Bodies
- A procedure heading is combined with a body specifying the internal workings of the procedure; a FORWARD declaration is used to delay specifying the body:
- • Declaration ::= ProcHead Body Id
- • Declaration ::= ProcHead forward
- • Body ::= Del List [ begin StmtList ] end
- The identifier repeats the procedure name.
- A FORWARD declared procedure must be completed later in the same declaration list by a full procedure declaration repeating the procedure heading and supplying a body.
- The declaration list declares entities that are local to the procedure; they must have names distinct from the formal parameters.
- Formal parameters of type ARRAY OF Type, open array parameters, are considered to be local arrays indexed with CARDINALS starting from 0; the upper index bound is obtained by the HIGH function.
- Local variables come into existence when procedures are called and vanish when they return. Procedures can call themselves directly or indirectly, causing several incarnations of local variables to be in existence simultaneously. Designating any local variable refers to the instance in the most recent active invocation of that procedure.
- A formal value parameter is considered an ordinary local variable whose value is initialized when the procedure is called. Formal VAR parameters denote actual objects, which are identified by the caller when the procedure is called.
- Open arrays can be used as actual parameters to other open array formal parameters; otherwise they can only be manipulated element-wise.
- The statement list specifies the actions of the procedure.
- Executing a RETURN statement is the only legal way of leaving & function. A proper procedure can also return by just reaching the end of the statement list.
- • Stmt ::= return [ Expr ]
- The expression must be present for functions exclusively, and the expression’s type must be assignment compatible with the return type; it is the value returned to die caller.
- Examples:
- PROCEDURE Max ( X,Y: LONGREAL): LONGREAL; BEGIN IF X > Y THEN RETURN X;
- ELSE
- RETURN Y;
- END;
- END Max;
- PROCEDURE HypSquare ( A,B: LONGREAL ): LONGREAL; FORWARD;
- PROCEDURE Accumulate ( VAR X: LONGREAL; Y: LONGREAL );
- VAR Z: LONGREAL;
- BEGIN
- Z := HypSquare( Y , 10.0-Y );
- X := X + Max(Z * Z , -999.99);
- END Accumulate;
- PROCEDURE HypSquare ( A,B: LONGREAL ): LONGREAL;
- BEGIN
- RETURN A*A + B*B;
- END HypSquare;
- Calling Procedures
- Proper procedures are invoked in call statements:
- • Stmt ::= Designator [ ActualLIst ]
- • ActualLIst ::= ’(’ [ ExPr { Expr } ] ')’
- The actual parameter list must supply one value or designator for each corresponding formal parameter. For a VAR parameter the expression must be a designator of an object with type identical to the formal type; for value parameters any expression of assignment compatible type is valid. String literals are valid parameters for any value parameter of type ARRAY ... OF CHAR.
- A formal type ARRAY OF Type is considered identical to any array type with that element type; the index range of the actual parameter is mapped onto the CARDINALS starting from 0. An expression of the element type is also valid (and is treated as an array with one element).
- The formal types BYTE, WORD and LONGWORD are compatible with any type of identical size. The formal types ARRAY OF BYTE, ARRAY OF WORD and ARRAY OF LONGWORD are compatible with anything, allowing the procedure to treat the actual parameter as unstructured storage.
- Examples:
- NewLine;
- PrintMessage("Don't panic");
- Accumulate( X , 7.0 * Y );
- Functions are invoked in expressions:
- • Value ::= Designator ActualLIst
- The parameter rules are as for proper procedures.
- Examples:
- X := HypSquare( 10.0 , Y );
- C :“ GetChar ();
- Some procedures can alternatively be called using infix notation:
- • Infix ::= \ ’ Designator ‘\ ’
- The designated procedure must take two parameters.
- Functions are applied like operators of the lowest possible expression precedence:
- • Expr’ ::= Expr { Infix Expr }
- Proper procedures are called similarly to assignment statements:
- • Stmt ::= Expr Infix Expr’
- Examples:
- X \Accuraulate\ 1.0 + (5.0 \HypSquare\ Y-1.0); (* infix *)
- Accumulate( X , 1.0 + HypSquare( 5.0 , Y-1.0 ) ); (* same *)
- Procedure Types
- A procedure type denotes a family of procedures with identical calling characteristics:
- • TypeDef ::=
- procedure I'(’ [ FormalTypeLlst ] ')’ [Name ]]
- • FormalTypeLlst ::=
- [ var ] FormalType { [ var ] FormalType }
- The procedures belonging to the type are those with matching procedure headings: each parameter must be of identical type for VAR parameters, and of identical or assignment compatible type for value parameters; return types must be identical for functions. Predefined procedures and procedures nested within other procedures are excluded.
- Example:
- TYPE PutProc = PROCEDURE ( ARRAY OF CHAR );
- VAR G: ARRAY BOOLEAN OF PROCEDURE () : CHAR;
- P: PutProc;
- There is one predefined procedure type:
- TYPE PROC = PROCEDURE; (* Procedures without parameters *)
- One predefined procedure value, NULLPROC, is compatible with any procedure type. Calling it causes a run-time error.
- Procedure values are denoted by designators without parameter lists.
- Examples:
- P :■ PrintMessage; (* P now denotes PrintMessage *)
- P("Hi, there"); (* Call it *)
- G[TRUE] :■= GetChar; (* G[TRUE] now denotes GetChar *)
- C := G[TRUE] (); (* Call it *)
- Predefined Procedures
- Modula-2 contains a number of predefined procedures. Some are generic in the sense that they are valid for several parameter types and can take one or two parameters.
- Predefined Function Procedures The predefined function procedures are:
- ABS ( X ) ADR( X ) CAP ( C ) CHR( X ) FLOAT( C ) HIGH ( A ) MAX ( T ) MIN( T ) ODD( X ) ORD ( X ) SIZE( T ) TRUNC( R ) VAL( T,X ) VSIZE( R.F )
- Absolute value of numeric operands.
- The physical ADDRESS of object X.
- Character C, changing *a’..‘z’ to *A’..‘Z’.
- The CHAR with ordinal value X.
- REAL value of CARDINAL C.
- The upper index bound of open array A.
- Maximum value of ordinal/real type T.
- Minimum value of ordinal/real type T.
- TRUE if ordinal value X is not even.
- CARDINAL, short ordinal value of X.
- Size in bytes of type or object T.
- CARDINAL, truncated value of real R.
- The value X converted to type T.
- Size of record type R if it contained just the fields up to and including field F. See the following example:
- Example: To illustrate how VS I ZE works, consider the following RECORD
- definition:
- TYPE VSTest = RECORD
- A : CARDINAL;
- B : INTEGER;
- C : CARDINAL;
- D : LONGCARD;
- END;
- With this RECORD definition, a call to VSIZE (VsTest. C) would return the size of the record including only the first three fields — A, B, and C.
- VAL can convert values between any two numeric or ordinal types.
- Any type name can be used as a type transfer function, taking one value parameter of any type. The result is that value interpreted as a value of the named type. The actual bit pattern of the value remains unchanged, except if the value type and transfer type are numeric or ordinal, when a proper VAL conversion is performed.
- A type transfer is considered well-behaved if the sizes of the value type and the transfer type are equal, or a proper VAL conversion is performed. Such type transfers can be used freely in expressions.
- If the value type size is larger than the transfer type size, the remaining last bytes of the value are ignored. If it is shorter, the last bytes of the resulting value are undefined.
- Such type transfers should only be used to circumvent the type requirements of assignment and parameter passing.
- Examples:
- I := CARDINAL( BITSET(I) L :« LONGCARD( SegOfz ); SegOfz := AdrPair( L );
- P :« ADDRESS ( L ) ;
- * BITSET(J) ); (* bitwise AND *) (* record -> cardinal *) (* cardinal -> record *)
- (* Not address of L!!! *)
- Predefined Proper Procedures The predefined proper procedures are:
- DEC( X ) DISPOSE! X )
- DEC( X,N ) EXCL( S,E ) HALT INC( X ) INC( X,N ) INCL( S,E ) NEW ( X)
- Decrement ordinal object X.
- When the compiler encounters the DISPOSE procedure, This is replaced by a call to DEALLOCATE ( X, SIZE(XA)). Decrement ordinal object X by amount N.
- Exclude element E from set object S.
- Terminate program execution successfully.
- Increment ordinal object X.
- Increment ordinal object X with amount N.
- Include element E in set object S.
- This is replaced by a call to ALLOCATE ( X, SIZE(XA)) when the compiler encounters the NEW procedure.
- Modules
- Modules encapsulate related declarations. An executing program consists of a main module and a number of server modules. The server modules are partitioned into a definition part, which is visible to clients, and an implementation part, which hides the internal details from clients.
- Modules provide a general facility for implementing features not supported explicitly within the language. Such features include: input and output, string handling, storage management, concurrency, operating system access, etc. (see Chapter 8).
- Modules are the basic units of compilation:
- • Compilation ::= Def Module
- • Compilation ::= [ implementation ] Module
- • Module ::=
- module Id [ Priority ] {Import} [ Export ] Body Id
- • DefModule ::=
- DEFINITION MODULE Id { Import } DcILIStEND Id
- • Priority ::= ‘[’ Expr “]’
- Each identifier names the module defined.
- Modules optionally have a CARDINAL priority used with the SYSTEM module (see
- Chapter 8).
- A compilation module without IMPLEMENTATION is a main module.
- Server Modules
- The definition part of a module declares the entities available to clients. Only CONST, TYPE and VAR declarations are legal, in addition to the following two, which are legal only in definition parts:
- • Declaration ::= ProcHead
- • Declaration ::= type { Id [ ‘=’ TypeDef ] }
- The first form declares the existence of a procedure. The second form, when the type definition is omitted, declares the existence of an opaque pointer type with unknown designated type; the only allowed operations on objects of opaque type are assignment and test for equality. Corresponding full declarations for objects of the opaque type must appear in the implementation part of the module.
- Objects declared in compilation modules are called global and exist throughout the execution of the program (as opposed to variables local to procedures).
- Example:
- DEFINITION MODULE Str; (* A bit of string handling *)
- CONST MaxWidth = 20;
- TYPE Buffer = ARRAY [1..MaxWidth] OF CHAR;
- VAR Width: [1..MaxWidth];
- PROCEDURE Put ( C: CARDINAL ): Buffer;
- PROCEDURE SetFill( C: CHAR );
- END Str.
- The implementation part contains declarations private to the module. These declarations are not accessible to client modules. The optional list of statements, initialization code, is executed before any statements of clients are executed. If this is impossible to satisfy because of circularity, the initialization order is undefined within the circle. The TopSpeed Modula-2 TechKit contains a program for determining the module dependencies in a program, and for detecting circular dependencies.
- The declarations in the implementation part form a single scope together with those in the definition part. Consequently every name from the definition part is visible, and additional names declared must be distinct from those. Reimporting identifiers is allowed.
- Example:
- IMPLEMENTATION MODULE Str;
- VAR FillChar: CHAR;
- PROCEDURE Put ( C: CARDINAL ): Buffer;
- VAR P: [0..MaxWidth];
- S: Buffer;
- BEGIN
- P := Width;
- REPEAT
- S[P] := CHR( ORD('O') + C MOD 10 );
- C := C DIV 10;
- DEC( P );
- UNTIL (C = 0) OR (P = 0);
- WHILE P > 0 DO
- S[P] := FillChar;
- DEC( P );
- END;
- RETURN S;
- END Put;
- PROCEDURE SetFill ( C: CHAR );
- BEGIN
- FillChar := C;
- END SetFill;
- BEGIN
- FillChar := ' ';
- END Str.
- Importing
- Clients gain access to a server module by importing from it:
- • Import ::= [ from Id ] import IdLlst
- The FROM form takes one module and a list of identifiers naming entities in it. Those names are considered declarations of those identifiers and thus achieve direct visibility of the named entities. Importing an enumeration type also imports the enumeration literals.
- The FROM-less form imports each of the modules named. Qualified names are used to denote the entities in those modules:
- • Name ::= Name Id
- The name denotes a module; the second component — the Id — an entity therein. The same qualified notation can be used to name a module’s own entities, but only within the implementation part.
- Example:
- FROM Str IMPORT Put,Width;
- IMPORT Str;
- VAR S: Str.Buffer;
- Str.SetFill(' ');
- Width := Str.MaxWidth DIV 2;
- S := Put( 1+7 );
- Local Modules
- In addition to their use as compilation units, local modules can be declared;
- • Declaration ::= Module
- Local modules obey special scope rules. Any required entity (except the predefined ones) from outside the local module must be imported, and must be visible immediately outside the local module. Thus FROM-less import can name any entity (not only server modules). Using the FROM form requires the named server module to be visible (and thus already imported) immediately outside the local module.
- Exportation is valid only in local modules:
- • Export ::= export [ QUALIFIED ] IdLlst
- The listed identifiers are declared in the enclosing scope to make those entities directly available.
- Qualification can be used to access any entity.
- If the export list contains QUALIFIED, then the export statement has no effect.
- The optional statement lists of local modules are executed (in the sequence they appear) before the statement list of the enclosing body.
- This concludes the TopSpeed Modula-2 language definition.
- Sources for Language Examples
- K. N. King’s TopSpeed Modula-2 Language Tutorial, included with your TopSpeed Modula-2 package, contains a more detailed discussion of the language, as well as numerous examples. The discussion of library procedures in Chapter 8 provides additional exposure to the language’s constructs and how to use them. The case studies in Chapter 4 also show examples of how certain Modula-2 types and constructs
- are used. You can refer to the source code for the library modules to see how various Modula-2 constructs are used, and also to see how modules are constructed.
- In Chapter 7, you will find out about options you can use to check that your program conforms to the run-time semantics of the language.
- Chapter 7
- The Compiler
- The TopSpeed Modula-2 compiler has a one-pass architecture, meaning that it outputs the generated code simultaneously with reading the source text; no temporary files are used.
- Importing is handled by (re)compiling module definition files (DEF-files) whenever required. This eliminates the need for special ‘symbol-table’ files, and means that module definitions need not be compiled explicitly; it also means that such definitions affect subsequent compilations as soon as they are modified. This strategy also eliminates the compilation-order restrictions that usually apply to module definitions; module implementations can be compiled in any order.
- The output from the compiler is a relocatable object file (OB J-file) in Intel/Microsoft format. A collection of such files is combined into one executable file (EXE-file) by a linker.
- The OBJ-file
- The OBJ-file created by the compiler contains special information that makes linking easier, checks consistency, and minimizes EXE-file size.
- Include-records are inserted into the OBJ-files. These records tell the linker the names of the files used by the module. This means that only the name of the main module needs be supplied when linking. The linker will find the remaining files through the include-records.
- Version-records are also inserted. These record the date and time of the DEF-files used. The linker will check that all modules agree on these versions. If they don’t, there is the possibility of a fatal inconsistency which should be eliminated by recompiling (see the Make option in “Making a Program,” page 69).
- The OBJ-file is built as a library, meaning that the module is split into sections which are only included by the linker if they are used. This eliminates the overhead for large general-purpose library modules. Thus, your EXE-file is as small as possible. In the OBJ-file, each global procedure is in a section by itself, and so are groups of data-declarations belonging to the same VAR or CONST part.
- Data Representation
- The basic storage unit is an 8-bit byte. Any Modula-2 object is represented in a number of bytes determined by the object’s type. Subrange types are represented as their base types.
- Taking the ADDRESS of an object yields the address of the first byte of its storage. For multi-byte numeric types, the least significant byte of the object is stored at the lowest address.
- Cardinal types are represented as unsigned binary numbers, and have the following storage requirements:
- SHORTCARD: 1 byte
- CARDINAL: 2 bytes
- LONGCARD: 4 bytes
- Integer types are represented as 2’s-complement binary numbers, and require the following storage:
- SHORTINT: 1 byte
- INTEGER: 2 bytes
- LONGINT: 4 bytes
- Real types are represented as 8087 mantissa/exponent pairs. (See the relevant 8087 documentation for your machine.) These types require the following amounts of storage.
- REAL: 4 bytes
- LONGREAL: 8 bytes
- Enumeration types are represented as unsigned binary (ordinal) numbers:
- <= 256 values: 1 byte
- > 256 values: 2 bytes
- BOOLEAN: 1 byte
- CHAR: 1 byte
- Absolute pointer types occupy 4 bytes. The first two bytes hold an offset value and the last two bytes hold a segment value. NIL is represented as (0,0). Based pointers occupy 2 bytes, which hold an offset.
- FAR procedure variables are represented as absolute pointers to the first instruction of the procedure’s code. NEAR procedure variables are represented as 16-bit offsets within the applicable code segment.
- Sets are represented as packed bit-maps with one bit for each potential member in the element type, say [ 0 . . N]. The number of bytes required to represent a set is given by 1+ (N DIV 8). For example, if you have a set which can have up to 100 elements, you need 13 bytes — that is, (1 + 100 DIV 8) —to represent this set. The set element E, where (0 <= E <= N) is represented by bit number E MOD 8 in byte number E DIV 8. The formula assumes you start counting with byte 0 and with bit 0.
- Elements of arrays are stored in consecutive memory locations, and ordered according to increasing indices. The total array size is the size of a single element multiplied by the number of elements.
- Fields of records are likewise stored in consecutive memory locations, and are ordered as they appear in the type declaration. Each field is stored according to its own type. The total record size is the sum of sizes of the individual fields. Variant record parts are special: the fields of different alternatives are overlayed (share storage). The total size of a variant part is the sum of the field sizes of the biggest alternative.
- Example:
- TYPE R = RECORD
- Fl: INTEGER; (* Bytes 0-1 *)
- CASE F2: BOOLEAN OF (* Byte 2 *)
- 1 FALSE: F3, (* Byte 3 *)
- F4, (* Byte 4 *)
- F5: CHAR; (* Byte 5 *)
- 1 TRUE: F6: CARDINAL; (* Bytes 3-4 *)
- END
- F7: SET OF [0..20]; (* Bytes 6-8 *)
- END; (* SIZE ( R ) = 9, VSIZE( R.F6 ) = 5
- This record requires nine bytes:
- • two bytes (0-1) for field Fl
- • one byte (2) for field F2
- • three bytes (3-5) for fields F3, F4, and F5 together
- • three bytes (6-8) for field F7
- Note that field F6 is subsumed by the larger storage allocated for the fields when F2 is FALSE.
- Calling Conventions
- This discussion of the calling conventions used in TopSpeed Modula-2 code files assumes familiarity with the 8086-architecture. We will refer to the registers by the following names: AX(, AL), BX, CX, DX, SI, DI, BP, SP, CS, SS, DS, ES, IP, and Flags. For most programming tasks, you won’t need to be concerned with these conventions, since the default conventions will suffice.
- The Stack Frame
- Procedure activation makes use of the hardware stack (defined by registers SS and SP) for several purposes:
- • Passing parameters.
- • Saving return addresses.
- • Saving registers which are used and must be preserved.
- • Saving 8087 contents if not enough 8087 stack space is left for local floating point computations.
- • Building ‘displays’ for accessing variables local to surrounding procedures.
- • Storing local variables (whether user or compiler generated).
- • Storing copies of value open array parameters, so they can be modified without modifying the actual parameters.
- • Saving the process priority of the caller.
- The parameters are pushed onto the stack by the calling procedure; the rest of the information on the stack is built by the called procedure on entry. The BP register points to the base of the stack-frame, and is used to access the local variables and parameters.
- The general picture is:
- old SP -*• Higher addresses
- parameters Actual parameters
- retum-CS retum-IP Return segment for FAR
- Return offset
- new BP —>
- new SP —> saved BP display-BPs local variables local temps saved registers value-copies priority saved 8087 Caller’s BP
- BPs of enclosing procedures Local user variables
- Local anonymous variables
- Caller’s registers
- Copies of array parameters Saved (process) priority Caller’s 8087-contents
- Lower addresses
- Only the parts required are actually built; for very simple procedures, saving BP will be sufficient.
- When returning, a procedure will restore the stack and preserved registers (see the $C directive) to their state before the call. This restoration includes popping the space used by the parameters.
- Parameter Passing
- Parameters are pushed onto the stack in the order they appear in the procedure declaration. Precisely what is pushed depends on the corresponding formal parameter’s type and whether it is a VAR parameter or not.
- All VAR parameters and any open array parameters are passed by reference. That is, the full segment-offset address for the parameter or array is pushed, and the procedure uses this address to access the storage for the actual parameter. Such a parameter takes up 4 bytes, regardless of the parameter’s base type.
- Value parameters, except open arrays, are passed by pushing the actual value of the parameter onto the stack. The space taken up is determined by the parameter’s type, except that any 1-byte type occupies 2 bytes when pushed.
- For open array value parameters, the procedure will optionally make a copy of the passed value into local storage, and will modify the address passed to point at the copy rather than at the original array. (See the $V- directive in “Directives (in source text)” page 133.)
- For open array parameters (whether VAR or not), the caller also will push the (2-byte) size (in bytes) of the actual array. This information will be pushed before the address of the array.
- Function Results
- Results from functions are returned in various ways, depending on the type of the value being returned.
- REALS and LONGREALs are returned on the top of the 8087 stack.
- Scalar values, small sets, pointers, and procedure variables are returned in 8086 registers according to their size: 1 byte in AL, 2 bytes in AX, and 4 bytes in DX:AX.
- Sets of other sizes, arrays, and records are returned on the stack under the parameters: before pushing parameters, the caller will allocate the required space.
- Options (on Command Line)
- When invoking the compiler, you can use options to specify what you want from the compiler. You can invoke any of these options on the DOS command line; you can also specify some of them from menus when compiling in the TopSpeed Modula-2 environment. To specify an option from the appropriate menu, select the Options Compiler menu, then set entries to the desired values. See Chapter 5 for more details about the TopSpeed Modula-2 options.
- When you invoke the options from the command line, you must precede the name of the file you want to compile with /C, to tell the system that you want to invoke the compiler on the file that follows as the next command line argument. (Command line options are not case sensitive. Thus, /C and /c are equivalent.)
- Example:
- M2 /C MyMain /ML
- The compiler options are:
- /B This option lets you specify whether compiler directives that do checking at run-time are ON or OFF. This option affects only the default settings for these options. You can override these settings with directives in the source code, as described in the next section.
- /D If selected, the compiler generates a debug information file for the module being compiled. This file is required by the TopSpeed Modula-2 source level debugger.
- /F Allows file names to be different from module names.
- /H Used together with Make (see the /M option below) to show which files need recompilation.
- /J Suppresses smart linking — that is, the automatic generation of libraries. When this directive is used, non-library OB J-files are created, meaning that everything in the file will always be included when linking. Although this results in larger, slower files, this file format is necessary for some linkers.
- /L Generates a screen log containing information about compilation speed for definition and for implementation modules.
- /M Invokes the Make utility. The file specified to the compiler must contain a mam module. Make will, based on the imports specified in that file, find all modules required by the program. For each of these, Make checks whether the corresponding OBJ-file is up-to-date, based on the time/date values of the files used. Modules that need it are recompiled. Only files whose module implementation is accessible are considered. See “Making a Program,” page 69, for more information about Make.
- /N Include line numbers in the OBJ-file. This enables a program such as a debugger to determine the correspondence between code addresses and source program lines.
- /O Where possible, the compiler will try to produce the fastest code it can. To do this, the compiler will sometimes reorganize expressions, in order to speed up their evaluation. The /O option disables reorganization of expressions. This ensures that expressions are evaluated left-to-right, but results in suboptimal code.
- /P Tells the compiler to display the name of each procedure as it is compiled, to indicate progress.
- /R Used together with Make to recompile everything, regardless of checks. This option may be necessary because the Make facility only considers the actual time/dates values of files; it does not read OBJ-files to find the version-records.
- /V Makes all variables volatile: instead of trying to keep variables in registers, they are kept in memory. This can help when debugging. This option results in slower code than if registers are used.
- Directives (in Source Text)
- Directives, which appear in the source text, are used to specify various details about how code should be generated. Directives are specified in special comments, whose first character is $ after the comment opening characters, (*. Each directive is indicated with a single letter, optionally followed by a parameter; several directives can be given in a single comment by separating them with commas.
- Most of the directives are flags. In such cases, the parameter is a + or - to indicate whether to enable the feature or not. The flags can be reset to their value before the most recent use of the directive by specifying the flag with = as the parameter.
- Example:
- (*$V-,M mycode,N*) (* set $V feature to regardless of current value *) .... (* code here *)
- (*$V=,F*) (* restore $V feature to value it had before $V- *)
- Other directives require a number or a name as their parameters — for example,
- M ntycode
- above. (Notice that the $ appears only once in the comment line.) Finally, a few directives are set simply by including the directive, without a parameter.
- Directives take effect from the spot in which they first occur, and remain in effect until the end of the source file or until revoked by another directive. The current setting for a directive is sampled at the place where its value is relevant.
- If certain directives are specified in a module definition, their settings override any settings in the module implementation. These directives are: C,G,F,K,N.
- The following list summarizes the compiler directives that are available in TopSpeed Modula-2. Where applicable, default values are specified in boldface.
- $A+/- Enable/disable aliased behavior on global variables. The compiler will assume that variables declared with the directive disabled cannot be accessed directly and indirectly at the same time.
- $B+/~ Include/exclude a control-break handler in the program. If included, pressing |ctrl|||Breakj] will terminate the program. The handler can be dynamically enabled and disabled with library procedures. The directive must be in the main module.
- $C h Specifies which registers will be preserved by procedures. The hexadecimal number, h, specifies the registers, based on the following values:
- AX=1, CX=2, DX=4, BX=8, DS=10, ES=20, SI=40, DI=80.
- The BP register is always preserved. The default configuration is
- $D n
- $E+/-
- $F
- $G+/~
- $H+/-
- $1+/-
- $J+/-
- $K+/-
- $M n
- $N
- $O+/-
- FO = DS+ES+SI+DI
- This would be specified as:
- (*$C FO*)
- Specifies the name, n, of the data segment in which to put the global variables declared by the module. The default is to use the module name. In any case, the name specified is prefixed by D_. If used, this directive must appear before the MODULE keyword in both definition and implementation files.
- Enable/disable relaxed alias treatment of variant records. Because of overlapping, the compiler will normally consider fields of variant records volatile, causing them to be kept in memory.
- Procedures will be called with FAR calls. Likewise, procedure types are 32-bit. This is the default, and applies only to global procedures; local procedures are always called with NEAR calls.
- Enable/disable module prefixes in external names. Enabling such prefixes guarantees that external names will be unique.
- Enable/disable treating constant aggregates as variables, thereby allowing them to be modified. This is possible because the values are in memory anyway.
- Enable/disable index checking. If enabled, accessing a non-existent array element will produce a run-time error. All variables are assumed to hold legal values corresponding to their type (see $R below). Likewise, type transfer on indices is assumed not to cause problems.
- Enable/disable interrupt procedures, by generating IRET returns instead of the usual RET instruction.
- Enable/disable the C language calling convention for procedures. This specifies that caller (not called) pops parameters. Across calls, the DS register is set to the group named ‘DGROUP.’
- Specifies the name, n, of the code segment in which to put code. The default is to use the module name. In any case, the name is prefixed by C_. When used, this directive must appear before the MODULE keyword in both definition and implementation files.
- When this directive is used, procedures will be called with NEAR calls. This requires callers to be in the same code segment. With this directive, procedure types are 16-bit.
- Enable/disable overflow checking on whole number operations. If this directive is enabled, a numeric overflow will cause a run-time error.
- $P+/~ Enable/disable generating external names for local procedures. Enabling eases debugging but can cause name clashes.
- $Q+/- Enable/disable procedure tracing. If enabled, procedures will execute an INT 60H instruction on entry and and INI 61H on exit. Handlers for these interrupts must be installed explicitly (see “Interrupt Handlers,” page 140). Library module ProcTrace enables you to do this.
- $R+/- Enable/disable subrange checking. If enabled, a run-time error is generated by assignment or parameter passing if the value is outside the bounds of the receiver’s type.
- $S h The hex number, h, specifies the amount of stack allocated for the program. If used, this directive must be in the main module.
- $S+/- Enable/disable stack overflow checking. If this directive is enabled, a run-time error is generated if stack space is exhausted.
- $V+/~ Enable/disable copying of open array value parameters. Disabling such copying increases efficiency but is potentially incorrect.
- $W+/- Enable/disable the use of volatile variables. Volatile variables are not kept in registers across statements. The ability to use volatile variables can be essential if concurrent processes communicate via shared global variables, and can make debugging easier. The /V command line option selects this globally.
- $X+/~ Enable/disable 8087 stack spilling for procedures. Spilling is necessary if nested function calls exhaust the 8087 stack. Spilling involves saving excess values from floating point computations on the hardware stack — because there is no longer room on the 8087 stack.
- $Y+/- Enable/disable coinciding variant fields in a record. If enabled, it is legal to use the same name for fields in distinct alternatives, provided that these fields have the same type and are at the same offset in the record.
- $Z+/- Enable/disable checks for dereferencing of NIL pointers, which then generate a run-time error. When the feature is enabled, all local variables are initialized to zero. If the feature is enabled in the main module, all global variables are also zeroed.
- Interface to Other Languages
- Since the compiler generates standard OB J-files, it is possible to link these files with code written in other languages and compiled with other compilers.
- However, anything called from Modula-2 must be declared in Modula-2 terms. This means that module definitions (DEF-files) must be written, even for the parts that are not implemented in Modula-2. The actual OBJ-file may be generated by a different compiler.
- For this to work, the different parts of the program must agree on the run-time structure of the total program. So, you’ll need to understand the run-time structure of both Modula-2 and the other languages being used.
- Inspecting the MAP-file produced by the linker can be a big help when fitting the pieces together. This file is also useful simply as a source to help understand how running programs are put together. The documentation for the TopSpeed Modula-2 TechKit provides information about this, and also includes an example of how to create and use a module written in assembler.
- Controlling Run-Time Program Structure
- You can control the Modula-2 run-time structure by using several of the directives summarized in the preceding section:
- $D selects the segment where data goes.
- $M selects the segment where code goes.
- $G disables module name prefixing.
- $N produces NEAR procedures.
- $F produces FAR procedures.
- $C selects which registers are preserved by procedures.
- $K follows C calling conventions.
- Segments, Groups and Classes
- The concept of a segment is fundamental to the 8086, and it is extended by the concepts of group and class in the OBJ-language.
- An item is the fundamental, undivisible piece of code or data, and is sometimes called a “logical segment.”
- A segment is a collection of items whose total size is less than 64K bytes; a segment has a name. Any item belongs to one segment.
- A group is a collection of segments, whose total size is still less than 64K bytes; a group also has a name. Any segment belongs to at most one group, but need not belong to any.
- When linking a set of OBJ-files, all the items must be arranged in physical memory in a way that ensures that items of the same segment or group are within the same 64K of memory.
- Segments may be qualified with the concept of named classes. These are used to specify preference when arranging the items: items with the same class name are placed adjacent to each other; within classes, items of the same segment are placed adjacent to each other. Classes take precedence, so if two items have the same segment name but different class names, they are not even considered to belong to the same 64K segment.
- The linker will order classes in the sequence it encounters them when linking. The compiler utilizes this to achieve the correct storage layout of the final program: first comes code (classes CODE, FCODE), then global data (MJDATA), then stack data (STACK), and finally heap data (HEAP).
- For each module, the compiler will generate four segments and one group with names derived from the module name. The segments are:
- C_module contains code for procedures.
- K_module contains structured constants (like strings).
- S_module contains special segment constants.
- D_module contains global variables.
- and the group is:
- G_module group containing the C_, K_, and S_ segments.
- Segments can be renamed with compiler directives: $D applies to the D_ segment, $M to the C_, K_ and S_ segments and the G_ group. This control can be used to make different modules use the same segments: for example, using the compiler directive (*$D DATA*) in all modules will put all global data in the same 64K segment.
- A further segment, INITCODE, contains initialization code for modules and the code for the main module. If (*$M CODE*) is specified, segments INITCODE and C_CODE are put in a group called G_CODE, enabling all code to reside within the same 64K group.
- Because there is a single data segment and code group for each module, the code and global data are limited to 64K bytes for each module. A complete program can have an arbitrary amount of code and data.
- Addressing Items
- A physical address consists of two parts: a segment address and an offset. All items in the same group or segment have the same segment address but different offsets.
- To address an item, a segment register must contain its segment address. This (implicit) register is combined with an explicit offset value to address the item. FAR calls, on the other hand, specify both the segment address and the offset explicitly.
- Thus, distinct objects can be accessed without reloading a segment register only if they belong to the same segment or group. Similarly, a procedure can only be called with a NEAR call if the caller is within the same (code) segment (so the CS register does not have to be changed).
- Note: Whether a procedure is considered NEAR or FAR ($N and $F directives, respectively) is determined by the procedure’s RETum instruction. The determination has nothing to do with the segment the procedure is in or with what else is in that segment.
- Naming Conventions
- The various OBJ-files refer to each other’s items by means of public external names. These names must be unique and distinct.
- The compiler forms the external name of an item by prefixing its source code name with the name of the module in which the item is declared. A $ or @ separates these two names: $ is used for FAR procedures, and @ is used for NEAR procedures and for data. Such prefixing can be disabled with the $G directive.
- Items declared in local modules immediately within global modules are prefixed with the names of both the global and local modules separated by @.
- Example:
- (*$D XYZ*)
- DEFINITION MODULE M;
- V: INTEGER;
- PROCEDURE F; (* (* (* Segments C_M, External name External name K M, M@V M$F S M, D XYZ *)
- *)
- *)
- (segment (segment D M) C_M)
- (*$N,G-*) PROCEDURE Nl; (* External name Nl (segment C _M) *)
- (*$G+*)
- PROCEDURE N2; (* External name M0N2 (segment C_ _M) *)
- END M.
- 8087 Support
- The compiler generates 8087 instructions for floating point operations. At run-time these instructions either will be executed by an actual 80x87 chip or they will be emulated by software.
- The emulator is included if any part of the program uses floating point instructions. At run-time the emulator will check if an 80x87 chip is present. If so, the emulator will patch the emulator calls back to 8087 instructions. The same EXE-file can thus be run on any machine at maximum possible speed.
- Normally 80x87 exceptions are suppressed. However, you can install exception handlers by just importing the FloatExc module (see Chapter 8).
- Interrupt Handlers
- It is possible to write interrupt handlers in Modula-2, though it should not be attempted without a thorough understanding of the 8086 and of MS-DOS.
- An interrupt handler is written as a Modula-2 procedure; the $ J+ directive gives it a proper return instruction, and the $C FF directive makes it save all registers. The $w+ directive can be used to keep shared global variables in memory.
- Hardware interrupts can be enabled or disabled with the El and DI procedures from the SYSTEM module (see Chapter 8).
- The interrupt handler is installed by assigning its address to one of the interrupt vectors in low memory. For more details on interrupt vectors, consult references on DOS or on the 80x86 chip.
- Example:
- MODULE Int ;
- VAR Prtlnt [0:5*4]: ADDRESS; (* Interrupt 5: print-screen *) Oldlnt: ADDRESS;
- (*$W+*)
- Flag: BOOLEAN;
- (*$W-*)
- (*$J+,C FF*)
- PROCEDURE Handler ;
- BEGIN
- END Handler;
- (*$J-,C F0*)
- BEGIN
- Oldlnt := Prtlnt;
- Prtlnt := ADR( Handler );
- Prtlnt := Oldlnt;
- END Int.
- If you’re very adventurous, the TechKit contains a module you can use to create terminate-and-stay-resident (TSR) programs, using the 031H MS-DOS call. A sample TSR program is also included. When creating such a program. Break handling must be disabled (by setting $B-), and the stack can be kept small. Use the $S directive to do this — for example:
- $s 500
- Finally, the heap requirements of the EXE-file must be trimmed using the supplied SETHEAPS utility, which is included in the TechKit; otherwise there will be no space left for other programs.
- Chapter 8
- The TopSpeed
- Modula-2 Library
- Introduction
- This chapter describes the library modules supplied with the TopSpeed Modula-2 compiler. TopSpeed Modula-2 comes with 12 different modules, containing more than 250 procedures in all.
- Most of these modules are ordinary Modula-2 modules. They all have a Modula-2 definition part, but some of the implementation parts are written in assembler.
- The following sections of this chapter describe each module in detail, but first an overview of the modules is presented. How the modules interrelate is also described.
- The modules can be partitioned into levels of successively more abstract functions, where each level will make use of the lower levels.
- Level MODULE
- System
- Assembly
- Utility :SYSTEM
- : AsmLib, MATHLIB
- : Str, Lib, Storage, Process, Graph, FloatExc, Proc- Trace
- IO : IO, FIO
- Window : Window
- Library Overview
- SYSTEM
- The SYSTEM module is a low-level module that contains compiler dependent features, such as data types of special interest in this implementation. Some of the procedures in this module are built-in to the compiler — that is, code for these procedures will be generated inline rather than as calls to the procedures.
- SYSTEM covers:
- • support for the specifics of the 8086 family of processors
- • support for concurrent processes
- SYSTEM does not make use of other modules.
- AsmLib
- AsmLib is an auxiliary module which you need not use directly; it is there to keep all the various assembler bits in one module. Some of the procedures that appear to be defined in other modules are actually from the AsmLib module. This is achieved by means of TopSpeed Modula-2’s alias-concept (see chapter 6).
- AsmLib uses SYSTEM.
- MATHLIB
- MATHLIB is implemented in assembler.
- MATHLIB covers:
- • trigonometric and hyperbolic functions on reals
- • logarithmic functions on reals
- • conversion of reals to/from binary coded decimals
- • 8087 specifics
- MATHLIB uses SYSTEM.
- Str
- The Str module deals with string handling.
- Str covers:
- • string concatenation, appending, insertion, deletion
- • string comparison
- • string searching, matching
- • string conversion to and from numeric types
- Str uses AsmLib and MATHLIB.
- Lib
- This module contains a collection of useful procedures. Parts of it are written in Modula-2 and parts of it are aliases into the AsmLib module.
- Lib covers:
- • sorting
- • random number generation
- • DOS-interrupt calls
- • command line access
- • memory block operations
- • long jumps
- • address arithmetic
- • break and error handling
- • sound procedures
- Lib uses SYSTEM, AsmLib, Str and Storage.
- Storage
- The Storage module maintains dynamic heaps of storage.
- Storage provides:
- • allocation and deallocation of storage
- • information about storage availability
- Storage uses SYSTEM.
- Process
- This module implements a multi-process manager with time-sliced scheduling and process synchronization.
- Process covers:
- • starting up processes
- • synchronization by means of semaphores
- Process uses SYSTEM, Lib, Storage.
- Graph
- The module Graph implements simple graphics. The module supports the following graphics boards: CGA, EGA, VGA, Hercules, and AT&T.
- Graph covers:
- • selecting a graphics board
- • selecting screen modes
- • writing and reading of single pixels
- • drawing of lines and circles
- • drawing of filled circles and polygons
- Graph uses SYSTEM, Lib.
- FIO
- This module allows access to MS-DOS files. Input/output to files can either be unformatted binary data, or formatted data to text files. Files are usually disk-files, but can be any device that MS-DOS allows.
- FIO covers:
- • creating, deleting, renaming, opening, closing files
- • reading, writing, seeking on files
- • creating, deleting, changing directory
- • directory scanning
- • reading and writing of characters, booleans, integers, cardinals, reals, strings
- FIO uses SYSTEM, AsmLib, Lib, Str.
- IO
- The IO module provides formatted input/output to the standard I/O devices (i.e. screen and keyboard). Input and output can be redirected. IO also contains functions for direct keyboard input.
- IO covers:
- • reading and writing of characters, booleans, integers, cardinals, reals, strings
- • redirection to any device
- • reading characters directly from keyboard
- • testing for key-ready
- IO uses SYSTEM, Lib, Str, FIO.
- Window
- The Window module allows you to define areas of the screen for output. These areas are called windows, and may be displayed simultaneously, possibly overlapping, on the physical screen.
- Window covers:
- • creating, disposing, opening, closing windows
- • setting frame, color, title on windows
- • rearranging the size, position, layering of windows
- • cursor control inside windows
- • inserting and deleting lines in windows
- • palette windows
- • writing to windows using the IO module
- Window uses SYSTEM, AsmLib, Lib, Str, Storage.
- FloatExc
- The module FloatExc supports 8087 exception handling.
- FloatExc covers:
- • enabling/disabling of 8087-exceptions.
- FloatExc uses SYSTEM, Lib, MATHLIB, Str.
- ProcTrace
- The ProcTrace module lets you trace procedure calls and to monitor variable values during program execution.
- ProcTrace covers:
- • monitoring procedure calls
- • determining the current procedure
- • monitoring the value of variables
- ProcTrace uses SYSETM, Lib, IO, FIO, Str.
- This concludes the general introduction to the library. More specific descriptions are given in the following sections.
- How to Use the Library Reference
- Rather than describing the procedures in alphabetical order, a description of the individual procedures can be found under the module where they belong. A list of all the procedures can be found on page 246.
- When you read a description of a particular procedure, you should also read the general remarks in the section to which the procedure belongs.
- MODULE Str
- This section deals with the string handling functions, which include string manipulation, as well as conversions from strings to numbers and vice versa.
- The Modula-2 language does not have a built-in string type. Strings are implemented as the type ARRAY [0. .N] OF CHAR. When a string literal is assigned to such an array type, it will be zero-terminated by appending the character value CHR(OC) to the string. However, this is not the case if the length of the string literal is equal to the maximum length of the destination string.
- All procedures that return a string (via a VAR parameter) will zero-terminate that string unless the length of the result string is greater than or equal to the length of the destination string. If the length of the result string is greater than the length of the destination string, the result string is truncated.
- Positions in the string are indexed starting with 0. Thus, the second character in the string has position 1.
- General String Procedures
- Append
- PROCEDURE Append(VAR R: ARRAY OF CHAR; S: ARRAY OF CHAR);
- Appends the string S to R. If the combined length of S and R is longer than the maximum length of S, only as much of R is appended as will fit in S.
- Example:
- (* si, s2 are strings *)
- si := 'ex';
- s2 := 'ample';
- Append( si, s2); (* Bl now = 'example' *)
- Caps
- PROCEDURE Caps (VAR S: ARRAY OF CHAR) ;
- Converts lower case letters in string S to upper case letters. Other letters are left unchanged.
- Example:
- s := 'example';
- Caps( s); (* s now = 'EXAMPLE' *)
- Compare
- PROCEDURE Compare(SI,S2: ARRAY OF CHAR) : INTEGER;
- Compares the strings SI and S2 lexicographically. The function compares characters from left to right until a (possible) difference is found. The result is indicated the following way:
- Value Condition
- -1 if SI is less than S2.
- 0 if SI equals S2 — that is, no differencs was found.
- 1 if SI is greater than S2.
- Example:
- result Compare( 'lowercase', 'uppercase');
- (* result = -1, since 'lowercase' precedes 'uppercase' *)
- result := Compare( 'lowercase', 'Lowercase');
- (* result = 1, since '1' comes later than 'L' lexicographically *)
- Concat
- PROCEDURE Concat(VAR R: ARRAY OF CHAR; S1,S2: ARRAY OF CHAR);
- Concatenates SI and S2, and returns the result in R. The second string is truncated if the concatenated string becomes longer than the Length ( R).
- Example:
- (* strl, str2, catstr are strings *)
- strl := 'ex';
- str2 := 'ample';
- Concat( catstr, str2, strl); (* catstr now = 'ampleex' *)
- Copy
- PROCEDURE Copy (VAR R: ARRAY OF CHAR ; S: ARRAY OF CHAR);
- Copies the string S to R. If S is too long to fit into R, then the copy of S is truncated.
- Example:
- strl := 'example';
- str2 := 'ample';
- (* strl now = 'ample' *)
- Copy( strl, str2) ;
- Length
- PROCEDURE Length(S: ARRAY OF CHAR) : CARDINAL;
- Returns the length of the string S, not including the zero-terminator if present.
- Example:
- result := Length('hello');
- (* result now = 5 *)
- Pos
- PROCEDURE Pos(S,P: ARRAY OF CHAR) : CARDINAL;
- Returns the position (starting from 0) of the first occurrence of the substring P in the string S. If P is not found in S the result is MAX(CARDINAL).
- Example:
- result :■ Pos( 'example', 'ample'); (* result = 2 *)
- result :■ Pos( 'source string', 'not in source—'); (* result = 65535 *)
- Slice
- PROCEDURE Slice (VAR R : ARRAY OF CHAR; S : ARRAY OF CHAR; P,L : CARDINAL);
- R is assigned a slice of string S. This slice goes from position P to P+L-l. If P+L-l is greater than Length (S), R is assigned the slice from P to Length (S). If P is greater than Length (S) or L is 0, then R becomes a null string (i.e. a string of length 0).
- Example:
- Slice(si, 'overused', 4, 2);
- (* si = 'us' *)
- (* si = 'used' *)
- (* si = null string *)
- Slice(si, 'overused', 4, 12);
- Slice(si, 'overused', 12, 4);
- Item
- PROCEDURE Item(VAR R : ARRAY OF CHAR; S : ARRAY OF CHAR; T : CHARSET; N : CARDINAL);
- Consider the string S divided into (nonempty) substrings which are separated by elements from the set T. Item returns the Nth of these substrings (counting from 0). The result goes in R.
- Example : The following call of Item
- si : = "aa bb,cc dd"; Item(s2, si, CHARSET{' 2) ;
- will assign “cc” to s2.
- ItemS
- PROCEDURE ItemS (VAR R : ARRAY OF CHAR;
- S : ARRAY OF CHAR; T : ARRAY OF CHAR; N : CARDINAL);
- This procedure works like Item. The only difference is that in Items the delimiters, given by T, are specified as an ARRAY OF CHAR as opposed to a CHARSET in Item.
- Example:
- TYPE SmArr = ARRAY [ 0 .. 3] OF CHAR;
- CONST delims = SmArr ( CHR(IO), CHR(13), CHR(26), ' ');
- VAR Bl, s2 : ARRAY [ 0 . . 40] OF CHAR;
- si : = ”aa bb cc dd";
- ItemS( s2, si, delims, 3);
- will assign “dd” to s2.
- Insert
- PROCEDURE Insert(VAR R : ARRAY OF CHAR;
- S : ARRAY OF CHAR;
- P : CARDINAL);
- Inserts string S into string R at position P. If P is greater than Length (R), then S is inserted at position Length (R).
- Example: The following example shows how insert new material in an existing
- string:
- si := "abcdefg";
- Insert(si,"xyz",3); (* si now = "abcxyzdefg *)
- Delete
- PROCEDURE Delete(VAR R: ARRAY OF CHAR; P,L: CARDINAL);
- Deletes a sequence of L characters in the string R starting at position P. Delete has no effect if P is greater than Length (R).
- Example:
- si := "abcdefg"; Delete(si,3,3); (* Bl now = "abcg" *)
- si := "abcdefg"; Delete(si,3,7); (* Bl now = "abc" *)
- si := "abcdefg"; Delete(si,7,3); (* sl now = "abcdefg" *)
- Match
- PROCEDURE Match(Source,Pattern: ARRAY OF CHAR) : BOOLEAN;
- Returns TRUE if the string Source matches the string Pattern. The pattern may contain any number of wild characters **’ and *?’. The *?’ character matches any single character, **’ matches any sequence of characters (including a zero length sequence).
- Example:
- VAR IsAMatch : BOOLEAN;
- IsAMatch := Match( "*m?t*i*", "Automatic");
- returns TRUE.
- Conversion Procedures
- This section describes procedures to do conversions from numbers to strings and vice versa.
- A string that represents a number may start with a sign ('+’ or however is not allowed for CARDINAL numbers. No leading or trailing spaces are allowed in the string.
- A string resulting from a conversion will contain a sign only if the number is negative. The string contains no leading or trailing spaces.
- All the conversion procedures have a BOOLEAN result parameter, OK, which is set to TRUE if the conversion succeeded, or FALSE otherwise.
- Procedures that convert between strings and integer or cardinal numbers take a parameter, Base, which denotes the base (normally 10) used in the conversion. Base should have a value in the range 2 to 16. The hexadecimal letters *A’..‘F’ are used in numbers when Base is larger than 10. No H is added to hexadecimal numbers.
- IntToStr
- PROCEDURE IntToStr( V : LONGINT;
- VAR S : ARRAY OF CHAR;
- Base : CARDINAL;
- VAR OK : BOOLEAN);
- Converts the LONGINT value V into a string representation. OK is set to FALSE if the string S is too short to hold the converted value.
- Example:
- VAR si : ARRAY[ 0..20] OF CHAR;
- Done : BOOLEAN;
- IntToStr( -1234567, si, 8, Done); (* si = "-4553207" *)
- IntToStr( -1234567, si, 10, Done); (* si = "-1234567" *)
- IntToStr( -1234567, si, 16, Done); (* si = "-12D687" *)
- CardToStr
- PROCEDURE CardToStr( V : LONGCARD;
- VAR S : ARRAY OF CHAR;
- Base : CARDINAL;
- VAR OK : BOOLEAN);
- Converts the LONGCARD value V into a string representation. OK is set to FALSE if the string S is too short to hold the converted value.
- Example:
- VAR si : ARRAY[ 0..20] OF CHAR;
- Done : BOOLEAN;
- CardToStr( 1234567, si, 8, Done); (* si = "4553207" *)
- CardToStr( 1234567, si, 10, Done); (* si = "1234567" *)
- CardToStr( 1234567, si, 16, Done); (* si = "12D687" *)
- RealToStr
- PROCEDURE RealToStr (
- V : LONGREAL;
- Precision : CARDINAL;
- Eng : BOOLEAN;
- VAR S : ARRAY OF CHAR;
- VAR OK : BOOLEAN);
- Produces a string representation of the LONGREAL value V. Precision denotes the number of digits you want in the mantissa, and must lie in the range 1 to 17. (If Precision is outside this range its value will be adjusted to the nearest bound). If Eng is TRUE, engineering notation is used — that is, the exponent is displayed as
- a multiple of three. If Eng is FALSE the mantissa is displayed with one significant digit before the decimal point. OK is set to FALSE if the string S is too short to hold the representation of V.
- Examples:
- RealToStr(123.45,7,FALSE,S,b); (* S now = "1.234500E+2" *)
- RealToStr(0.12345,7,FALSE,S,b); (* S now = "1.234500E-1" *)
- RealToStr(0.12345,7,TRUE,S,b); (* S now = "123.4500E-3" *)
- FixRealToStr
- PROCEDURE FixRealToStr(
- V : LONGREAL;
- Precision : CARDINAL;
- VAR S : ARRAY OF CHAR;
- VAR OK : BOOLEAN) ;
- Produces a string representation of the LONGREAL value V. No exponent is given in this format (see RealToStr). Precision denotes the number of digits after the decimal point. OK is set to FALSE if the string S is too short to hold the representation of V, or if ABS (V) is larger than 1.0E18.
- Examples:
- FixRealToStr(0.12345,7,S,b); (* S now = "0.1234500" *)
- FixRealToStr(123.4567,5,S,b); (* S now = "123.45670" *)
- FixRealToStr(123.4567,2,S,b); (* S now = "123.46" *)
- StrToInt
- PROCEDURE StrToInt( S : ARRAY OF CHAR;
- Base : CARDINAL;
- VAR OK : BOOLEAN ) : LONGINT;
- StrToInt takes a string S representing an integer value, and returns the corresponding LONGINT representation. Base denotes the base of the number currently in string form, and must lie in the range 2 to 16. OK is set to FALSE if the string S does not represent a LONGINT value.
- Example:
- VAR FInt : LONGINT; Done : BOOLEAN;
- FInt := StrToInt( "-4553207", 8, Done); (* FInt = "-1234567" *)
- FInt :» StrToInt( "-1234567", 10, Done); (* FInt = "-1234567" *)
- FInt := StrToInt( "-12D687", 16, Done); (* FInt = "-1234567" *)
- StrToCard
- PROCEDURE StrToCard( S : ARRAY OF CHAR;
- Base : CARDINAL;
- VAR OK : BOOLEAN ) : LONGCARD;
- StrToCard takes a string S, representing a cardinal value, and returns the corresponding LONGCARD representation. Base denotes the base used in the conversion, and must lie in the range 2 to 16. OK is set to FALSE if the string S does not represent a LONGCARD value.
- Example:
- VAR FCard : LONGINT;
- Done : BOOLEAN;
- FCard := StrToCard( FCard := StrToCard( FCard :« StrToCard(
- "4553207", 8, Done);
- "1234567", 10, Done) "12D687", 16, Done);
- (* FCard = "1234567" *)
- (* FCard = "1234567" *)
- (* FCard = "1234567" *)
- StrToReal
- PROCEDURE StrToReal( S : ARRAY OF CHAR;
- VAR OK : BOOLEAN ) : LONGREAL;
- StrToReal takes a string S representing a real value and returns the corresponding LONGREAL value. The syntax for valid REAL values can be found in chapter 6. OK is set to FALSE if S does not represent a real value.
- Example:
- VAR FReal : LONGINT;
- Done : BOOLEAN;
- FReal StrToReal(
- FReal : = StrToReal(
- FReal :« StrToReal(
- "455.3207", Done);
- "123456e7", Done);
- "-0.1234567", Done)
- (* FReal - "4.553207E+2" *) (* FReal » "1.23456E-2" *)
- (* FReal - "-1.234567E-1" *)
- MODULE Lib
- The module Lib contains a number of general purpose procedures. These include: random number generation, data sorting, using DOS interrupts, producing sounds on the computer, and so forth.
- Sorting
- TopSpeed Modula-2 supplies two different sort procedures. These implement the quicksort and the heapsort algorithms. Quicksort is usually the fastest, but can be rather slow in the worst case (which is when the elements are already sorted). The running time of heapsort has a very small variance. Quicksort is a stable sorting algorithm, i.e. equal keys are not swapped, while heapsort is not stable.
- QSort
- TYPE
- CompareProc = PROCEDURE( CARDINAL, CARDINAL ) : BOOLEAN;
- SwapProc = PROCEDURE ( CARDINAL, CARDINAL ) ;
- PROCEDURE QSort(N: CARDINAL; Less: CompareProc; Swap: SwapProc);
- QSort performs a quicksort. The number of elements to be sorted is given by N. The elements are numbered from 1 to N. less is a function procedure which takes two CARDINAL parameters and returns the BOOLEAN result TRUE if the element specified by the first parameter is less than the element specified by the second parameter, swap is used to swap two elements specified by the parameters. You must provide procedures that perform the tasks carried out by less and swap.
- Example:
- MODULE SortArray; (* This module sorts an array *) IMPORT Lib;
- VAR a : ARRAY [1..100] OF CARDINAL;
- PROCEDURE less(11,12 : CARDINAL) : BOOLEAN;
- BEGIN
- RETURN a[il] < a[12);
- END less;
- PROCEDURE swap(11,12 : CARDINAL);
- VAR tmp : CARDINAL;
- BEGIN
- tmp := a[ll]; a[il] := a[12]; a[12] := tmp;
- END swap;
- BEGIN
- GetValues(a); (* assign values to a *)
- Lib.QSort(100,less,swap); (* sort the array a *) END SortArray.
- HSort
- PROCEDURE HSort(N: CARDINAL; Less: CompareProc; Swap: SwapProc);
- HSort performs a heapsort. See Qsort above for an explanation of the parameters.
- You can also use the example under QSort to try HSort.
- Random Number Generation
- RANDOMIZE
- PROCEDURE RANDOMIZE;
- This procedure initializes the pseudorandom number generator, and should be called before you start calling the procedures RANDOM or RAND. If you do not call RANDOMIZE before using the other two procedures, the “random” behavior of your program will be the same each time you run the program.
- RANDOM
- PROCEDURE RANDOM (Range: CARDINAL) : CARDINAL;
- Returns a random CARDINAL number in the range 0 to Range-1, inclusive.
- Example:
- VAR RVal : CARDINAL;
- RVal := RANDOM( 10000);
- returns a random CARDINAL value between 0 and 9999.
- RAND
- PROCEDURE RAND() : REAL;
- Returns a random REAL number in the range: 0.0 <= result < 1.0.
- Example:
- VAR RVal : REAL;
- RVal := RAND();
- might return 0.569, for example.
- Environment Procedures
- You can access the DOS command line via the pointer variable CommandLine or via the procedures ParamStr and ParamCount.
- TYPE
- CommandType = POINTER TO ARRAY [0.. 126] OF CHAR;
- VAR
- CommandLine : CommandType;
- The procedures listed below let you access the DOS environment and the command line.
- Environment
- PROCEDURE Environment(N : CARDINAL) : CommmandType;
- Returns string number N in the DOS environment. The first string has number zero.
- Example: The following statements illustrate the elements needed to call and
- display a DOS environment string. The statemements assume that the appropriate modules have been imported.
- VAR CLString : Lib.CommandType;
- WhichString : CARDINAL;
- CLString := Lib.Environment ( WhichString);
- lO.WrStr ( CLString*);
- Depending on your DOS environment and on the value of WhichString, the calls to Lib.Environment and to lO.WrStr might produce, for example:
- PROMTT=$p$g
- ParamCount
- PROCEDURE ParamCount() : CARDINAL;
- Returns the number of arguments on the command line. The program name is not counted as an argument. For example, if you call program pctest with the following command line:
- pctest first second third fourth
- ParamCount will return 4 as the number of arguments in the following call:
- CardResult := ParamCount ();
- ParamStr
- PROCEDURE ParamStr(VAR S: ARRAY OF CHAR; N: CARDINAL);
- Returns argument number N on the command line in the string S. The first argument has number one.
- Example: With the command line shown in the example for ParamCount,
- ParamStr ( argstr, 3);
- returns “third” in string argstr.
- Memory Block Operations
- All procedures in this section perform some operation on a consecutive block of memory.
- Move
- PROCEDURE Move(Source,Dest: ADDRESS; Count: CARDINAL);
- Copies a block of Count bytes from the memory area given by Source to the memory area given by Dest. The copy direction is chosen so that overlapping blocks are copied correctly.
- This move operation is independent of type, so the information in Dest will only be in a proper format if you moved the appropriate number of bytes. For example, if you move part of a string to a memory area allocated for another string, the destination “string” will not necessarily be null terminated.
- Example:
- Move ( ADR( vail), ADR( val2), 4);
- moves four bytes of material, beginning at the start of the memory area allocated for vail. The material is moved to the four bytes of memory that begin at the address of val2.
- WordMove
- PROCEDURE WordMove(Source,Dest: ADDRESS; WordCount: CARDINAL);
- Similar to Move, except that WordCount denotes the number of words (2 bytes) to be moved, rather than the number of bytes. This procedure is quicker than performing a Move of twice the size.
- Example:
- WordMove ( ADR( vail), ADR( val2), 4);
- moves eight bytes (four words) of material, beginning at the start of the memory area allocated for vail. The material is moved to the eight bytes of memory that begin at the address of val2.
- Fill
- PROCEDURE Fill(Dest: ADDRESS; Count: CARDINAL; Value: BYTE);
- Stores Value in the Count consecutive bytes starting at Dest. This is a fast way of initializing certain areas of memory in your program.
- Example:
- Fill ( strl. Length( strl), 47);
- initializes the string, strl, with the character (*/’) whose ASCII code is 47.
- WordFill
- PROCEDURE WordFill( Dest : ADDRESS;
- WordCount : CARDINAL;
- Value : WORD);
- Stores Value in the Count consecutive words starting at Dest.
- Example:
- WordFill ( ADR( vail), 4, 32768);
- puts the bit pattern for 32768 in the four consecutive words beginning at the the location of Vail.
- ScanR
- PROCEDURE ScanR( Dest : ADDRESS;
- Count : CARDINAL;
- Value : BYTE) : CARDINAL;
- ScanR searches for the first occurrence of Value in the block starting at location Dest and going Count bytes ahead towards higher addresses. The procedure returns the position relative to Dest, with Dest being in position 0. ScanR returns Count if Value is not found.
- Examples:
- VAR Res : CARDINAL;
- Res := ScanR (ADR ('klmnopqrst'), 10, SHORTCARD ('p')) ; (* Res = 5 *)
- Res ScanR(ADR('klmnopqrst'),10,SHORTCARD('k')); (* Res = 0 *)
- Res := ScanR(ADR('klmnopqrst'),10,SHORTCARD('x')); (* Res = 10 *)
- ScanL
- PROCEDURE ScanL( Dest : ADDRESS;
- Count : CARDINAL;
- Value : BYTE) : CARDINAL;
- Works like ScanR, except the search starts at Dest and works towards lower addresses — still returning a positive distance from Dest.
- Examples:
- VAR TestStr : ARRAY[ 0 .. 80] OF CHAR;
- Res : CARDINAL;
- TestStr := "abcdefghijklmnopqrst";
- Res :« ScanL( ADR( TestStr[ 10]), 10, SHORTCARD( 'd')); (* Res = 7 *)
- Res := ScanL( ADR( TestStr[ 10]), 10, SHORTCARD( 'k')); (* Res = 0 *)
- Res := ScanL( ADR( TestStr[ 10]), 10, SHORTCARD( 'z')); (* Res = 10 *)
- ScanNeR
- PROCEDURE ScanNeR(Dest : ADDRESS;
- Count : CARDINAL;
- Value : BYTE) : CARDINAL;
- Scans the block given by Dest, going Count bytes ahead towards higher addresses, to the first position where the contents differ differ from Value. It returns Count if every element in the block is equal to Value.
- Examples:
- VAR Res : CARDINAL;
- Res :» ScanNeR ( ADR (' aaaaabbbcc') ,10, SHORTCARD (' a')); (* Res = 5 *)
- Res := ScanNeR( ADR('aaaaaaaaaa'), 10, SHORTCARD ('a')); (* Res “ 10 *)
- Res : = ScanNeR( ADR('aaaaaaaaaa'), 10, SHORTCARD ('b')); (* Res = 0 *)
- ScanNeL
- PROCEDURE ScanNeL(Dest : ADDRESS;
- Count : CARDINAL;
- Value : BYTE) : CARDINAL;
- Similar to ScanNeR, except the search starts at Dest and works towards lower addresses. The distance returned from Dest is 0 or a positive value.
- Examples:
- VAR TestStr : ARRAY[ 0 .. 80] OF CHAR; Res : CARDINAL;
- TestStr : = "aaaaabbbbb";
- Res := ScanNeR ( ADR( TestStr [ 9]), 10, SHORTCARD ('a')) ; (* Res = 5 *)
- TestStr :« "aaaaaaaaaa";
- Res := ScanNeR) ADR( TestStr[ 9]), 10, SHORTCARD ('a')) ; (* Res = 10 *)
- TestStr := "aaaaaaaaaa";
- Res := ScanNeR( ADR( TestStr[ 9]), 10, SHORTCARD ('b')); (* Res = 0 *)
- Compare
- PROCEDURE Compare(Source,Dest : ADDRESS;
- Len : CARDINAL) : CARDINAL;
- Compares the two blocks specified by Source and Dest. The procedure looks for the first position where a difference occurs, and returns this position. Len denotes the length of the search. Compare returns Len if the two blocks are equal.
- Example:
- CardResult := Compare ( ADR( "abcdefghijkl"), ADR( "abcdeghujkl"), 10);
- returns 5, since the two locations differ in the sixth position, which has index 5.
- DOS Procedures
- Dos
- PROCEDURE Dos(VAR R: SYSTEM.Registers) ;
- Allows you to access DOS services through the DOS function handler (INI 21H). Consult the DOS documentation for details of the various function calls. Also see “MODULE System,” page 202, for a description of SYSTEM.Registers.
- Example:
- VAR r : SYSTEM.Registers;
- BEGIN
- r.AH : = 2CH; (* 2CH is the number of the DOS service requested *) Dos (r);
- END;
- Upon return, r contains the current time in the following bytes of the CX and DX registers.
- Register Value
- CH hour (0 through 23)
- CL minutes (0 through 59)
- DH seconds (0 through 59)
- CH hundredths of seconds (0 through 99)
- Intr
- PROCEDURE Intr(VAR R: SYSTEM.Registers; I: CARDINAL);
- Allows you to make a software interrupt directly — that is, to bypass the DOS function handler (INT21H) when sending an interrupt. I is the interrupt number. Consult the DOS documentation for details of the interrupts. Also see page 203 for a description of SYSTEM.Registers.
- Example:
- VAR r : SYSTEM.Registers;
- BEGIN
- Intr(r, 12H) ; END;
- This interrupt returns the amount of RAM memory in the field r. AX
- Execute
- PROCEDURE Execute (Name CommandLine StoreAddr StoreLen
- ) : CARDINAL;
- ARRAY OF CHAR, ARRAY OF CHAR, ADDRESS; CARDINAL
- (* full name of program *) (* command line for program *) (* storage to execute in *) (* length in paragraphs *) (* DOS reply (0=OK) *)
- This procedure executes a program. Name is the full name (including the extension) of the program you want executed. CommandLine holds the parameters (if any) for the program that is to be run. You must also supply a pointer to the storage where the program can be executed (StoreAddr), and the length in paragraphs of this storage (StoreLen). This storage could be allocated by the ALLOCATE function, see page 198.
- Execute returns the DOS return status. Zero means the program has executed; for other values consult the DOS documentation. The newly started program inherits a copy of the environment of the parent program. It also inherits all open files of the parent program.
- Example:
- MODULE h;
- IMPORT IO, Lib;
- VAR s : ARRAY[0..30] OF CHAR;
- BEGIN
- Lib.ParamStr(«,1) ;
- IO. WrStr ('Hallo ');
- 10.WrStr(a);
- END h.
- Compile and link h. mod to get h. exe; now h. exe can be executed from the following program:
- MODULE ExecEx; (* Execute example *)
- IMPORT Storage, Lib, IO;
- VAR a : ADDRESS;
- i : CARDINAL;
- BEGIN
- Storage.ALLOCATE(a,20000);
- 1 := Lib.Execute("h.exe"," there",a,20000 DIV 16);
- IF i # 0 THEN IO.WrStr ('Failed' ); END;
- Storage.DEALLOCATE(a,20000);
- END ExecEx.
- This will produce the following output:
- Hello there
- Program h. exe writes “hello” and whatever is passed as the first command line argument — in this case, “there” is passed as an argument to Execute.
- Address Arithmetic
- The procedures in this section perform arithmetic (addition and subtraction) on pointers. Addresses in the 8086 family of processors consist of a segment part and an offset part. The physical address is calculated as: segment * 16 + offset. A normalized pointer is a pointer with an offset in the range 0 to 15.
- AddAddr
- PROCEDURE AddAddr(A: ADDRESS; increment: CARDINAL): ADDRESS;
- Returns the normalized address of the byte increment bytes after the physical address A.
- Example:
- VAR ShiftedAddr : ADDRESS;
- Reference : LONGREAL;
- ShiftedAddr := AddAddr( ADR( Reference), 8);
- returns the address eight bytes past the starting location of Reference.
- SubAddr
- PROCEDURE SubAddr(A: ADDRESS; decrement: CARDINAL): ADDRESS;
- Returns the normalized address of the byte decrement bytes before the physical address A.
- Example:
- VAR ShiftedAddr : ADDRESS;
- Reference : LONGREAL;
- ShiftedAddr := AddAddr( ADR( Reference), 8);
- returns the address eight bytes before the starting location of Reference.
- IncAddr
- PROCEDURE IncAddr(VAR A : ADDRESS; increment : CARDINAL);
- A becomes the normalized address of the byte increment bytes after the physical address A.
- Example:
- VAR ShiftedAddr : ADDRESS;
- Reference : LONGREAL;
- ShiftedAddr :- ADR( Reference);
- IncAddr( ShiftedAddr, 8);
- makes ShiftedAddr refer to the address eight bytes after the starting location of Reference.
- DecAddr
- PROCEDURE DecAddr(VAR A : ADDRESS; decrement : CARDINAL);
- A becomes the normalized address of the byte decrement bytes before the physical address A.
- Example:
- VAR ShiftedAddr : ADDRESS;
- Reference : LONGREAL;
- ShiftedAddr := ADR( Reference);
- IncAddr( ShiftedAddr, 8);
- makes ShiftedAddr refer to the address eight bytes before the starting location of Reference.
- Long Jumps
- Long jumps are a (restricted) way to do non-local gotos. That is, by means of long jumps execution can be transferred from one procedure to another, without returning. The following procedures are often used to deal with error situations.
- SetJmp and LongJmp
- TYPE
- LongLabel = ARRAY[0..3] OF CARDINAL;
- PROCEDURE SetJmp (VAR Lbl: LongLabel) : CARDINAL;
- PROCEDURE LongJmp(VAR Lbl: LongLabel; result: CARDINAL);
- SetJmp and LongJmp are used in conjunction with each other. SetJmp saves the state of a procedure in the buffer Lbl, and returns the value 0. A later call to LongJmp with the same buffer will restore that state, so that it appears as if SetJmp has been called and has returned the value result.
- SetJmp must be called before LongJmp is called, and the procedure that called SetJmp must still be active when LongJmp is called, otherwise the result is unpredictable.
- Note that local variables are often held in machine registers (even across procedure calls), which means that their values might have been changed when SetJmp “returns” via LongJmp. To deal with this problem, the volatile compiler directive (*$W+*) (see Chapter 7) can be used for those local variables whose values you wish to save.
- Example:
- MODULE LongJmpEx;
- IMPORT IO, Lib;
- VAR buf : Lib.LongLabel;
- PROCEDURE p2; FORWARD;
- PROCEDURE p;
- BEGIN
- IF Lib.SetJmp(buf) # 0 THEN
- IO.WrStr('LongJmp has been called'); HALT;
- END;
- IO.WrStr ('Hello') ; lO.WrLn;
- p2;
- END p;
- PROCEDURE p2;
- VAR error : BOOLEAN;
- BEGIN
- error := TRUE;
- IF error THEN Lib.LongJmp(buf,1); END;
- END p2;
- BEGIN
- p;
- END LongJmpEx.
- Will produce the following output:
- Hello
- LongJmp has been called
- Error Handling
- MathError and MathError2
- PROCEDURE MathError ( R: LONGREAL; S: ARRAY OF CHAR);
- PROCEDURE MathError2(Rl,R2: LONGREAL; S: ARRAY OF CHAR);
- These are default math error handling procedures. They are called by some of the procedures in the module MATHLIB, in case of an invalid argument.
- MathError outputs a message which includes the name of the procedure in error. See “Error Handling” for the MATHLIB module, page 211, for more information.
- UserBreak
- PROCEDURE UserBreak;
- This procedure aborts the program with a runtime error message, and terminates by a call to the procedure HALT (see Chapter 6). The run-time error message has the following layout:
- Run Time Error [AAAA/SSSS:OOOO] User Break
- AAAA is the absolute segment of the user break, SSSS is the relative segment (which can be seen in the link map), and OOOO is the offset of the user break.
- DisableBreakCheck
- PROCEDURE DisableBreakCheck;
- Disables the control-break handler. After a call to this procedure the program can no longer be aborted with ICtrllllBreakH The check setting is ON by default. You can also specify this setting through the (*$B*) compiler directive (see Chapter 7).
- EnableBreakCheck
- PROCEDURE EnableBreakCheck;
- Enables the control-break handler, so the program can be aborted using ||Ctrl||[Brcak]|. When the program is aborted through such a key sequence, a run-time error message is reported and the program terminates by a call to the HALT procedure (see Chapter 6).
- The run-time message has the layout described for procedure UserBreak (see above). However, if AAAA is outside the program, (e.g., if the program is aborted while executing a DOS function) the runtime message will have the following form:
- Run Time Error [AAAA:OOOO] User Break
- FatalError
- PROCEDURE FatalError(S : ARRAY OF CHAR);
- Writes the string S to standard output, and terminates program execution by a call to the procedure HALT.
- Example:
- FatalError ( 'Cannot continue, ending program.');
- writes the string message if the procedure is called.
- SetReturnCode
- PROCEDURE SetReturnCode(code: SHORTCARD);
- This procedure lets you specify the DOS return code to use when the program is terminated. This value is passed on to the parent program. If the program was activated from the command line, then you can also access this return code in the operating system — through the DOS code ErrorLevel.
- Example:
- SetReturnCode( 1);
- would indicate to DOS that ||Ctrl||Breakl] was used to end the program.
- Miscellaneous
- There are several additional procedures in the Lib module, which do a variety of things.
- Delay
- PROCEDURE Delay(Time : CARDINAL);
- Delays program execution by Time milliseconds.
- Example:
- Delay( 60000);
- delays for one minute.
- Sound
- PROCEDURE Sound(FreqHz : CARDINAL);
- Turns on the computer’s speaker with a sound of FreqHz Hz.
- Example:
- Sound( 1000);
- creates a 1000Hz sound.
- NoSound
- PROCEDURE NoSound;
- Turns off the computer’s speaker.
- HashString
- PROCEDURE HashString ( S : ARRAY OF CHAR;
- Range : CARDINAL) : CARDINAL;
- HashString computes a hash value in the range 0 to Range-1, of the string S.
- Example:
- VAR HashNr : CARDINAL;
- HashNr := HashString( "Hello", 26); (* HashNr = 4 *)
- HashNr := HashString( "hello", 26); (* HashNr = 14 *)
- Terminate
- PROCEDURE Terminate(P : PROC; VAR C : PROC);
- Terminate is used to program actions which need to be performed when the program terminates. Terminate causes procedure P to be called when the program terminates, or by the HALT procedure. C is the procedure which HALT would call if Terminate had not been invoked. Normally, procedure P will call procedure C, and in this way a chain of procedures is built.
- If HALT is called in P, program execution will stop.
- Example:
- MODULE TerminateEx;
- IMPORT Lib,10;
- VAR
- Continual : PROC;
- Continue2 : PROC;
- PROCEDURE CloseDownl;
- BEGIN
- 10.WrStr ('CloseDown-1'); lO.WrLn;
- Continual;
- END CloseDownl;
- PROCEDURE CloseDown2;
- BEGIN
- IO. WrStr ('CloaeDown-2'); IO.WrLn;
- Continue2;
- END CloseDown2;
- BEGIN
- IO.WrStr('Program starts');
- IO.WrLn;
- Lib.Terminate(CloseDownl,Continual);
- Lib.Terminate(CloseDown2,Continue2);
- HALT;
- IO.WrStr('this statement is never executed'); END TerminateEx.
- This program produces the following output:
- Program starts
- CloseDown-2
- CloseDown-1
- MODULE IO
- This section describes the screen input/output library. The IO procedures work on the standard input/output devices (i.e., the keyboard and screen). You can also do screen I/O with the procedures in module FIO, by using the standard file handles (see “Global Variables in FIO,” page 182).
- Global Variables in IO
- The variables below control the behaviour of the I/O procedures. Several variables are also declared in module FIO,page 182 and have the same meaning in both modules. These are: OK, Eng, Separators and ChopOf f.
- CONST
- MaxRdLength = 256;
- TYPE
- WrStrType = PROCEDURE ( ARRAY OF CHAR );
- RdStrType = PROCEDURE ( VAR ARRAY OF CHAR ) ;
- CHARSET = SET OF CHAR;
- VAR
- RdLnOnWr : BOOLEAN; (* Clear buffered input after write *)
- Prompt : BOOLEAN; (* Prompt '?' on read from empty line*)
- WrStrRedirect : WrStrType;
- RdStrRedirect : RdStrType;
- Separators OK
- ChopOff Eng
- : CHARSET;
- : BOOLEAN;
- : BOOLEAN;
- : BOOLEAN;
- (* Engineering notation *)
- The BOOLEAN variable OK is set by all the formatted input/output procedures, as well as by WrBin and RdBin. The value of the BOOLEAN indicates whether the attempted operation was successful.
- Separators is a set of delimiters used by the Rdltem procedure. The default contents of Separators are shown in the following listing. You can change these values by changing assignment statements in FIO.MOD and IO.MOD.
- CHARSET{CHR (9) , CHR (10) , CHR (13) , CHR (26) , ' ' } .
- All the formatted I/O procedures call one of two procedure variables to do their worK: WrStrRedirect or RdStrRedirect. You can redirect I/O by replacing WrStrRedirect and RdStrRedirect with your own “write string” and “read string” procedures.
- Formatted Output
- A write procedure is available for each of the simple types of TopSpeed Modula-2.
- Wr‘simple type’
- PROCEDURE WrChar PROCEDURE WrBool ( V : ( V : : CHAR );
- : BOOLEAN ; Length : INTEGER);
- PROCEDURE WrShtlnt ( V : : SHORTINT ; Length : INTEGER);
- PROCEDURE Wrlnt ( V : INTEGER ; Length : INTEGER);
- PROCEDURE WrLnglnt ( V : : LONGINT ; Length : INTEGER);
- PROCEDURE WrShtCard( V : : SHORTCARD; Length : INTEGER);
- PROCEDURE WrCard ( V l : CARDINAL ; Length : INTEGER) ;
- PROCEDURE WrLngCard( V : : LONGCARD ; Length : INTEGER) ;
- PROCEDURE WrShtHex ( V : : SHORTCARD; Length : INTEGER);
- PROCEDURE WrHex ( V : CARDINAL ; Length : INTEGER);
- PROCEDURE WrLngHex ( V : : LONGCARD ; Length : INTEGER) ;
- PROCEDURE WrReal ( V : : REAL ; Preci si or
- Length : i: CARDINAL;
- INTEGER);
- PROCEDURE WrLngReal( V : : LONGREAL ; Precisiot i; CARDINAL;
- Length : INTEGER);
- These procedures write the value V (of the given type) to the standard output device. All procedures (except WrChar) also take a parameter (Length) which specifies the field width of the formatted data. If Length is negative, the formatted data will be left adjusted, otherwise the output is right adjusted.
- All the procedures (except WrChar and WrBool) call a suitable conversion procedure from the Str module to get a string representation of the value V (see page 153); this string is then output using WrStrAdj.
- Finally, WrReal and WrLngReal take an additional parameter, Precision, whose meaning is described in the procedure RealToStr (page 154).
- The global variable Eng indicates whether real numbers are formatted using engineering notation (see RealToStr, page 154). The default value of Eng is FALSE.
- Cardinal values can the written in hexadecimal format using procedures WrShtHex, WrHex and WrLngHex.
- Examples: The following calls to the routines for writing simple types produce
- the output following the calls.
- WrChar( 'a');
- WrLn;
- WrBool( TRUE, -15);
- WrLn;
- WrBool( TRUE, 15);
- WrLn; WrLn;
- WrShtlnt( 7, -15);
- Wrlnt( 27, -15);
- WrLnglnt( 2777777, -15);
- WrLn;
- WrShtlnt( 7, 15);
- Wrlnt( 27, 15);
- WrLnglnt( 2777777, 15);
- WrLn; WrLn;
- WrShtCard( 35, -15);
- WrCardf 3555, -15);
- WrLngCardf 355555, -15);
- WrLn;
- WrShtCardf 35, 15);
- WrCard( 3555, 15);
- WrLngCardf 355555, 15);
- WrLn; WrLn;
- WrShtHex( 39, -15);
- WrHex( 3999, -15);
- WrLngHexf 399999, -15);
- WrLn;
- WrShtHex( 39, 15);
- WrHex( 3999, 15);
- WrLngHexf 399999, 15);
- WrLn; WrLn;
- WrReal( 35.5555, 5, -15);
- WrLngReal( 356789.55556789, 5, -15);
- WrLn;
- WrReal( 35.5555, 5, 15);
- WrLngReal( 356789.55556789, 5, 15);
- WrLn;
- (* Output from calls *) a
- TRUE
- TRUE
- 7 27
- 7 2777777
- 27 2777777
- 35 3555 355555
- 35 3555 355555
- 27 F9F 61A7F
- 27 F9F 61A7F
- 3.5556E+1 3.5679E+5
- 3.5556E+1 3.5679E+5
- WrStr
- PROCEDURE WrStr(S: ARRAY OF CHAR);
- This procedure writes the string S to standard output.
- Example:
- WrStr < "Hello there");
- writes the two-word string.
- WrStrAdj
- PROCEDURE WrStrAdj(S: ARRAY OF CHAR; Length: INTEGER);
- This pocedure writes the string S to standard output, using ABS (Length) as the field width. If ABS(Length) is smaller than Str. Length (S) and the global variable ChopOff is TRUE, then a sequence of *?’ characters is written instead of S. If ChopOff is FALSE the field is extended to the number of characters in the string, regardless of the original original field width. If ABS ( Length) is greater than or equal to Str. Length ( S), then the entire string is written.
- The sign of Length determines whether S will be left adjusted (negative) or right adjusted (positive).
- Example:
- WrStrAdj( 'Hello', 10);
- WrLn;
- WrStrAdj( 'Hello', -10);
- write the following output:
- Hello
- Hello
- WrCharRep
- PROCEDURE WrCharRep(V: CHAR; Count: CARDINAL);
- Writes character V repeatedly to the standard output. The character is written Count times.
- Example:
- WrCharRep( 'g', 5);
- writes the following:
- ggggg
- WrLn
- PROCEDURE WrLn;
- Writes a newline (CHR (13), CHR (10)) to standard output.
- Formatted Input
- A read procedure is available for each of the simple types of TopSpeed Modula-2.
- Rd'simple type’
- PROCEDURE PROCEDURE PROCEDURE PROCEDURE PROCEDURE PROCEDURE PROCEDURE PROCEDURE
- RdChar() RdBool () RdShtlntO Rdlnt() RdLnglntO RdShtCard() RdCard() RdLngCard ()
- : CHAR;
- : BOOLEAN;
- : SHORTINT;
- : INTEGER;
- : LONGINT;
- : SHORTCARD;
- : CARDINAL;
- : LONGCARD;
- PROCEDURE RdShtHex() : SHORTCARD;
- PROCEDURE RdHex() : CARDINAL;
- PROCEDURE RdLngHex() : LONGCARD;
- PROCEDURE RdReal () : REAL;
- PROCEDURE RdLngReal () : LONGREAL;
- The Rd* simple type’ procedures read from the standard input and return a value of a ‘simple type’ as indicated by the declarations above.
- All procedures (except RdChar) call Rdltem to get a character sequence which is delimited by characters from the global set variable Separators. The string read in this way is then converted to a value using one of the conversion procedures from the Str module (see page 153).
- The procedures RdShtHex, RdHex and RdLngHex read cardinal values in hexadecimal format.
- The procedure RdBool returns TRUE if it reads the string ‘TRUE’ (but neither ‘true’ nor ‘True’); for all other input the procedure returns FALSE.
- The syntax for valid REAL values can be found in Chapter 6.
- The global variable OK is set to FALSE if a value of the required type cannot be read.
- All input is buffered a line at a time. Therefore, it’s possible to prompt for more than one value on a given line of input.
- RdStr
- PROCEDURE RdStr(VAR V: ARRAY OF CHAR);
- RdStr reads a string from the standard input, and returns it in V. Characters are read until either of the following conditions is met:
- • the carriage return character (CHR (13)) is read, in which case V is zero terminated
- • the string is full — that is, HIGH (V) +1 characters have been read, in which case V is not zero terminated
- Example:
- RdStr( CurrQn);
- reads a string from the standard input, and assigns this value to the string variable
- CurrQn.
- Rdltem
- PROCEDURE Rdltem VAR V: ARRAY OF CHAR);
- Rdltem reads a string from the standard input. The procedure stops reading when any character from the global set variable Separators is read. The string is returned in V.
- Example: Consider the following line in the standard input:
- Hello there, how are you?
- The call
- Rdltem( CurrStr);
- would read only the word ‘Hello’ into the string variable CurrStr. Procedure Rd- Str, on the other hand, would read all five words.
- RdLn
- PROCEDURE RdLn;
- Skips the rest of the input on the current input line.
- EndOfRd
- PROCEDURE EndOfRd(Skip: BOOLEAN) : BOOLEAN;
- If Skip is TRUE, then a sequence of characters, is skipped from the input line. In particular, characters belonging to the set Separators are skipped. EndOfRd returns TRUE if all characters on the current input line have been read.
- EndOfRead can be used to determine whether there is more information on the line. The procedure can be used to skip over any delimiters. You can then read the next item on the line, if there is one. This is useful when reading more than one item of information from a line.
- Example: For the input string,
- Hello there, how are you? I'm fine, thanks.
- the following loop produces the output below it.
- Rdltem( First);
- WHILE NOT EndOfRd( TRUE) DO
- WrStr( First);
- Rdltem( First);
- END;
- WrLn;
- (* Output from preceding loop: *) hellothere,howareyou?!'mfine,
- Basic Input Procedures
- The following two procedures provide low-level services, such as deciding whether a key has been pressed.
- KeyPressed
- PROCEDURE KeyPressed() : BOOLEAN;
- This procedure returns true if a character is available from the standard input. Note that this procedure is not valid for buffered input characters.
- Example:
- IF KeyPressed () THEN
- END;
- RdKey
- PROCEDURE RdKey() : CHAR;
- RdKey returns a character from standard input. If no character is available it waits for one. No buffering is involved and the character is not echoed on the screen.
- Example:
- TheChar :“ RdKey ();
- reads a character into the CHAR variable, TheChar, without echoing the input.
- Redirection
- The following two procedures enable you to redirect the input and output streams.
- Redirectlnput
- PROCEDURE Redirectlnput(FileName: ARRAY OF CHAR);
- Closes the current input stream and opens a new input stream specified by the string FileName. If this stream is closed later, input will be restored to the standard input (even if the input stream was redirected to a file on the command line).
- Example:
- Redirectlnput( "Newlnput");
- opens a stream specified by “Newlnput” and gets input from this file instead of from standard input.
- To close the current input stream (and return the standard input to its default stream), enter the following:
- Redirectlnput( 'CON');
- RedirectOutput
- PROCEDURE RedirectOutput(FileName: ARRAY OF CHAR);
- This procedure closes the current output stream and opens a new output stream specified by the string FileName. If this stream is closed later, output will be restored to the standard output (even if the output stream was redirected to a file on the command line).
- Example:
- Red!rectOutput( "NewOut");
- opens a stream specified by “NewOut” and writes to this file instead of to standard output.
- To close the current output stream (and return the standard output to its default), enter the following:
- RedirectOutput( 'CON');
- MODULE FIO
- The procedures in this module are used for file handling and file input/output. FIO also contains procedures for directory handling.
- A file has an associated file position, which is updated by write and read operations. The first position in a file is 0.
- Files are sequential but direct access to individual elements in a file is possible using the Seek procedure.
- Before a file can be read or written it must be opened using one of the procedures Open, Create or Append. These procedures all return a file handle, which is used in all subsequent references to that file. Open files should be closed with Close before the program terminates, or when they are no longer used.
- By default, files are unbuffered. To do buffered I/O, use the procedure Assign- Buffer, as described below.
- Global Variables in FIO
- These variables are used to control the behavior, and to inspect the result of the file handling and input/output procedures. Some of these variables are also used in module IO, and have the same meaning in both modules.
- CONST
- MaxOpenFiles = 15;
- (* Error if Write fails with disk full*) (* MSDOS standard file handles *)
- DiskFull = 0F0H;
- Standardinput - 0 ;
- Standardoutput = 1 ;
- ErrorOutput - 2 ;
- AuxDevice = 3 ;
- PrintarDavice = 4 ;
- TYPE
- File - CARDINAL; (* File handle type *)
- VAR
- EOF lOcheck
- Separators OK ChopOff Eng
- : BOOLEAN;
- : BOOLEAN;
- : Str.CHARSET;
- : BOOLEAN;
- : BOOLEAN;
- : BOOLEAN;
- (* if TRUE, errors terminate *) (* program with report *)
- (* Engineering notation *)
- The predefined MSDOS standard file handles are numbered from 0 to 4, as defined by the constants above; user files are numbered from 5 to MaxOpenFiles. The files denoted by the standard handles are defined when program execution starts. You need not open these files before using them.
- The BOOLEAN variable OK is set by all the formatted input/output procedures, as well as by WrBin and RdBin. The value of the BOOLEAN indicates whether the attempted operation was successful.
- If an attempt is made to write formatted data in less space than is required, then a sequence of *?’ is written if ChopOff is TRUE. If ChopOff is FALSE then the specified field width is exceeded. ChopOff has a default value of FALSE.
- EOF indicates whether the end of file was reached during the last read operation.
- Separators is a set of delimiters used by the Rdltem procedure. The default contents of Separators are shown in the following listing. You can change these values by changing assignment statements in FIO.MOD and IO.MOD.
- CHARSET{CHR(9) ,CHR(10) ,CHR(13) ,CHR(26) , ' ' } .
- Eng indicates whether real numbers are formatted using engineering notation (see RealToStr, page 154). The default value of Eng is FALSE.
- If lOcheck is TRUE then errors that occur during execution of the procedures listed below will terminate the program with an error message. If lOcheck is FALSE, errors can be inspected by a call to the procedure lOresult. The default value of lOcheck is TRUE. The following procedures report errors if lOcheck is TRUE:
- Open Append
- Truncate GetPos Erase Rename ChDir MkDir
- Create
- Seek
- ReadFirstEntry
- RmDir
- Close Size ReadNextEntry GetDir
- File Handling
- Files are unbuffered by default. Thus, DOS is accessed every time a read or write operation is done. To achieve more efficient input/output, you can associate a buffer with a file — using the procedure AssignBuf f er — so that larger chunks of data are passed to DOS.
- Open
- PROCEDURE Open(Name: ARRAY OF CHAR) : File;
- This procedure opens the file specified by Name for reading or writing, and returns a handle for subsequent operations on the file. The file position is set to the beginning of the file. If lOcheck is FALSE and the specified file could not be opened, MAX (CARDINAL) is returned.
- If you write to a nonempty file that has been opened using this procedure, data already in the file will be overwritten.
- Example:
- VAR QnFile, AnsFlle : File;
- QnFile := Open( "Trivia.Qns");
- AnsFlle := Open( "Trivia.Ans");
- The preceding commands open two files (named “Trivia.Qns” and the other named “Trivia.Ans”). The file handles associated with these files are returned to the variables QnFile and QnsFile.
- Append
- PROCEDURE Append(Name: ARRAY OF CHAR) : File;
- Append opens the file specified by Name, sets the file position to the end of the file, and returns a handle to the open file (or MAX (CARDINAL), if the file was not successfully opened). Doing write operations to a nonempty file opened with Append will add data to the end of the file, rather than overwriting data already in the file.
- Example:
- VAR QnFile, AnsFlle : File;
- QnFile := Append( "Trivia.Qns");
- AnsFile := Append( "Trivia.Ans");
- The preceding commands open two files (named “Trivia.Qns” and “Trivia.Ans”). In each case, the file position is set to the end of the files so new material will be appended to the end of the files.
- Create
- PROCEDURE Create(Name: ARRAY OF CHAR) : File;
- This procedure creates a file specified by Name, and returns a handle to the file (or MAX (CARDINAL), if the file was not successfully created). If the file already exists then the previous contents are lost. The created file is opened for read or write operations.
- Example:
- VAR NewQns : File;
- NewQns := Create( "NewQ.Qns");
- creates a new file (named “NewQ.Qns”).
- Close
- PROCEDURE Close (F: File);
- Close flushes the buffer associated with the file F (if any), and then closes the file.
- Example:
- Close ( QnFile);
- closes the file whose handle is stored in QnFile, which is of type File.
- AssignBuffer
- PROCEDURE AssignBuffer (F : File; VAR Buf: ARRAY OF BYTE);
- This procedure assigns the buffer Buf to the file F. For most efficient use the size of the buffer should be: N * 512 + Bufferoverhead, where N is at least 2. The value of Bufferoverhead is specified in FIO.DEF.
- Example:
- VAR FBuff : ARRAY [ 0..2047] OF BYTE;
- AnsFile : File;
- AssignBuffer( AnsFile, FBuff);
- assigns a 2K buffer, FBuff, to the file with handle AnsFile.
- Exists
- PROCEDURE Exists(Name: ARRAY OF CHAR) : BOOLEAN;
- This procedure returns TRUE if the file specified by Name exists. Exists uses ReadFirstEntry to determine its result.
- Example:
- VAR QnFHandle : File;
- IF Exists( "Current.Qns") THEN
- QnFHandle := Append( "Current.Qns");
- ELSE
- QnFHandle := Create( "Current.Qns") ;
- END;
- Erase
- PROCEDURE Erase(Name: ARRAY OF CHAR);
- Thie procedure deletes the file specified by Name.
- Example:
- Erase( "Current.Qns");
- deletes the file named “Current.Qns” from the current directory.
- Rename
- PROCEDURE Rename(Name,NewName : ARRAY OF CHAR);
- This renames the file Name to NewName.
- Example:
- Rename( "Current.Qns", "Old.Qns");
- changes the name of a file from the first to the second value.
- Truncate
- PROCEDURE Truncate(F: File);
- This procedure truncates the file F to its current file position. Note that F is a file handle, not a file name.
- Example:
- VAR AnsFile : File;
- Truncate ( AnsFile);
- truncates the file with handle AnsFile at the current file position.
- GetPos
- PROCEDURE GetPos(F: File) : LONGCARD;
- GetPos returns the current file position in the file F.
- Example:
- Where := GetPos( QnFile);
- assigns the current file position of QnFile to the LONGCARD variable, Where.
- QnFile is of type File.
- Seek
- PROCEDURE SeekfF: File; Pos: LONGCARD);
- This procedure sets the file position associated with F to Pos.
- Example:
- Seek( QnFile, Where);
- moves the file position to location Where in the file.
- Size
- PROCEDURE Size(F: File) : LONGCARD;
- Returns the size in bytes of the file F.
- Example:
- VAR FSize : LONGCARD; QnFile : FILE;
- FSize := Size( QnFile);
- lOresult
- PROCEDURE lOresult () : CARDINAL;
- lOresult can be called after most operations to test the success of the operation. Zero means that the operation succeeded, otherwise lOresult returns the error code as defined by DOS. Note that the global variable lOcheck must be FALSE when using this function (see also lOcheck, page 182).
- Example:
- FileOpeningStatus lOresult();
- assigns the DOS error code resulting from the last file operation.
- Formatted Output
- The procedures below perform formatted output to files. A write procedure is available for each of the simple types of TopSpeed Modula-2.
- All Wr'simple type’ procedures (except WrChar) call WrStrAdj.
- Wr'simple type
- PROCEDURE WrChar (F : File; V : CHAR );
- PROCEDURE WrBool (F : File; V : BOOLEAN ; Length : INTEGER);
- PROCEDURE WrShtlnt (F : File; V : SHORTINT ; Length : INTEGER);
- PROCEDURE Wrlnt (F : File; V : INTEGER ; Length : INTEGER);
- PROCEDURE WrLnglnt (F : File; V : LONGINT ; Length : INTEGER);
- PROCEDURE WrShtCardfF : File; V : SHORTCARD; Length : INTEGER); PROCEDURE WrCard (F : File; V : CARDINAL ; Length : INTEGER);
- PROCEDURE WrLngCard(F : File; V : LONGCARD ; Length : INTEGER);
- PROCEDURE WrShtHex (F : File; V : SHORTCARD; Length : INTEGER);
- PROCEDURE WrHex (F : File; V : CARDINAL ; Length : INTEGER);
- PROCEDURE WrLngHex (F : File; V : LONGCARD ; Length : INTEGER);
- PROCEDURE WrReal (F : File; V : REAL; Precision : CARDINAL;
- Length : INTEGER);
- PROCEDURE WrLngReal(F :
- File;
- LONGREAL; Precision: CARDINAL; Length : INTEGER);
- The Wr’simple type’ procedures take the following parameters: a file handle F, the value V to be written, and the field width (Length) of the formatted data. (The last parameter does not apply to WrChar). If Length is negative, the formatted data will be left adjusted, otherwise the output is right adjusted.
- All the procedures (except WrChar and WrBool) call a suitable conversion procedure from the Str module to get a string representation of the value V (see “Conversion Procedures,” page 153); this string is then output using WrStrAdj.
- Cardinal values can be the written in hexadecimal format, using the procedures Wr- ShtHex, WrHex and WrLngHex.
- WrReal and WrLngReal take an additional parameter, Precision, which has the same meaning as in the procedure RealToStr (see page 154). The global variable Eng indicates whether a real value is formatted in engineering notation.
- Examples: The following calls to the routines for writing simple types produce
- the output following the calls.
- VAR OutFile : File;
- WrChar( OutFile, 'a');
- WrLn( OutFile);
- WrBool( OutFile, TRUE, -15);
- WrLn( OutFile);
- WrBool( OutFile, TRUE, 15);
- WrLn( OutFile); WrLn( OutFile);
- WrShtlnt( OutFile, 7, -15);
- Wrlnt( OutFile, 27, -15);
- WrLnglnt( OutFile, 2777777, -15);
- WrLn( OutFile);
- WrShtlnt( OutFile, 7, 15);
- Wrlnt( OutFile, 27, 15);
- WrLnglnt( OutFile, 2777777, 15);
- WrLn( OutFile); WrLn( OutFile);
- WrShtCardf OutFile, 35, -15);
- WrCard( OutFile, 3555, -15);
- WrLngCard( OutFile, 355555, -15);
- WrLn( OutFile);
- WrShtCard( OutFile, 35, 15);
- WrCard( OutFile, 3555, 15);
- WrLngCard( OutFile, 355555, 15);
- WrLn( OutFile); WrLn( OutFile);
- WrShtHex( OutFile, 39, -15);
- WrHex( OutFile, 3999, -15);
- WrLngHex( OutFile, 399999, -15);
- WrLn( OutFile);
- WrShtHex( OutFile, 39, 15);
- WrHex( OutFile, 3999, 15);
- WrLngHex( OutFile, 399999, 15);
- WrLn( OutFile); WrLn( OutFile);
- WrReal( OutFile, 35.5555, 5, -15);
- WrLngReal( OutFile, 356789.55556789, 5, -15);
- WrLn( OutFile);
- WrReal( OutFile, 35.5555, 5, 15);
- WrLngReal( OutFile, 356789.55556789, 5, 15);
- WrLn( OutFile);
- (* Output from calls, written to file associated with OutFile handle *)
- TRUE
- TRUE
- 7 27 7 2777777
- 27 2777777
- 35 3555 355555
- 35 3555 355555
- 27 F9F 61A7F
- 27 F9F 61A7F
- 3.5556E+1 3.5679E+5
- 3.5556E+1 3.5679E+5
- WrStr
- PROCEDURE WrStr(F: File; V: ARRAY OF CHAR);
- This procedure Writes the string V to the file F.
- Example:
- WrStr( AnsFile, "Excellent");
- writes “Excellent” to the file associated with the handle AnsFile.
- WrStrAdj
- PROCEDURE WrStrAdj(F: File; S: ARRAY OF CHAR; Length: INTEGER);
- WrStrAdj writes the string S to the file F, using ABS (Length) as the field width. If ABS (Length) is smaller than Str. Length (S) and the global variable ChopOff is TRUE, then a sequence of *?’ characters is written instead of S. If ChopOf f is FALSE then the field width is exceeded and the entire string is written. If Length is negative the formatted data will be left adjusted, otherwise it is right adjusted.
- Example:
- WrStrAdj(Standardoutput,'Hello',10);
- WrLn(Standardoutput);
- WrStrAdj(Standardoutput,'Hello',-10);
- write the following output:
- Hello
- Hello
- WrCharRep
- PROCEDURE WrCharRep(F: File; V: CHAR ; Count: CARDINAL);
- WrCharRep writes the character V repeatedly to the file F. Count specifies the number of times to write V.
- Example:
- WrCharRep( Standardoutput, ' g' , 5) ; writes the following:
- ggggg
- WrLn
- PROCEDURE WrLn(F: File);
- WrLn writes a newline (CHR(13) ,CHR (10)) to the file F.
- Example:
- WrLn( Standardoutput);
- moves the cursor to the beginning of the next line on the standard output — generally the screen.
- WrBin
- PROCEDURE WrBin (F: File; Buf: ARRAY OF BYTE; Count: CARDINAL);
- This procedure writes a block of “raw” unformatted data specified by Buf to the file F. Count is the size (in bytes) of the block.
- Example:
- VAR Code : ARRAY [ 0 .. 49] OF BYTE;
- WrBin( CodeFile, Code, 50);
- writes 50 bytes — contained in the array Code — to the file associated with the handle CodeFile.
- Formatted Input
- The global variable EOF is set to TRUE if the end-of-file character (CHR(26)) is read, or no more input can be read from a given file.
- Rd‘simple type’
- PROCEDURE RdChar ( F : : File ) : CHAR;
- PROCEDURE RdBool ( F : : File ) : BOOLEAN;
- PROCEDURE RdShtlnt ( F : : File ) : SHORTINT;
- PROCEDURE Rdlnt ( F : : File ) : INTEGER;
- PROCEDURE RdLnglnt ( F : File ) : LONGINT;
- PROCEDURE RdShtCard( F : File ) : SHORTCARD
- PROCEDURE RdCard ( F : File ) : CARDINAL;
- PROCEDURE RdLngCard( F : File ) : LONGCARD;
- PROCEDURE RdShtHex ( F : File ) : SHORTCARD
- PROCEDURE RdHex ( F : : File ) : CARDINAL;
- PROCEDURE RdLngHex ( F : File ) : LONGCARD;
- PROCEDURE RdReal ( F : File ) : REAL;
- PROCEDURE RdLngReal( F : File ) : LONGREAL;
- The Rd‘simple type’ procedures all take a file handle, F, specifying the file from which to read. The procedures return a value of a ‘simple type’ as indicated by the declarations above.
- All procedures (except RdChar) call Rdltem to get a character sequence which is delimited by characters from the global set variable, Separators. This string is then converted to a value using one of the conversion procedures from the Str module (see “Conversion Procedures,” page 153).
- The procedures RdShtHex, RdHex and RdLngHex read cardinal values in hexadecimal format.
- The procedure RdBool returns TRUE if it reads the string ‘TRUE’ (but neither ‘true’ nor ‘True’), for all other input it returns FALSE.
- The syntax for valid REAL values can be found in Chapter 6.
- The global variable OK is set to FALSE if a value of the required type cannot be read, e.g. if the input has an illegal format or value.
- RdStr
- PROCEDURE RdStr (F: File; VAR V: ARRAY OF CHAR);
- RdStr reads a string from the file F and returns it in V. Characters are read until one of the following conditions are met:
- • the end-of-file character (CHR (26)) is read, in which case EOF is set to TRUE, and V is zero terminated
- • the carriage return character (CHR (13)) is read, in which case V is zero terminated
- • the string is full — that is, HIGH (V) +1 characters have been read, in which case V is not zero terminated
- Example:
- RdStr( QnFile, CurrQn);
- reads a string from the file associated with the handle QnFile, and assigns this string to the string variable CurrQn.
- Rdltem
- PROCEDURE Rdltem(F: File; VAR V: ARRAY OF CHAR);
- Rdltem reads a string (from the file F). The procedure stops reading when any character from the global set variable Separators is read. The string is returned in V.
- Example: Consider the following line in a file (with handle QnFile):
- Hello there, how are you?
- The call
- Rdltem( QnFile, CurrStr);
- would read only the word ‘Hello’ into the string variable CurrStr. Procedure RdStr, on the other hand, would read all five words.
- RdBin
- PROCEDURE RdBin( F : File;
- VAR Buf: ARRAY OF BYTE;
- Count : CARDINAL) : CARDINAL;
- RdBin reads a block of Count “raw” bytes from the file F, and returns this input in Buf. The procedure returns the number of bytes actually read.
- Example:
- VAR Code : ARRAY [ 0 .. 49] OF BYTE; NrRead : CARDINAL;
- NrRead : = RdBin( CodeFile, Code, 50);
- reads 50 bytes from the file with handle CodeFile, and stores these bytes in the array Code.
- Directory Handling
- ChDir
- PROCEDURE ChDir(Name: ARRAY OF CHAR);
- This procedure changes the current directory. Name specifies the new directory path and may include a drive name.
- Example:
- ChDir( "a:\jpi\src");
- switches you to the directory \JPI\SRC on drive A. If lOcheck is TRUE, then this procedure displays an error message if the specified path doesn’t exist.
- MkDir
- PROCEDURE MkDir(Name: ARRAY OF CHAR);
- This procedure creates a new subdirectory at the path specified by Name. If lOcheck is TRUE, then this procedure displays an error message if the specified directory can’t be created.
- This might happen because a subdirectory on the path for your procedure has not yet been created. It might also happen because there is already a file with the specified name in the specified directory.
- Example:
- MkDir( "zasu");
- creates a subdirectory named ZASU in the current directory.
- RmDir
- PROCEDURE RmDir(Name: ARRAY OF CHAR);
- This procedure removes the directory specified by Name from the directory structure.
- This directory must be empty. You cannot remove the cunent directory.
- Example:
- RmDir( "zasu");
- removes the subdirectory, ZASU, from the current directory.
- GetDir
- PROCEDURE GetDir ( Drive : SHORTCARD;
- VAR Name : ARRAY OF CHAR);
- GetDir returns the full path name, in Name, for the current directory on the drive specified by Drive (O=default,l=drive A, etc.).
- Example:
- GetDir( 3, HDCurrDir);
- returns the name of the current directory on drive C. The name is returned in the string HDCurrDir.
- ReadFirstEntry
- TYPE
- PathTail = ARRAY[0..12] OF CHAR;
- FileAttr = SET OF (readonly,hidden, system, volume,directory,archive);
- DirEntry = RECORD
- rsvd : ARRAY[O..2O] OF SHORTCARD; (* reserved *)
- attr : FileAttr;
- time : CARDINAL;
- date : CARDINAL;
- size : LONGCARD;
- name : PathTail;
- END;
- PROCEDURE ReadFirstEntry( DirName : ARRAY OF CHAR;
- Attr : FileAttr;
- VAR D : DirEntry) : BOOLEAN;
- This procedure searches a directory for a file that matches the string specified in DirName. The string DirName contains the drive, path and file name of the file to be found. The file name may contain wildcard characters (**’, *?’).
- The Attr parameter requires some explanation. If Attr is the empty set, then only normal file entries are found. (The same applies if the readonly and archive attributes are set.) If hidden files, system files or directory entries are to be taken into account, then the corresponding attribute must be set. Finally, if the volume attribute is set, then only the volume name is returned.
- If a matching entry is found ReadFirstEntry will return TRUE, and D will contain the directory entry for the first match.
- See also the procedure ReadNextEntry, which can be used to find subsequent matches.
- Examples:
- FoundEntry := ReadFirstEntry( "c:\com\*.,
- FileAttr{hidden,system,directory), Ent);
- will match all files in the directory c: \corn, and Ent will contain the first entry (if the function result is TRUE, that is, if any matches were found).
- FoundEntry:= ReadFirstEntry( "a:*.mod", FileAttr{), Ent);
- will match all normal files with the extension “mod” in the root directory on drive A. Ent will contain the first entry (if the function result is TRUE).
- ReadNextEntry
- PROCEDURE ReadNextEntry(VAR D: DirEntry) : BOOLEAN;
- This procedure works together with ReadFirstEntry. Procedure ReadNextEntry takes a directory entry, D, which is the result of a previous call to ReadFirstEntry or ReadNextEntry, and finds the next entry that matches the given specification (DirName). This procedure works only after ReadFirstEntry has already been called.
- Example:
- FoundEntry:= ReadFirstEntry( "a:*.mod", FileAttr{), Ent);
- FoundEntry:= ReadNext( Ent);
- will find the first two entries that match the string specified in ReadFirstEntry. After the calls, you will have information only about the second entry.
- MODULE Storage
- This section describes the storage handling functions, which allow you to allocate and deallocate blocks of memory dynamically on a heap. Programs that import the module Storage get a default heap, called the MainHeap, but other heaps can be defined.
- Global Variables in Storage
- TYPE
- HeapRecPtr = POINTER TO HeapRec;
- HeapRec = RECORD
- size : CARDINAL;
- next : HeapRecPtr;
- END;
- VAR
- MainHeap : HeapRecPtr;
- ClearOnAllocate : BOOLEAN;
- MainHeap is the predefined default main heap, and can be used in calls to procedures that use heaps other than the main one. ClearOnAllocate specifies whether procedure ALLOCATE zero-fills the allocated block of memory. ClearOnAllocate is by default FALSE (see also the (*$Z*) compiler directive in Chapter 7).
- Main Heap Procedures
- The procedures ALLOCATE, DEALLOCATE and Available all operate on the main heap, and therefore need no heap reference.
- ALLOCATE
- PROCEDURE ALLOCATE (VAR a: ADDRESS; size: CARDINAL);
- Allocates a block of size bytes from the main heap. The reference to the allocated block is returned in a. The block is zero filled if the global variable ClearOnEntry is TRUE. If the allocation does not succeed, the error message
- 'Heap overflow'
- is given and program execution terminates. The maximum size of a block that can be allocated by ALLOCATE is MAX ( CARDINAL) (65,535) bytes; larger blocks can be allocated by the general heap procedure HeapAllocate.
- Example:
- VAR HeapSrc : ADDRESS;
- ALLOCATE ( HeapSrc, 2000) ;
- allocates 2000 bytes from MainHeap (if available), and sets HeapSrc to reference these 2000 bytes.
- DEALLOCATE
- PROCEDURE DEALLOCATE (VAR a: ADDRESS; size: CARDINAL);
- Deallocates the memory block of size bytes given by the address a; a is then set to NIL. The deallocated block again becomes part of the main heap’s free storage.
- Example:
- VAR HeapSrc : ADDRESS;
- DEALLOCATE ( HeapSrc, 2000);
- deallocates 2000 bytes accessible through HeapSrc, sets HeapSrc to NIL, and returns the 2000 bytes to MainHeap.
- Available
- PROCEDURE Available(size : CARDINAL) : BOOLEAN;
- Returns TRUE if a block of size bytes can be allocated from the main heap.
- Example: If there are only 2000 bytes of heap space available, the call
- VAR outcome : BOOLEAN;
- outcome : = Available ( 3000);
- would return FALSE.
- General Heap Procedures
- The following procedures can apply to heaps other than MainHeap. For example, you might need to build several trees or other dynamic data structures in a program. A convenient way of distinguishing these trees is to keep them in separate heaps, which you can allocate and use by calling the following procedures. These procedures either require a HeapRecPtr as an argument or they return such a pointer.
- Whereas the main heap procedures used parameters representing bytes, the general heap procedures use paragraphs to specify block sizes.
- MakeHeap
- PROCEDURE MakeHeap(Source: CARDINAL; (* base segment of heap *) Size : CARDINAL (* size in paragraphs *) ) : HeapRecPtr;
- This procedure defines a new heap. Source specifies the storage segment where the new heap is located. This storage must have been allocated — for example, by a storage allocation procedure. Size is the size, in paragraphs (16 bytes), of the given storage. MakeHeap returns a pointer to the new heap. This pointer can subsequently be used in calls to the general heap procedures: HeapAllocate, HeapDeallocate, etc.
- Example:
- VAR TPort : HeapRecPtr;
- BaseSeg : CARDINAL;
- TPort :« MakeHeap ( BaseSeg, 200);
- defines a heap of 200 paragraphs (3200 bytes) in the base segment specified by BaseSeg. It’s assumed that you’ve already allocated storage in that segment — for example, through a call to ALLOCATE to “steal”’ storage from the main heap. The call to MakeHeap simply reserves (some of) that storage for the heap accessed through TPort.
- HeapAllocate
- PROCEDURE HeapAllocate
- (* source heap *) (* result *) (* size in paragraphs *)
- ( Source: HeapRecPtr;
- VAR A : ADDRESS;
- Size : CARDINAL);
- HeapAllocate allocates a block of 16 * Size bytes on the heap given by Source. A pointer to the allocated block is returned in A. If the allocation does not succeed, the error message 'Heap overflow' is given and program execution stops.
- Example:
- VAR HeapSrc : ADDRESS;
- TPort : HeapRecPtr;
- HeapAllocate ( TPort, HeapSrc, 50);
- allocates a memory block of 800 bytes (if available) from the heap defined by TPort.
- This storage will be accessible through HeapSrc.
- HeapDeallocate
- PROCEDURE HeapDeallocate
- (* source heap *)
- (* block to deallocate *) (* size in paragraphs *)
- ( Source: HeapRecPtr;
- VAR A : ADDRESS;
- Size : CARDINAL);
- This procedure deallocates the memory block of 16 * Size bytes starting at the address A. This storage is from the heap specified by Source. After the deallocation, A is set to NIL. The deallocated block becomes part of the (Source) heap’s free storage. Note that you must always deallocate a block into the heap from which it was allocated.
- Example:
- VAR HeapSrc : ADDRESS;
- TPort : HeapRecPtr;
- HeapDeallocate( TPort, HeapSrc, 50);
- deallocates 800 bytes of storage accessible through HeapSrc, sets HeapSrc to NIL, and returns the freed memory to the the heap defined by TPort.
- Heap Aval I
- PROCEDURE HeapAvail(Source : HeapRecPtr) : CARDINAL;
- HeapAvail returns the size, in paragraphs of the largest block available for allocation from the heap Source.
- Example:
- VAR result : CARDINAL;
- TPort : HeapRecPtr;
- result := HeapAvail ( TPort);
- After the assignment in the example, result represents the largest block of storage you can allocate from the heap defined by TPort.
- HeapTotalAvail
- PROCEDURE HeapTotalAvail(Source : HeapRecPtr) : CARDINAL;
- Returns the size, in paragraphs, of the total amount of storage available for allocation from the heap Source. This storage is all in one block only if the value returned is equal to the value returned by a call to HeapAvail.
- Example:
- VAR Res : CARDINAL;
- Res : = HeapTotalAvail( MainHeap);
- will return the amount of available storage at the top of memory.
- HeapChangeSize
- PROCEDURE HeapChangeSize
- (* source heap *)
- (* block to change *)
- (* old size of block *)
- (* new size in paragraphs*)
- ( Source : HeapRecPtr;
- VAR A : ADDRESS; OldSize, NewSize : CARDINAL ) ;
- This procedure changes the size of the memory block specified by A. OldSize and NewSize are the sizes, in paragraphs, of the existing block and the desired new block. Source indicates the heap on which the block is allocated. HeapChangeSize avoids any copying of the block if possible. If such a move is necessary, the procedure finds a new area of the heap for the desired block, which causes A to change.
- Example:
- VAR TPort : HeapRecPtr; HeapSrc : ADDRESS;
- HeapChangeSize( TPort, HeapSrc, 200, 400);
- doubles the size of the memory block accessible through HeapSrc. This procedure calls HeapAllocate, so you will get a
- 'Heap overflow'
- error message is there is not enough available storage on the heap specified by TPort.
- HeapChangeAlloc
- PROCEDURE HeapChangeAlloc
- ( Source : HeapRecPtr;
- A : ADDRESS;
- OldSize,
- NewSize : ) : BOOLEAN,
- CARDINAL
- (* source heap *) (* block to change *) (* old size of block *) (* new size of block *) (* If successful *)
- This procedure tries to change the size of the block A, allocated on the heap Source — but only if this change does not require relocating the block. If the resizing is possible, the procedure carries it out and returns TRUE; otherwise the block is not resized, and the procedure returns FALSE. Thus, HeapChangeAlloc never moves a block. Note that only expansions can fail.
- Example:
- VAR TPort : HeapRecPtr;
- HeapSrc : ADDRESS;
- Bigger : BOOLEAN;
- Bigger : = HeapChangeAlloc( TPort, HeapSrc, 400, 200);
- sets Bigger to TRUE, since the new block is smaller than the original, and size reduction never causes block relocation.
- MODULE SYSTEM
- The module SYSTEM plays a special role in the TopSpeed Modula-2 compiler, in that it contains compiler dependent features (such as Ofs and Seg). In fact some of the procedures are built-in to the compiler. Fbr this reason, the module is also called a pseudo-module.
- SYSTEM also contains data types that are of interest in this particular implementation. For example, the Registers type is used to access the 80x86 registers when making
- DOS calls and interrupts (see “DOS Procedures,” page 164), because access to the individual machine registers is necessary when making such calls.
- The type PROCESS is explained below.
- TYPE
- PROCESS = ADDRESS;
- Registers = RECORD
- CASE : BOOLEAN OF
- • TRUE : AX, BX, CX, DX, BP, SI, DI, DS, ES: CARDINAL;
- Flags : BITSET;
- • FALSE : AL, AH, BL, BH, CL, CH, DL, DH : SHORTCARD;
- END;
- END;
- CONST
- CarryFlag = 0;
- ZeroFlag = 6;
- VAR
- HeapBase : CARDINAL ; (* Base segment of heap *)
- Low-level Processes
- Since the IBM PC/AT and compatibles are single-processor computers, true concurrent processes cannot be implemented. However processes can be implemented by means of coroutines.
- A coroutine is a sequential program that can be suspended by transferring execution to another coroutine (which will resume from its state when last suspended). When a coroutine is suspended its current state is saved, so it can resume execution later when another coroutine transfers execution back to it. In the following we will use the term process instead of coroutine.
- Module Priorities in TopSpeed Modula-2 Module priorities control the handling of hardware interrupts. The priorities are based on the hardware interrupt controller in the PC/AT computer. The priority is interpreted as a mask (BITSET) that enables and disables individual interrupts. An interrupt is disabled if its corresponding bit in the mask is 1. See the Technical Reference Manual for your machine for information about its interrupt controller — in order to use these priorities effectively.
- Priority is defined for an entire module, and holds for any procedures defined in the module. The priority is in effect for the entire module, or until replaced by a new module with different priority.
- On entry to a block (a PROCEDURE body or a MODULE body), the priority mask in the interrupt controller and the priority mask for the block are logically or-ed together. On exit from the block the mask in the interrupt controller is restored to the contents it had on entry to the block.
- The AT and the PC differ in that the AT has two interrupt controllers and the PC has only one. For the AT, the full 16 bits of the priority mask are used; the 8 lower bits are used to set the mask in the primary interrupt controller and the upper 8 bit are used to set the slave controller. In case of the PC only the lower 8 bits are used to set the mask in the interrupt controller.
- The masks in the interrupt controller are considered to be a part of the state of a process, so these are saved and restored on TRANSFER and IOTRANSFER operations (see these procedures below). If an IOTRANSFER is associated with a hardware interrupt handled by an interrupt controller, a non-specific End-Of-Interrupt is issued.
- The interrupts requests (IRQs) handled by the hardware are vectored through the DOS interrupt vectors 08H to OFH for the primary controller and 7 OH to 77H for the slave controller. These correspond to IRQ 0 - IRQ 15.
- Example of an interrupt handler:
- MODULE T;
- FROM SYSTEM IMPORT NEWPROCESS, IOTRANSFER, TRANSFER, Currentpriority, NewPriority, ADDRESS;
- VAR IntProc : ADDRESS;
- MODULE Int[CARDINAL({3})]; (* IRQ 3 is disabled *)
- IMPORT IOTRANSFER;
- EXPORT IntHandler;
- PROCEDURE IntHandler;
- BEGIN
- IOTRANSFER( . . ., OBH); (* IOTRANSFER on IRQ 3 (Int. OBH) *)
- END IntHandler;
- END Int;
- BEGIN
- NEWPROCESS( ..., IntProc );
- TRANSFER( ..., IntProc );
- NewPriority(CARDINAL(BITSET(Currentpriority())-{3}));
- (* enable IRQ 3 *)
- END T.
- NEWPROCESS
- PROCEDURE NEWPROCESS ( P : PROC;
- A : ADDRESS;
- S : CARDINAL;
- VAR Pl: ADDRESS);
- This procedure creates a new process. P is a parameterless procedure which will constitute the new process. A is a pointer to the workspace for the process. The workspace is needed for local variables and to store the state of the process when it is suspended. S is the size in bytes of this workspace, and should be at least IK. NEWPROCESS returns a reference to the newly created process in Pl. Note that NEWPROCESS only prepares the process for execution, it does not cause it to begin execution.
- Example:
- VAR Newp : PROC;
- ProcAddr, ProcRef : ADDRESS;
- NEWPROCESS ( NewP, ProcAddr, 2000, ProcRef);
- creates a new process. The new process is accessed through ProcRef, and its workspace starts at ProcAddr. The workspace is 2000 bytes. After this call, the process ProcRef is accessible but not active.
- TRANSFER
- PROCEDURE TRANSFER(VAR P1,P2 : ADDRESS);
- This procedure transfers execution from one process to another. The current process is suspended and assigned to Pl. Then process P2 is resumed (at its current point of suspension).
- P2 must be the result of a previous call to NEWPROCESS or TRANSFER. The process Pl will be resumed later, when another process transfers execution back to it.
- Note that assignment to Pl occurs after identification of the new process P2. This means that the actual parameters for the processes can be the same variable.
- This kind of transfer is called synchronous transfer, as opposed to the asynchronous transfer which is done by the procedure IOTRANSFER.
- Example:
- VAR ProclRef, Proc2Ref : ADDRESS;
- TRANSFER ( ProclRef, Proc2Ref);
- suspends the current process and assigns it to ProclRef, and then activates the process references by Proc2Ref — at whatever point that process was suspended.
- IOTRANSFER
- PROCEDURE IOTRANSFER(VAR Pl,P2: ADDRESS; I: CARDINAL);
- IOTRANSFER is an interrupt driven (or asynchronous) transfer. It associates the current process with the interrupt number specified by I. The procedure then suspends the current process and assigns it to Pl and activates the process specified by P2.
- When the processor receives an interrupt it checks if that interrupt has been associated with a process. If this is the case, the current process is suspended and assigned to P2, and the (suspended) process Pl is resumed.
- Once an interrupt and a resultant transfer have occurred, the interrupt is no longer associated with that process.
- If there are more processes associated with the interrupt I, they will be treated in a stack like manner. That is, the last process associated with I will be activated when the first interrupt I occurs, the second to last associated process will be activated when the next interrupt I occurs, etc.
- Example:
- VAR PRefl, PRef2 : ADDRESS;
- IOTRANSFER( PRefl, PRef2, OBH);
- associates the current process with interrupt OBH (IRQ 3), and assigns this process to PRefl. The procedure then activates the process specified by PRef2. If an interrupt OBH is received, the current process wil be suspended and the process assigned to PRefl will be reactivated — because that process had been associated with IRQ3.
- InterruptRegisters
- PROCEDURE InterruptRegisters(P: ADDRESS) : ADDRESS;
- InterruptRegisters can be used to access the contents of the registers when an interrupt has taken place. It is only meaningful to call the procedure after an IOTRANSFER to the process P has taken place. InterruptRegisters returns a pointer to a record (on the stack) with the following layout:
- TYPE
- ExtendedRegisters
- = RECORD
- r : Registers;
- IP : CARDINAL;
- CS : CARDINAL;
- RetFlags : CARDINAL;
- END;
- (* as defined above *) (* instruction ptr *) (* code segment *)
- Example:
- VAR Reginfo, ProcRef : ADDRESS;
- Reginfo := InterruptRegisters( ProcRef);
- If the preceding statement follows a call to IOTRANSFER with an interrupt as a parameter, the call returns a pointer to the state of the process after the interrupt.
- CurrentProcess
- PROCEDURE CurrentProcess() : ADDRESS;
- This procedure returns a reference to the current process.
- Example:
- VAR ProcAddr : ADDRESS;
- ProcAddr := CurrentProcess ();
- Currentpriority
- PROCEDURE Currentpriority() : CARDINAL;
- This procedure returns the (MODULE) priority of the current process.
- Example:
- VAR Prior : CARDINAL;
- Prior := Currentpriority () ;
- NewPriority
- PROCEDURE NewPriority(PR : CARDINAL);
- This process gives the the current process a new (MODULE) priority specified by PR.
- (See description of priorities above.)
- Example:
- NewPriority( (3));
- gives the current process a priority specified by the BITSET, {3}.
- Listen
- PROCEDURE Listen(Mask: BITSET);
- Listen temporarily enables the interrupts specified by Mask. This allows pending interrupts to be accepted. The procedure then restores the interrupt mask to its previous state.
- Example:
- Listen( {3});
- temporarily enables the interrupt specified by bit 3.
- Miscellaneous
- The compiler generates inline code for all the procedures in this section.
- DI
- PROCEDURE DI();
- DI disables hardware interrupts. This is useful when accessing data which is shared among several processes.
- El
- PROCEDURE EI();
- El enables hardware interrupts.
- Ofs
- PROCEDURE Ofs ( A: WORD) : CARDINAL;
- Ofs returns the offset part of the address of A. Note that addresses consist of an offset part (ofs) and a segment part (seg), and the physical address is calculated as seg * 16 + ofs.
- Please note that certain values don’t have an offset — for example, simple constants and simple expressions do not have memory locations.
- Example:
- VAR TestSpot : LONGCARD;
- Offset : CARDINAL;
- Offset := Ofs( TestSpot);
- returns the offset portion of the address at which TestSpot is stored.
- Seg
- PROCEDURE Seg( A: WORD) : CARDINAL;
- Seg returns the segment part of the address of A. Please note that the segment of an expression returns the stack segment. Simple constants do not have a segment.
- Example:
- VAR Testspot : LONGCARD;
- Segmt : CARDINAL;
- Segmt : = Ofs( TestSpot);
- returns the segment portion of the address at which TestSpot is stored.
- Out
- PROCEDURE Out(P: CARDINAL; V: SHORTCARD);
- This procedure outputs the value V to the hardware port specified by P.
- Example:
- Out( 4, 111);
- sends ASCII character 111 (‘o’) to hardware port 4 (printer port).
- In
- PROCEDURE In(P: CARDINAL) : SHORTCARD;
- In Returns a value from the hardware port specified by P.
- Example:
- VAR Vai : SHORTCARD;
- Vai := In( 4);
- reads a value from port 4 (printer port), and assignes the value to Vai.
- GetFlags
- PROCEDURE GetFlags() : CARDINAL;
- This procedure returns the contents of the processor’s flags register.
- Example:
- VAR FSet : CARDINAL;
- FSet := GetFlags ();
- stores the current flags settings in FSet.
- SetFlags
- PROCEDURE SetFlags(F: CARDINAL);
- This procedure sets the processor’s flags register to the value specified by F. Procedures SetFlags and GetFlags are especially useful when disabling and enabling interrupts — to save and restore previous interrupt flag values.
- Example:
- VAR FSet : CARDINAL;
- SetFlags ( FSet);
- stores the value of FSet as the new flags register settings.
- The GetFlags and SetFlags can be used together to help in writing critical code, which cannot be interrupted. First, call GetFlags just before the critical code, to save the current flags values. Then call DI to disable interrupts during the critical code. After the code, call El to enable interrupts again. Finally, call SetFlags to restore the flags register to its values before the critical code. The following exmaple illustrates this:
- VAR CurrFlags : CARDINAL;
- CurrFlags := GetFlags ();
- DI
- ... (* critical code goes here *)
- El
- SetFlags( CurrFlags);
- MODULE MATHLIB
- The procedures in this module perform common mathematical calculations. In addition, the module contains some 8087 specific procedures.
- Error Handling
- In the case of invalid arguments, some of the procedures call the error handling functions defined below:
- VAR
- MathError : PROCEDURE (LONGREAL, ARRAY OF CHAR);
- MathError2 : PROCEDURE (LONGREAL, LONGREAL, ARRAY OF CHAR);
- Note that the error procedures are procedure variables, which means that they can be replaced by user defined procedures. By default they are assigned to the procedures MathError and MathError2 in the module Lib (see “Error Handling,” page 169).
- Error procedure called by
- MathError Sin, Cos, Tan, Asin, Acos, Log, LoglO and Sqrt.
- MathError2 ATan2
- Trigonometric functions
- PROCEDURE Sin (A : LONGREAL) : LONGREAL;
- PROCEDURE Cos (A : LONGREAL) : LONGREAL;
- PROCEDURE Tan(A : LONGREAL) : LONGREAL;
- PROCEDURE ASin (A : LONGREAL) : LONGREAL;
- PROCEDURE ACos (A : LONGREAL) : LONGREAL;
- PROCEDURE Alan(A : LONGREAL) : LONGREAL;
- PROCEDURE ATan2(X,Y : LONGREAL) : LONGREAL;
- Sin, Cos and Tan implement the corresponding mathematical functions. The argument A to these procedures is specified in radians. Sin and Cos return values in the range -1 to 1.
- ASin, ACos and ATan return the arc sine, arc cosine and arc tangent, respectively. The argument A to ASin and ACos must be in the range -1 to 1. ASin and ATan return values in the range -tt/2 to tt/2. ACos returns values in the range 0 to tt.
- ATan2 returns the arc tangent of Y/X. The result is in the range — tt to tv
- Example:
- CONST PIOver6 = .5235988; (* pi/6 == 30 degrees *)
- VAR asres, sres, acres, cres, atres, atres2, tres : LONGREAL;
- sres := Sin( PI0ver6) ; (* sres = 0.5 *)
- cres := Cos( PI0ver6) ; tres := Tan( PI0ver6); asres : = ASin( sres); acres :■ ACos( cres); atres : = ATan( tres); (* cres = 0.866 *)
- (* tres = 0.577 *)
- (* asres = 0.5236 *)
- (* acres = 0.5236 *)
- (* atres = 0.5236 *)
- atres2 := Atan2( sres, cres); (* atres2 = 1.047 *)
- Hyperbolic Functions
- PROCEDURE SinH(A : LONGREAL) : LONGREAL;
- PROCEDURE CosH(A : LONGREAL) : LONGREAL;
- PROCEDURE TanH(A : LONGREAL) : LONGREAL;
- These procedures return the hyperbolic sine, hyperbolic cosine, and hyperbolic tangent, respectively, of the given argument A.
- Example:
- VAR sres, cres, tres : LONGREAL;
- sres : = SinH( 0.5); (* 8res = 0.5478 *)
- cres : = CosH( 0.5);
- tres : = TanH( 0.5); (* cres = 1.1402 *)
- (* tres = 0.4805 *)
- Log
- PROCEDURE Log (A : LONGREAL) : LONGREAL;
- Log returns the natural logarithm (log to base e) of A. The argument must be positive.
- Example:
- VAR Ires : LONGREAL;
- Ires := Log( 2); (*
- Ires := Log( 1); (*
- Ires := Log( 0.5); (* Ires = 0.6931 *)
- Ires = 0.0 *)
- Ires = -0.6931 *)
- Log10
- PROCEDURE LoglO(A : LONGREAL) : LONGREAL;
- LoglO returns the logarithm (base 10) of A. The argument must be positive.
- Example:
- VAR Ires : LONGREAL;
- Ires := LoglO( 2); (* Ires = 0.3010 *)
- Ires := LoglO( 1); (* Ires = 0.0 *)
- Ires := LoglO( 0.5); (* Ires = -0.3010 *)
- Pow
- PROCEDURE Pow(X,Y : LONGREAL) : LONGREAL;
- Returns X raised to the power Y.
- Example:
- VAR pres : LONGREAL;
- pres := Pow( 2.5, 3.5); (* pres = 24.705 *)
- pres := Pow( 2.5, -3.5); (* pres = 0.04048 *)
- Exp
- PROCEDURE Exp (A : LONGREAL) : LONGREAL;
- Returns the result of raising e to the power A. (This function is the inverse of Log.)
- Example:
- VAR eres : LONGREAL;
- eres := Exp( 3.5); (* eres = 33.115 *)
- eres := Exp( -3.5); (* eres = 0.0302 *)
- Mod
- PROCEDURE Mod(X,Y: LONGREAL) : LONGREAL;
- Returns the remainder after “removing” Y from X as often as possible. More specifically, the function returns the result of evaluating the following expression:
- X - Y * [ABS (X / Y) j
- where [..] is the floor function, and represents the largest integer less than or equal to the expression between the bracket — in this case, the quotient from X/Y. The absolute value is used to make sure the integer returned by the floor function is rounded toward 0. (For example, floor( -12.5) would be -13, but in the formula above, the result would be 12.)
- Examples:
- VAR mres : LONGREAL;
- mres := Mod( 0.3, 0.65);
- (* mres = 0.3 *)
- (* mres = -1.5 *)
- (* mres = 4.0 *)
- mres := Mod( -73.0, 6.5);
- mres := Mod( 23.5, 6.5);
- Rexp
- PROCEDURE Rexp(VAR I: INTEGER;A: LONGREAL) : LONGREAL;
- Rexp splits the value A into its exponent and mantissa parts. The exponent (for base two) is returned in I, and the mantissa is the function’s return value.
- Example:
- VAR Exponent : INTEGER; result : LONGREAL;
- result := Rexp( Exponent, 79.37);
- After this call, result = 1.24016 and Exponent = 6. To check this, multiply 1.24016 by 64 (26).
- Sqrt
- PROCEDURE Sqrt (A: LONGREAL) : LONGREAL;
- This procedure returns the square root of A. The argument must be positive or zero.
- Example:
- VAR sres : LONGREAL;
- sres := Sqrt( 3.5); (* sres = 1.8708 *)
- sres := Sqrt ( 237.68); (* sres = 15.4169 *)
- Conversion Procedures
- The two procedures below convert the integer part of real values to binary coded decimals and vice versa. Binary coded decimals are represented by the type Packed- Bed:
- TYPE PackedBcd = ARRAY [0..9] OF SHORTCARD;
- Two decimal digits are packed into each element of the array. Element number 9 is the sign.
- LongToBcd
- PROCEDURE LongToBcd(A: LONGREAL) : PackedBcd;
- This procedure returns the value A in a PackedBcd representation. A is rounded to the nearest integer.
- Example: If BcdVal is a variable of type PackedBcd, then
- BcdVal := LongToBcd(-12345.67);
- puts the following values in the cels of BcdVal:
- element : 9 87654321 0
- value in hex : 80 0 0 0 0 0 0 1 23 46
- BcdToLong
- PROCEDURE BcdToLong(A: PackedBcd) : LONGREAL;
- Returns the LONGREAL representation of the PackedBcd value given by A.
- Example: If BcdVal has the same cell values as in the example for procedure
- LongToBcd, then
- Result : = BcdToLong ( BcdVal);
- assigns the value -12346.0 to Result.
- 8087 Procedures
- For a description of the 8087 control word and environment, consult your 8087 documentation.
- LoadControlWord
- PROCEDURE LoadControlWord(C: BITSET);
- This loads the 8087 coprocessor with the control word specified by C.
- Example:
- LoadControlWord( {0, 6..8, 13});
- would load the coporcessor with a control word having five bits turned on.
- StoreControlWord
- PROCEDURE StoreControlWord() : BITSET;
- StoreControlWord returns the 8087’s control word.
- Example:
- VAR bst : BITSET;
- bst := StoreControlWord ();
- returns the current control word and assigns this BITSET to bst.
- ClearExceptions
- PROCEDURE ClearExceptions();
- This procedure clears the 8087’s exception flags, the interrupt request flag and the busy flag in the status word.
- StoreEn viron merit
- TYPE Environment = RECORD Controlword : BITSET; StatusWord : BITSET; TagWord : BITSET; IP : CARDINAL;
- Opcode : CARDINAL; DataPointer : CARDINAL; R80287 : CARDINAL;
- END;
- PROCEDURE StoreEnvironment() : Environment;
- This returns the 8087 processor’s current environment as specified by the record type Environment. See also the 8087 documentation.
- Example:
- VAR CurrEnv : Environment;
- CurrEnv : = StoreEnvironment ();
- After the call to StoreEnvironment, CurrEnv contains the environment setting in the 8087 at the time of the call.
- MODULE FloatExc
- This module enables floating point exception handling. If an 8087 exception occurs, program execution will stop (by a call to FatalError), and a message of the following form is given:
- [AAAAA-OOOO] Float Error : 'message'
- The address AAAAA is an absolute address in hexadecimal. OOOO is the offset from the start of the program. Thus, the procedure in error can be found in the mapfile: first you need to normalize OOOO to get ssss: oooo, then find the largest segment value SSSS in the map file which is less than or equal to ssss; now subtract ssss from SSSS to get dddd. To convert the segment difference dddd to an offset f f f f, multiply by 16. The address you should look for in the map is:
- SSSS:ffff+oooo
- Easy, isn’t it!
- EnableException Handling
- PROCEDURE EnableExceptionHandling;
- This procedure enables 8087 exception handling.
- DisableExceptionHandling
- PROCEDURE DisableExceptionHandling;
- This procedure disables 8087 exception handling.
- MODULE ProcTrace
- This module enables you to trace procedure calls in your programs. You can also monitor the values of specified variables.
- The module contains two procedure variables, Entry and Exit, which are used if you specify the (*$Q+*) directive. When this directive is specified, these procedures are called when your program enters or exits a procedure being traced.
- If you turn procedure tracing on — by calling the Install procedure in ProcTrace — messages will be displayed upon entry to and exit from all procedures to which the (*$Q+*) directive applies.
- Monitor
- PROCEDURE Monitor(VAR W: WORD);
- (* Monitor variable W *)
- This procedure lets you monitor the value of a specified variable at a specific point in your program. The procedure takes a WORD parameter. When called, Monitor changes two global values delcared in PROCTRACE.DEF:
- MonWrd This WORD variable contains the value of the variable being monitored.
- MonAdr This ADDRESS variable contains the location of the variable being
- monitored.
- Example:
- VAR MyVal : INTEGER;
- MyVal := -2345;
- Monitor( WORD ( MyVal)); (* check value of MyVal *)
- Wrlnt ( INTEGER( MonWrd), 10); (* display current value of MonWrd, *)
- (* which = -2345 *)
- At the call to Monitor, the variable MonWrd is assigned the current value of MyVal, and the address of MyVal is stored in MonAdr.
- Check
- PROCEDURE Check(S: ARRAY OF CHAR); (* check current monitored variable *)
- This procedure checks the value of the variable currently being monitored, to determine whether its value has changed since the last time Monitor was called. If so, the procedure prints a message, and assigns the new value to MonWrd.
- Example:
- VAR MyVal : INTEGER;
- MyVal := -2345;
- Monitor( WORD( MyVal)); Wrlnt( INTEGER( MonWrd)
- (* check value of MyVal *)
- 10); (* display current value of MonWrd, *) (* which = -2345 *)
- MyVal := 2345; (* change value of the variable being monitored *)
- Check( 'MyVal');
- Wrlnt( INTEGER( MonWrd), 10); (* display current value of MonWrd, *) (* which has been updated to 2345 '*)
- Get_Name
- PROCEDURE Get_Name() : Name; (* returns name of current procedure *)
- This procedure returns the name of the procedure executing when Get_Name is called. You must call ProcTrace. Install before calling this procedure, and you must have the (*$Q+*) directive set in order for this procedure to work properly.
- Example: In the prog3 case study from Chapter 4 (see page 20), the following
- statement in the body of PlayScale produces the output below it.
- WrStr( Get_Name()); WrLn;
- (* output from calls in PlayScale *)
- Entering ProcTrace reading MAP-file...
- prog3$PlayScale
- prog3$PlayScale
- This output illustrates the TopSpeed Modula-2 nameing convention: module name (prog3, followed by delimiter (here, $, indicating a FAR call), followed by procedure name (PlayScale).
- GetCsIp
- PROCEDURE GetCsIp () : ADDRESS;
- This proceudre returns the current code segment and instruction pointer in an ADDRESS variable.
- Example:
- VAR CurrLoc : ADDRESS;
- CurrLoc := GetCsIp ();
- Install
- PROCEDURE Install;
- (* Install procedure-trace traps *)
- This procedure installs the traps needed to trace program execution and procedure calls. This procedure must be installed before any of the other procedure tracing routines is called.
- MODULE Process
- The procedures in this module handle “concurrent” processes. TopSpeed Modula-2 is implemented on a single processor computer, so processes share the processor’s time by means of time-slicing.
- Other (more low-level) procedures relating to processes can be found in the module SYSTEM, see “Low Level Processes,” page 203.
- Scheduler
- The following procedures let you control the time-sliced scheduler, which will control the sequence in which processes are allocated time-slices for their execution. An example at the end of the discussion of the Process module shows how these procedures are used.
- Startscheduler
- PROCEDURE Startscheduler;
- This procedure starts the time-sliced scheduler. If the scheduler is already active this call has no effect.
- StopScheduler
- PROCEDURE StopScheduler;
- This stops the time sliced scheduler. Note that SEND and WAIT operations still function when the scheduler is stopped (see “Signals” below).
- StartProcess
- PROCEDURE StartProcess(P: PROC; N: CARDINAL; Pr: CARDINAL);
- Creates a new process which is specified by the procedure P. The process will be allocated a workspace of N bytes (N should be at least IK). Each process has a priority (not to be confused with MODULE priority). Pr is the priority of the process, and should be greater than zero. If Pr is greater than or equal to the priority of the cunent process, then the newly created process will become active.
- Example:
- StartProcess( NewProc, 4096, 2);
- creates a new process, specified by procedure NewProc. This prcess is allocated 4096 bytes, and has priority 2.
- Signals
- Processes can communicate in two different ways: either via global shared variables, or via signals. Signals are used for synchronization among processes.
- Apart from initialization, the following operations can be done on signals: SEND, WAIT, Notify and Awaited. A signal consists of two entities: a counter and a queue. The counter is used to determine whether any processes are waiting for the signal or whether there are signals waiting for processes to use them; the queue is used to determine the order in which any waiting processes are activated.
- Init
- TYPE SIGNAL;
- PROCEDURE Init(VAR s: SIGNAL);
- Initializes the signal s — that is, sets its counter to zero and its queue to empty. A SIGNAL is defined as a pointer to a record containing counter and queue information. See the implementation file, PROCESS .MOD, for details.
- Example:
- VAR MySignal : SIGNAL;
- Init( MySignal);
- initializes the counter and queue for MySignal.
- SEND
- PROCEDURE SEND(s: SIGNAL);
- A call to SEND with s as argument will cause the first process waiting for s to become active. If no processes are waiting, the call will be queued.
- The SEND operation works by incrementing the counter associated with s. If the counter is less than or equal to zero, then at least one process is waiting for s and the first one in the queue will become ready for execution. This process will also start execution if its priority is greater than or equal to the priority of the current process.
- Example:
- VAR KeyReady : SIGNAL;
- SEND( KeyReady);
- causes the first process in the queue waiting for a KeyReady signal to become active, or causes the signal to be queued if no process is waiting for the signal.
- WAIT
- PROCEDURE WAIT(s: SIGNAL);
- A call to WAIT causes the calling process to wait for a corresponding SEND unless the signal s has previously queued SEND operations — that is, unless the counter for s is greater than zero.
- The WAIT procedure decrements the counter associated with s. If the counter is less than zero, it means that the calling process has to wait for a corresponding SEND to s, and another process will be activated. If the counter is greater than or equal to zero then the calling process will continue.
- Example:
- VAR KeyReady : SIGNAL;
- WAIT( KeyReady);
- causes the sending process to wait for a SEND with KeyReady as its argument, unless previous SEND operations have already been queued for KeyReady.
- Notify
- PROCEDURE Notify(s: SIGNAL);
- Notify causes a task waiting on signal s to be scheduled when possible, for example, at the next time-slice. If no process is waiting for s, the call has no effect. This call does not cause rescheduling, so it may be used by an interrupt handler (see Chapter 7) to safely notify another process of an event’s occurrence.
- Example:
- VAR MySignal : SIGNAL;
- Notify( MySignal);
- causes a task waiting for MySignal to be scheduled for activation.
- Awaited
- PROCEDURE Awaited(s: SIGNAL): BOOLEAN;
- This procedure returns TRUE if any process is waiting on the signal s — that is, if the counter associated with s is negative).
- Example:
- VAR MySignal : SIGNAL;
- IF Awaited( MySignal) THEN
- END;
- Miscellaneous
- The following procedures enable you to control how a particular process fits into the time-slice scheme. You can use these procedures to keep a process from being scheduled as well as from being descheduled.
- Delay
- PROCEDURE Delay(t : CARDINAL);
- This delays the current process for at least t timeslices. A timeslice is approximately 1/18 second . If t is zero, rescheduling takes place without a delay, allowing another process with the same or higher priority to become active.
- Example:
- Delay( 54);
- delays the current process for about 3 seconds.
- Lock
- PROCEDURE Lock;
- Lock prevents the current process from being descheduled by time-slicing, until a call to Unlock. This is useful when a process is accessing data which is shared among several processes. Calls to Lock may be nested, but must always be paired with calls to UnLock.
- Unlock
- PROCEDURE Unlock;
- Unlock allows time-slice rescheduling, and must always be paired with a Lock call. The current process will be descheduled if there is a ready process with the same or higher priority.
- Example: A keyboard process.
- MODULE KBP;
- IMPORT Process,10;
- VAR (*$W+*)
- KBbuff : ARRAY[0..1023] OF CHAR; (* cyclic buffer *)
- KBhead : CARDINAL;
- KBtail : CARDINAL;
- KeyReady : Process.SIGNAL;
- (*$W=*)
- PROCEDURE KBProcess; VAR k : CHAR; p : CARDINAL;
- BEGIN LOOP
- Process.Lock; (* DOS and shared variables are used *)
- IF IO.KeyPressed() THEN k := I0.RdKey(); p := (KBhead+1)MOD SIZE(KBbuff); IF p <> KBtail THEN
- KBbuff[KBhead] := k; KBhead := p;
- END;
- Process.Unlock;
- IF Process.Awaited(KeyReady) THEN Process.SEND(KeyReady) END;
- ELSE
- Process.Unlock;
- END;
- END;
- END KBProcess;
- PROCEDURE GetKeyO : CHAR;
- VAR k : CHAR;
- BEGIN LOOP
- Process.Lock; (* global shared variables are used *) IF KBtailOKBhead THEN k := KBbuff[KBtail];
- KBtail := (KBtail+1)MOD SIZE(KBbuff);
- Process.Unlock;
- RETURN k;
- END;
- Process.Unlock;
- Process.WAIT(KeyReady) ; END;
- END GetKey;
- PROCEDURE InitKBProcess;
- BEGIN
- KBhead : = 0;
- KBtail := 0;
- Process.Init(KeyReady) ;
- Process.StartProcess(KBProcess, 1000,1);
- Process.Startscheduler;
- END InitKBProcess;
- VAR c : CHAR;
- BEGIN
- InitKBProcess;
- LOOP
- c := GetKeyO;
- Process.Lock; (* because IO.WrChar calls DOS *) IO.WrChar(c);
- Process.Unlock;
- IF c=CHR(27) THEN EXIT END;
- END;
- END KBP.
- MODULE Graph
- The module Graph implements basic graphics for IBM PCs and true compatibles. The module makes it possible to use TopSpeed Modula-2 for doing graphics on several commonly available graphics boards: CGA, EGA, VGA, Hercules, and the board used in AT&T and Olivetti computers.
- In graphics mode, the screen resolution will depend on the graphics board you are using. Certain features are the same, regardless of graphics board. For example, the upper left hand comer of the screen is coordinate 0, 0. The X coordinates go to the right from 0..N, where N is one less than the horizontal resolution possible with your graphics board; the Y coordinates go downwards from 0..M, where M depends on the vertical resolution of the graphics board. Any attempt to draw outside these coordinates is ignored.
- Global Constants
- The following declarations provide the data structures and the procedures used to do graphics using various boards.
- TYPE
- PlotProc = PROCEDURE ((* x *) CARDINAL,(* y *)CARDINAL,(* c *)CARDINAL);
- PointProc = PROCEDURE ((* x *) CARDINAL,(* y *)CARDINAL) : CARDINAL ;
- HLineProc = PROCEDURE ( (* X *) CARDINAL, (* y *)CARDINAL, (* x2 *) CARDINAL,
- (* FillColor *)CARDINAL);
- VAR
- Width : CARDINAL ; (* X values are 0..Width-1 *)
- Depth : CARDINAL ; (* y values are 0..Depth-1 *)
- NumColor : CARDINAL ; (* Colors are 0..NumColor-1 *)
- (*
- procedure variables for device dependent routines *)
- GraphMode,TextMode Plot
- Point
- HLine
- : PROC ;
- : PlotProc ;
- : PointProc ;
- : HLineProc ;
- The following declarations contain procedures and constants, defined specifically for each graphics board supported. When the program is initialized to use a particular board, the appropriate declarations from the following collection are used.
- (*
- Device specific constants and routines
- equivalent to the variables Width, Depth and NumColors *)
- PROCEDURE CGAGraphMode;
- PROCEDURE CGATextMode;
- PROCEDURE CGAPlot(x,y:CARDINAL;c:CARDINAL) ;
- PROCEDURE CGAPoint(x,y:CARDINAL) : CARDINAL;
- PROCEDURE CGAHLine ( x,y,x2 : CARDINAL; c:CARDINAL );
- PROCEDURE EGAGraphMode;
- PROCEDURE EGAPlot( x,y,c : CARDINAL);
- PROCEDURE EGAPoint(x,y:CARDINAL) : CARDINAL;
- PROCEDURE EGAHLine ( x,y,x2 : CARDINAL; c:CARDINAL );
- PROCEDURE HercGraphMode;
- PROCEDURE HercTextMode;
- PROCEDURE HercPlot(x,y:CARDINAL;c:CARDINAL) ;
- PROCEDURE HercPoint(x,y:CARDINAL) : CARDINAL;
- PROCEDURE HercHLine ( x,y,x2 : CARDINAL; c:CARDINAL );
- PROCEDURE ATTGraphMode;
- PROCEDURE ATTPlot(x,y:CARDINAL;c:CARDINAL);
- PROCEDURE ATTPoint(x,y:CARDINAL) : CARDINAL;
- PROCEDURE ATTHLine ( x,y,x2 : CARDINAL; c:CARDINAL );
- CONST VGAGraphMode VGAPlot VGAPoint VGAHLine EGATextMode VGATextMode ATTTextMode
- = EGAGraphMode ;
- = EGAPlot ;
- = EGAPoint ;
- = EGAHLine ;
- = CGATextMode ;
- = CGATextMode ;
- = CGATextMode ;
- CONST
- CGAWidth CGADepth CGANumColor EGAWidth EGADepth EGANumColor VGAWidth VGADepth VGANumColor HercWidth HercDepth HercNumColor ATTWidth ATTDepth ATTNumColor
- END Gr.
- = 320 ;
- = 200 ;
- = 4 ;
- = 640 ;
- = 350 ;
- = 16 ;
- = 640 ;
- = 480 ;
- = 16 ;
- = 720 ;
- = 348 ;
- = 2 ;
- = 640 ;
- = 400 ;
- = 2 ;
- The module substitutes the appropriate constants for the general values (such as Width, Depth, etc.) used by the procedures. Similarly, the procedures appropriate for a specific graphics board are used once you initialize for a particular board. The default initialization is for the CGA board.
- For the CGA board, the colors are numbered as follows: black = 0, blue = 1, red = 2 and white = 3. The color assignments will differ for other boards.
- For the CGA board, filling functions fill with dots of two alternate colors, which are encoded as Colorl + NumColor * Color2. For example, if you want to fill with the color blue the fill color is: 1 + NumColor *1 = 5. You can use this same expression for other boards; the second part of the expression will not be used in determining the color, however.
- Graphics Procedures
- When you call the following procedures, the system will actually call the procedure appropriate for your graphics board. For example, if you have a Hercules board, and you have initialized your program for this board with a call to InitHerc, then a call to GraphMode in your program will actually be a call to HercGraphMode. This is all done automatically, based on the initialization code that is executed for the Graph module.
- GraphMode
- PROCEDURE GraphMode;
- Selects the graphics mode for the board being used.
- TextMode
- PROCEDURE TextMode;
- Returns to text mode.
- Plot
- PROCEDURE Plot(x,y: CARDINAL; Color: CARDINAL);
- This procedure sets the dot at coordinates x, y to the the color specified by Color.
- Example: On a CGA board, the following statement would set the specified
- dot to blue:
- Plot( 200, 100, 1);
- Point
- PROCEDURE Point (X,y: CARDINAL) : CARDINAL;
- Returns the color of the dot at the coordinates x, y.
- Example: On a CGA, the following function returns 2 to CurrColor, a
- CARDINAL, if the specified point is red:
- CurrColor := Point( 220, 120);
- Line
- PROCEDURE Line(xl,yl,x2,y2: CARDINAL; Color: CARDINAL);
- Draws a line between the coordinates xl, yl and x2, y2 in the color specified by Color.
- Example: On a CGA board, the following statement would draw a vertical
- line in blue between the specified points:
- Line( 200, 50, 200, 150, 1) ;
- Circle
- PROCEDURE Circle(x0,y0,r: CARDINAL; c: CARDINAL);
- Draws a circle with center at positiion x0,y0 and radius r. The circle is drawn in the color given by c.
- Example: On a CGA board, the following statement draws a blue circle, having
- the specified center and radius:
- Circlet 200, 100, 20, 1);
- Disc
- PROCEDURE Disc(xO,yO,r: CARDINAL; FillColor: CARDINAL);
- Draws a filled circle with center at position x0,y0 and radius r. The color of the circle is given by FillColor; for the CGA, note that the fill color is a combination of two colors encoded as Colorl + NumColor * Color2.
- Example: The following statement draws a filled blue circle, having the spec
- ified center and radius.
- Disc( 200, 100, 20, 5) ;
- Ellipse
- PROCEDURE Ellipse(xO, yO : CARDINAL; aO, bO : CARDINAL; c : CARDINAL; fill : BOOLEAN);
- (* center *)
- (* semi-axes *)
- (* color *)
- (* whether filled *)
- Draws an ellipse having its center at position xO, yO, and having aO and bO as the length of the semimajor and semiminor axes, respectively. The BOOLEAN, fill, specifies whether the interior of the ellipse should be filled, and c specifies the color to use for the ellipse.
- Example:
- VAR MyColor : CARDINAL;
- Ellipse( 0, 0, 5, 3, MyColor, TRUE);
- draws a filled ellipse, with its center at the origin (0,0), and with semimajor and semiminor axes of length 5 and 3, respectively. The ellipse is drawn in whatever color is specified in MyColor.
- Polygon
- PROCEDURE Polygon(n : CARDINAL;
- px,py : ARRAY OF CARDINAL;
- FillColor : CARDINAL);
- Draws a filled polygon with n edges. The two arrays px and py specify the corners of the polygon (px [ 0 ], py [ 0 ] is the first comer, px[1],py[1] is the second comer, and so forth). FillColor is the color of the polygon.
- Example:
- TYPE Coordinate = ARRAY [0..2] OF CARDINAL;
- VAR Xs,Ys : Coordinate;
- Xs Coordinate(160,80,240);
- Ya := Coordinate(25,175,175);
- Polygon (3,Xa, Ya, 5);
- The call above draws a blue triangle, with vertices at
- 160, 25 80, 175
- 240, 175
- HLine
- PROCEDURE HLine(x,y,x2: CARDINAL; FillColor: CARDINAL);
- Draws a horizontal line at the Y coordinate given by y. Values x and x2 specify where the line starts and stops, respectively. The color of the line is specified by FillColor.
- Example:
- CGA board:
- The following statement draws a red line, 100 pixels wide, using a
- HLine( 50, 100, 150, 10);
- Initialization Procedures
- There is a separate initalization procedure for each graphics board supported by TopSpeed Modula-2. You need to use the procedure appropriate for your graphics board when compiling programs to run on your machine. The routines are:
- Initialization routines.
- Called to setup display output type.
- PROCEDURE InitCGA ; (* Default *)
- PROCEDURE InitEGA ;
- PROCEDURE InitVGA ;
- PROCEDURE InitHero ;
- PROCEDURE InitATT ;
- By default, the initialization code for the Graph module calls InitCGA. You can change this in your module implementation or you can simply call a different initialization procedure at the start of your programs.
- MODULE Window
- This section describes the powerful window management module that comes with TopSpeed Modula-2. Window allows you to display several virtual screens, or windows, on the physical screen. Multiple windows are treated in a stack like manner. Two kinds of windows are supported, “normal” windows, and palette windows which are described on page 242.
- An example of window programming (windemo. mod) is included on the disks supplied with your compiler. Take a look at the source, and then compile and run the program. The environment that comes with TopSpeed Modula-2 is another example of the use of the Window module.
- Window Constants and Types
- CONST
- Screenwidth = 80;
- ScreenDepth = 25;
- TYPE WinType = POINTER TO WinDescriptor; (* internal *) RelCoord = CARDINAL;
- AbsCoord = CARDINAL; Color = ( Black, Blue, Green, Cyan,
- Red, Magenta, Brown, LightGray,
- DarkGray, LightBlue, LightGreen, LightCyan,
- LightRed, LightMagenta, Yellow, White );
- X1,Y1,
- X2,Y2
- Foreground, : AbsCoord; (* outer coordinates of
- opposite corners *)
- Background : Color; (* not used if Palette *)
- CursorOn : BOOLEAN; (* if cursor active *)
- WrapOn : BOOLEAN; (* if EOL wrap enabled *)
- Hidden : BOOLEAN; (* if window on view *)
- FrameOn : BOOLEAN; (* if frame *)
- FrameDef FrameFore, : FrameStr; (* only used if frame *)
- FrameBack : Color; (* only used if frame and not Palette Window *)
- FrameStr = ARRAY[0..8] OF CHAR; (* Characters for frame *)
- (* 0 1 2 *)
- (* 3 4 *)
- (*
- TitleStr = ARRAY[0..ScreenWidth-1] OF 5 CHAR; 6 7 *)
- WinDef = RECORD
- END;
- TitleMode = (NoTitle,
- LeftUpperTitle,CenterUpperTitle,RightUpperTitle, LeftLowerTitle,CenterLowerTitle,RightLowerTitle);
- CONST
- SingleFrame = FrameStr (' I I II ।—। ') ;
- DoubleFrame = FrameStr (' IttI IIII LJ=U ') ;
- FullScreenDef = WinDef ( 0,0, ScreenWidth-1,ScreenDepth-1,
- White, Black, TRUE, TRUE, FALSE, FALSE, ' ',Black,Black );
- VAR
- Fullscreen : WinType;
- A window is defined by the type WinDef, and a variable or constant of this type is used to create a window. In WinDef, XI, Y1 are the coordinates of the upper left comer and X2, Y2 represent lower right hand comer of the window. If Hidden is TRUE, the window will not be displayed until the procedure PutOnTop is called. FrameOn specifies whether the window has a frame.
- A frame is specified by the type FrameStr — an array of 9 characters — where element 0 denotes the character of the upper left comer, element 1 is the character that denotes the upper bar, etc., as outlined in the declaration above. Two predefined frames are declared by the constants SingleFrame and DoubleFrame.
- A window is created using the procedure Open, which returns a handle of type WinType. Any subsequent reference to that window is made by using this handle. WinType is a pointer to an internal window descriptor, which should be regarded as private to the Window MODULE.
- The window manager operates with two different kinds of coordinates — coordinates relative to a window (RelCoord) and coordinates relative to the screen (AbsCo- ord). Coordinate 0,0 is the upper left comer of the screen when using AbsCoord, and coordinate (1,1) is the upper left comer of a window when using RelCoord.
- Output to windows is accomplished by using the output procedures in the IO module. (Window redefines WrStrRedirect, see MODULE IO).
- Window Management
- Open
- PROCEDURE Open(WD: WinDef) : WinType;
- Given a window definition, WD, Open creates a new window, clears the window and puts it on top of any existing windows. All subsequent output will be appear in this window. Open returns a handle which is to be used in further operations on the window.
- Example:
- Leftwindow := Open( WinDef( 0,0,
- Screenwidth DIV 2-1, ScreenDepth - 1, White, Black, TRUE, TRUE, FALSE, TRUE, SingleFrame, Black, Black));
- opens a window that is about half as wide as the entire screen. This window is on the left half of the screen and becomes the currently active window.
- SetTitle
- PROCEDURE SetTitle( W : Winiype;
- Title : ARRAY OF CHAR;
- Mode : TitleMode);
- SetTitle updates the window title within the window frame of window W. The parameter Mode gives the position of the title.
- Example:
- SetTitle( Leftwindow, "Left Side", CenterLowerTitle);
- specifies that Leftwindow is to have the title “Left Side” and that this title should be written at the bottom of the window, and should be centered.
- SetFrame
- PROCEDURE SetFrame ( W : WinType;
- Frame : FrameStr;
- Fore, Back : Color);
- This procedure changes the frame around the window W, redisplaying any title if necessary. Frame specifies the new frame, Fore and Back give the colors of the frame.
- Example:
- SetFrame( Leftwindow, DoubleFrame, Black, White);
- specifies that the frame for Leftwindow should use double lines. The foreground color will be Black and the background collor will be White.
- Use
- PROCEDURE Use(W: WinType);
- Use causes all subsequent output (by the current process) to appear in window W. W does not not have to be on the screen. This procedure is useful if you have more than one process. See Process, page 220.
- Example:
- Use( Leftwindow);
- PutOnTop
- PROCEDURE PutOnTop(W : WinType);
- This procedure puts the window W on top of the window stack, ensuring it is fully visible. All subsequent output will appear in this window (except for output redirected by Use).
- Example:
- PutOnTop( Fullscreen);
- makes the entire screen the active window. The variable Fullscreen is defined as FullScreenDef in file WINDOW.MOD.
- PutBeneath
- PROCEDURE PutBeneath(W: WinType; WA: WinType);
- This procedure puts the window W beneath the window WA on the window stack.
- Example:
- PutBeneath( Fullscreen, Leftwindow);
- puts Fullscreen under Leftwindow on the window stack.
- Hide
- PROCEDURE Hide(W: WinType);
- Hide removes the window W from the screen and the window stack. However, the contents of the window are saved so they can be redisplayed later, if required. Any window obscured by W will be uncovered as a result of the call to Hide. Any material written to a hidden window, W, is recorded, and will appear when the window is made visible.
- Example:
- Hide( Leftwindow);
- Change
- PROCEDURE Change(W: WinType; X1,Y1,X2,Y2: AbsCoord);
- Changes the size and/or position of the window W, as specified by the new comer coordinates Xl,Yl, X2 and Y2. The contents of the window will be moved with it. If the window is expanded, blanks are filled in; if the window is contracted, text is clipped.
- The comer coordinates specify the upper left (Xl, Yl) and lower right (X2, Y2) comers, respectively.
- Example:
- Change( Leftwindow, 0, 0, Screenwidth DIV 2-1, ScreenDepth DIV 2 - 1);
- makes Leftwindow half its original size — so that it takes up roughly the upper left quadrant of the screen.
- Close
- PROCEDURE Close(VAR W: WinType);
- Close removes the window w from the screen, deletes its window descriptor and deallocates any buffers previously allocated for W. Finally, W is set to NIL to prevent further use.
- Example:
- Close ( Leftwindow);
- removes Leftwindow and effectively deallocates the storage set aside for the window.
- Used
- PROCEDURE Used(): WinType;
- This procedure returns the window currently being used for output by the current process. If no window has been assigned by Use then the top window is returned.
- Example:
- CurrWin := Used();
- makes CurrWin (which is of type WinType) reference the window that is currently active.
- Top
- PROCEDURE Top() : WinType;
- This procedure returns the current top window.
- Example:
- NewTop := Top();
- Info
- PROCEDURE Info(W: WinType; VAR WD: WinDef);
- Given the window W, Info returns the definition of the window in parameter WD.
- Example:
- Info( Leftwindow, Windinfo);
- returns the values for Leftwindow to the WinDef variable, Windinfo.
- Coordinate Handling
- The following procedures enable you to check the status of a window at particular coordinates, and also to set the current window position. Notice that some procedures use RelCoord, whereas others use AbsCoord.
- Obscured At
- PROCEDURE ObscuredAt(W : WinType; X,Y: RelCoord) : BOOLEAN;
- This procedure returns TRUE if the window w is obscured at the position given by the relative coordinates, X and Y.
- Example:
- IF ObscuredAt( Leftwindow, 5, 5) THEN
- WrStr( 'Cannot see your point');
- END;
- At
- PROCEDURE At(X,Y: AbsCoord) : WinType;
- This procedure returns a handle for the window currently displayed at the absolute position X, Y. If no window is displayed at this position NIL is returned.
- Example:
- CurrWind At( 5, 5);
- returns the handle associated with the window currently being displayed at position 5,5.
- GotoXY
- PROCEDURE GotoXY(X,Y: RelCoord);
- This procedure sets the current X, Y position for the cursor in the window currently being used. If X or Y are outside the window frame they will be clipped.
- Example: The following statement makes 5,5 the current cursor position of
- the active window:
- GoToXY( 5, 5);
- WhereX
- PROCEDURE WhereX() : RelCoord;
- WhereX returns the X position of the cursor in the window currently being used.
- Example:
- VAR VP : RelCoord;
- VP :=WhereX();
- returns the cunent horizontal position of the cursor in the active window.
- WhereY
- PROCEDURE WhereY() : RelCoord;
- WhereY returns the Y position of the cursor in the window currently being used.
- Example:
- VAR YP : RelCoord;
- YP.:- WhereY () ;
- returns the current vertical position of the cursor in the active window.
- ConvertCoords
- PROCEDURE ConvertCoords( W : WinType;
- X,Y : RelCoord;
- VAR XO,YO : AbsCoord)
- This procedure converts the relative coordinates X, Y in window W to absolute screen coordinates. The results go in XO, YO.
- Example:
- VAR AbsX, AbsY : AbsCoord;
- ConvertCoord( Leftwindow, 5, 5, AbsX, AbsY);
- returns the absolute coordinates corresponding to the relative coordinates 5,5 in Leftwindow.
- Window Output Procedures
- Output to windows is accomplished by using the output procedures in the IO module. The procedures in this section also affect the output to windows. These procedures work in the currently active window.
- InsLine
- PROCEDURE InsLine;
- This procedure inserts a blank line at the current cursor position. The screen below this line scrolls downward.
- DelLine
- PROCEDURE DelLine;
- This procedure deletes the line at the current cursor position. The screen below the line scrolls upward.
- ClrEol
- PROCEDURE ClrEol;
- ClrEol clears from the current cursor position to the end of line.
- TextColor
- PROCEDURE TextColor(c: Color);
- This procedure sets the text foreground color to c in the current window.
- Example:
- TextColor( Magenta);
- sets the foreground text color in the cunent window to Magenta.
- TextBackground
- PROCEDURE TextBackground(c: Color);
- This procedure sets the text background color to c in the current window.
- Example:
- TextBackground( Black);
- sets the background text color in the cunent window to Black.
- DirectWrite
- PROCEDURE DirectWrite(X,Y: RelCoord; (* start coords *)
- A : ADDRESS; (* address of char array*) Len: CARDINAL); (* length to be written *)
- This procedure writes the string A directly to the cunent window, beginning at the position specified by X, Y. The Len parameter specifies the length to write. No check is made for special characters or end-of-line wrap.
- Example:
- DirectWrite ( 1, 5, ADR ( First), 5);
- writes five characters to the cunently active window. The characters are taken from the area of memory beginning with the location of First, and are written starting from the leftmost column on the fifth line in the window.
- SetWrap
- PROCEDURE SetWrap(on: BOOLEAN);
- SetWrap enables/disables automatic wrap — depending on the value of on — when writing beyond the right end of the current window.
- Example:
- SetWrap( FALSE);
- turns automatic wrap off.
- Clear
- PROCEDURE Clear;
- This procedure clears the current window.
- CursorOn
- PROCEDURE CursorOn;
- This turns the cursor on in the current window. Note that the cursor in a particular window is visible only when the cursor is turned on and the window is on top.
- CursorOff
- PROCEDURE CursorOff;
- This procedure turns the cursor off in the current window.
- Multi-Process Support
- By default, the Window module assumes that only one process calls it. If more processes use this module, the procedure SetProcessLocks should be called, to ensure that all window operations are performed consistently.
- SetProcessLocks
- PROCEDURE SetProcessLocks(LockProc,UnlockProc: PROC);
- This procedure enables process locking in the window system. The LockProc and UnlockProc procedures specify the lock and unlock procedures, respectively. SetProcessLocks also notifies the Window module that concurrent processes are used. If the module PROCESS is being used then the procedures Lock and Unlock may be passed as LockProc and UnlockProc see page 224, and see also Use, page 235.
- Example:
- SetProcessLocks( MyLock, MyUnlock);
- specifies MyLock and MyUnlock as the procedures to lock and unlock processes, respectively.
- See also Use, page 235.
- Palette Windows
- A special kind of window, a palette window, allows you to use several color sets within the sam ewindow, and to change these color sets dynamically.
- Palette Constants and Types
- CONST
- PaletteSize = 10;
- PaletteMax = PaletteSize-1;
- NonnalPaletteColor = 0; (* see procedure PaletteOpen *)
- FramePaletteColor - 1;
- TYPE
- PaletteRange = SHORTCARD [ 0..PaletteMax ];
- PaletteColorDef = RECORD Fore,Back : Color END;
- PaletteDef = ARRAY PaletteRange OF PaletteColorDef;
- A palette (PaletteDef) is 0 to PaletteMax entries of color sets (PaletteColorDef). Each color set specifies a foreground and a background color.
- PaletteOpen
- PROCEDURE PaletteOpen(WD : WinDef; Pal: PaletteDef) : WinType;
- PaletteOpen creates a new palette window, as specified by Wd and Pal. The window is cleared to the colors given by Pal [NormalPaletteColor] and the frame is drawn in the colors given by Pal [FramePaletteColor]. Finally the window is put on view on top of any existing windows. The current palette color is given by NormalPaletteColor.
- Example:
- VAR W : WinDef;
- PWind : WinType;
- PalToUse : PaletteDef;
- PWind := PaletteOpen( W, PalToUse);
- creates a new palette window, having the window characteristics specified in W and the palette settings in PalToUse.
- SetPalette
- PROCEDURE SetPalette(W: WinType; Pal: PaletteDef);
- SetPalette changes the palette of the specified window W to Pal, redisplaying the changed colors.
- Example:
- VAR PWind : WinType;
- PalToUse : PaletteDef;
- SetPalette( PWind, PalToUse);
- changes the palette for PWind to the settings in PalToUse.
- PaletteColor
- PROCEDURE PaletteColor() : PaletteRange;
- This procedure returns the current palette color set of the current window.
- Example:
- VAR WhatPalColor: PaletteRange;
- WhatPalColor := PaletteColor() ;
- returns the current palette color set to WhatPalColor.
- SetPaletteColor
- PROCEDURE SetPaletteColor(pc: PaletteRange);
- This procedure sets the current palette color set in the current window to the color set specified by pc. Any subsequent output will now appear in the colors specified by entry pc.
- Example:
- VAR NewPalColor: PaletteRange;
- SetPaletteColor( NewPalColor);
- changes the palette color set in the current window to those specified in the variable
- NewPalColor.
- PaletteColorUsed
- PROCEDURE PaletteColorUsed(W: WinType;pc: PaletteRange) : BOOLEAN;
- Returns TRUE if the color set pc is in use anywhere in the palette window W.
- Example:
- VAR IsUsed : BOOLEAN;
- MyWind : WinType;
- MyPalette : PaletteRange;
- IsUsed := PaletteColorUsed( MyWind, MyPalette);
- returns TRUE if the color set specified by MyPalette is used anywhere in MyWind.
- Str IO RdLnglnt
- Append 149 EndOfRd 179 RdLngReal
- Caps 149 KeyPressed 180 IxCuxCdl
- RdShtCard
- CardToStr 154 RdBool 177
- Compare 149 RdCard 177 RuShcHex RdShtlnt RdStr
- Concat 150 RdChar 177
- Copy 150 RdHex 177
- Delete 152 Rdlnt 177 ReadFirstEntry
- FixRealToStr 155 Rdltem 179 ReadNextEntry
- Insert 152 RdKey 180 Rename
- IntToStr 154 RdLn 179 XxIlUJir
- Item 151 RdLngCard 177 Seek
- S 3.
- Items
- Length 152
- 150 RdLngHex
- RdLnglnt 177
- 177 Truncate WrBin WrBool
- Match 153 RdLngReal 177
- Pos 151 RdReal 177
- RealToStr 154 RdShtCard 177 WrC ard
- Slice 151 RdShtHex 177
- StrToCard 156 RdShtlnt 177 WrCharRep
- StrToInt 155 RdStr 178 WrHex Wrlnt WrT.n
- StrToReal 156 RedirectInput 181
- Lib RedirectOutput
- WrBool
- WrCard 181
- 174
- 174 WrLngCard WrLngHex
- AddAddr 166 WrChar 174 WrLnglnt
- Compare 164 WrCharRep 177 WrLngReal WrReal
- DecAddr 167 WrHex 174
- Delay 171 Wrlnt 174 WrShtCard
- Di sableBreakCheck 170 WrLn 177 WrShtHex
- Dos
- EnahleBreakCheck 164
- 170 WrLngCard WrLngHex 174
- 174 WrShtlnt WrStr
- Environment 159 WrLnglnt 174 WrStrAdj
- Execute 165 WrLngReal 174 Storage
- FatalError 170 WrReal 174
- Fill 161 WrShtCard 174
- HashString 172 WrShtHex 174 ALLOCATE
- HSort 158 WrShtlnt 174 Avaiiaoie
- IncAddr 167 WrStr 176 DEALLOCATE
- Intr 165 WrStrAdj 176 HeapAllocate
- MathError and MathError2 169 HeapAvail
- Move 160 FIO He apChangeAl10c
- No Sound 172 He apChange S i z e
- ParamCount 160 Append 184 HeapDeallocate
- ParamStr QSort 160
- 157 AssignBuffer ChDir 185
- 194 HeapTotalAvail MakeHeap
- RAND 158 Close 185 SYSTEM
- RANDOM 158 Create 184
- RANDOMIZE 158 Erase 186
- ScanL 162 Exists 185 Currentpriority
- ScanNeL 163 GetDir 195 Currentprocess
- ScanNeR 163 GetPos 187 DI El GetFlags In
- ScanR 162 lOresult 188
- SetJmp and LongJmp 168 MkDir 194
- SetReturnCode 171 Open RdBin 183
- Sound 171 194 InterruptRegisters
- SubAddr 167 RdBool 192 IOTRANSFER Listen
- Terminate 172 RdCard 192
- UserBreak 169 RdChar 192 NewPriority
- WordFill 162 RdHex 192 NEWPROCESS
- WordMove 161 Rdlnt 192 UZS
- Out
- Rdltem 193
- RdLngCard RdLngHex 192
- 192 Seg SetFlags TRANSFER
- 192 192 192 192
- 192 192
- 193 195
- 196 186 195 187
- 187 186 191
- 188 188
- 188 191
- 188 188
- 191 188 188
- 188 188 188 188
- 188 188 190 190
- 198
- 198
- 198
- 200
- 201
- 202
- 201
- 200
- 201
- 199
- 207
- 207
- 208
- 208
- 210
- 209
- 206
- 206
- 208
- 207
- 204
- 208
- 209
- 209
- 210
- 205
- MATHUB TextMode 228
- ACos 211
- ASln 211 Window
- ATan 211
- ATan2 211 At 238
- BcdToLong ClearExceptions Cos 216
- 217
- 211 Change Clear Close 236
- 242
- 236
- CosH 212 ClrEol 240
- Exp
- LoadControlWord 213
- 216 ConvertCoords CursorOff 239
- 242
- Log 212 CursorOn DelLine 242
- 240
- LoglO
- LongToBcd 213
- 215 DirectWrite GotoXY 241
- 238
- Mod 214 Hide
- T T"1 236 O o '■»
- Bow 213
- Rexp 214 inio
- InsLine 240
- oin
- SinH 212 ObscuredAt 238
- Sqrt
- StoreControlWord 215
- 216 Open
- PaletteColor 233
- 244
- 245
- StoreEnvironment 217 cdietL6LO1OIUS6Q
- 211 PaletteOpen 244
- TanH 91 9 PutBeneath 235
- 414 PutOnTop 235
- FloatExc SetFrame SetPalette 234
- 244
- DisableExceptionHandllng 218 SetPaletteColor 245
- EnableExcept1onHandling 218 SetProcessLocks 243
- SetTitle 234
- ProcTrace SetWrap
- TextBackground 242
- 241
- Check 219 TextColor 241
- GetCsIp 220 Top 237
- Get_Name 219 Use 235
- Install 220 Used 237
- Monitor 218 WhereX 239
- WhereY 239
- Process
- Awaited 224
- Delay 224
- Init 222
- Lock 224
- Notify 223
- SEND 222 -
- Startprocess 221
- Startscheduler 221
- StopScheduler 221
- Unlock 225
- WAIT 223
- Graph
- Circle 229
- Disc 230
- Ellipse 230
- GraphMode 228
- HLine 231
- Line 229
- Plot 228
- Point 229
- Polygon 230
- Index
- 8086
- Architecture, 95
- 8087 specific procedures, 216
- 8087
- emulation, 140
- exceptions, 140, 217, 217
- support, 140
- $X directive, 136
- ABS function, 120
- Absolute variables, 106
- ACos, 211
- AddAddr, 166
- Adding, 110
- ADDRESS type, 105
- Address
- arithmetic, 166
- of object, 120
- offset procedure, 208 physical, 95, 104, 106, 109,
- 138, 95
- segment procedure, 209
- ADR function, 120
- Alias directive, 134, 135
- ALLOCATE, 198
- Allocation of storage, 197
- AND operator, 110
- Append, 149, 184
- ARRAY type, 105
- representation, 129
- Array, 102
- aggregate, 107
- index, 102
- indexing, 108
- open, 116, 117, 118
- ASin, 211
- AsmLib module, 144
- Assembler, 136
- AssignBuf fer, 185
- At, 238
- ATan, 211
- ATan2, 211
- Available, 198
- Awaited, 224
- BcdToLong, 216
- BIOS scrolling, 76
- BITSET type, 102
- Block commands, 64
- BOOLEAN type, 101
- Bottom scroll zone, 76
- Break directive, 134
- BYTE type, 27, 105, 118
- C convention, 135
- C, 136
- Calculator
- example program, 38
- Call
- characteristics, 119 conventions, 130 infix, 118
- recursive, 116
- CAP function, 120
- Caps, 149
- CARDINAL type, 100
- representation, 128
- CardToStr, 154
- CASE
- keyword, 104 statement, 42, 112
- Case study, 15
- Change, 236
- ChDir, 194
- Check, 219
- Checking index, 135
- NIL dereferencing, 136 overflow, 135 stack overflow, 136 subrange, 136
- CHR function, 120
- Circle, 229
- Class, 138
- Clear, 242
- ClearExceptions, 217
- Close, 185, 236
- ClrEol, 240
- Code segment, 135
- Comment, 97
- Compare, 149, 164
- Comparing, 110
- Compatibility type, 105, 118
- Compiler, 127
- Compiler batch, 78 environment, 67 line numbers, 73 options, 73 segments, 138
- Compound type, 105
- Concat, 150 Configuration error file, 92 load, 77 menu, 79 options, 76 save, 77 segment names, 138
- CONST declaration, 99, 107
- Constant, 106
- Constant aggregate, 107
- case study, 21
- choices, 104
- declaration, 107 expression, 109 literals, 106 named, 107
- Control variable, 114 Conversion
- float to BCD, 215
- ConvertCoords, 239
- Copy, 150
- Coroutines, 203
- Cos, 211
- CosH, 212
- Create, 184
- Currentpriority, 207
- CurrentProcess,207
- Cursor movement, 63
- CursorOff, 242
- CursorOn, 242
- Data segment, 135
- DEALLOCATE, 198
- Debug
- generate information, 73
- DEC procedure, 121
- DecAddr, 167
- Decimal numbers, 97
- Declaration, 98
- constant, 107 enumeration, 101 forward, 116
- full, 116, 122
- global, 122
- importing, 123
- label, 115
- local, 116
- nested, 99
- parameter, 116
- Procedure, 115
- type, 100
- TYPE,122
- variable, 106
- DEF-file, See File
- Default
- extensions, 75
- filenames, 75
- DEFINITION keyword, 122
- Delay, 20, 171, 224
- Delete, 152
- Delimiter, 96
- DelLine, 240
- DI, 208
- Directive, 134
- See also: Options
- Directory
- change directory, 57
- files dir, 57
- handling, 194
- DirectWrite, 241
- DisableBreakCheck, 170
- DisableExceptionHandling,
- 218
- Disc, 230
- DISPOSE procedure, 121
- Div operator, 110
- Dividing, 110
- Dos, 164
- DOS
- command line, 159
- environment, 159
- execute program, 58
- menu commands, 82, 88
- procedures, 164
- quit to, 58
- Shell, 58
- Editor, 59
- block commands, 64
- commands, 62
- correct case, 66
- cursor movement, 63
- deletion and insertion, 63
- insertion and deletion, 63
- keys, 62
- load file, 55, 59
- menu definition, 84
- menu, 59
- options, 65, 75
- pick file, 56
- save File, 57
- save file, 61
- search and replace, 66
- El, 208
- Ellipse, 230
- EnableBreakCheck,170
- EnableExcept ionHandling, 218
- EndOfRd, 179
- Entity, 98
- Enumeration type, 101
- Enumeration
- case study, 41
- importing, 123
- literal, 101
- representation, 129
- Environment, 159
- changing windows, 90
- compiling, 67
- editor, 59
- file menu, 55
- information, 77
- input, 52
- keys, 48, 50, 62, 84
- linker, 71
- make, 69
- running programs, 70
- windows, 51
- Erase, 186
- Error
- linker, 71
- message file, 92
- run-time, 70
- stop on first, 73
- syntax, 95
- type, 95
- EXCL procedure, 121
- EXE-file, See File
- Execute, 165
- Execute program, 58
- Exists, 185
- EXIT statement, 113
- Exp, 213
- Expression, 109
- context, 109
- literal, 109
- External names, 139
- FAR, 135, 139
- FatalError, 170
- File menu, 54
- File
- 7BJ-file, 140
- auto save, 75
- backup, 76 configuration, 77 DEF-file, 127, 136 environment, 47 error messages, 92
- EXE-file, 127, 140, 141
- handling, 183
- load, 55, 59
- MAP-file, 74, 137
- menu definition, 83
- OBJ-file, 127, 133, 136, 137, 139, 140
- pick, 56
- redirection, 76, 77
- save, 57, 61
- selection window, 53
- session, 58
- Fill, 161
- FIO module, 35, 146, 182
- FixRealToStr, 155
- FLOAT function, 120
- FloatExc module, 147, 217
- FOR statement, 18, 114
- Formal parameter, 116
- FORWARD declaration, 116
- FROM importing, 123
- Full declaration, 116, 122
- Function procedure
- case study, 28
- predefined, 119
- Function
- body, 116
- call, 118
- return value, 117
- returning conventions, 132
- Generic tokens, 96
- GetCsIp, 220
- GetDir, 195
- GetFlags, 210
- GetPos, 187
- Get_Name, 219
- GOTO statement, 115
- GotoXY, 238
- Graph module, 30. 146, 226
- GraphMode, 228
- Group, 137
- HALT procedure, 121
- Hashstring, 172
- HeapAllocate, 200
- HeapAvail, 201
- HeapChangeAlloc, 202
- HeapChangeSize,201
- HeapDeallocate,200
- HeapSort, 36, 156
- HeapTotalAvail, 201
- Help lines, 82, 84
- Hexadecimal numbers, 97
- Hide, 236
- HIGH function, 116, 120
- HLine, 231
- HSort, 158
- Hyperbolic Functions, 212
- Identifier, 95, 96
- Identifier
- declaration, 98
- predefined, 100
- visibility, 98
- IF statement, 19, 111
- IMPLEMENTATION keyword,
- 121
- IMPORTing, 123
- In, 209
- IN operator, 110
- INC procedure, 121
- IncAddr, 167
- INCL procedure, 121
- Indenting
- program text, 19
- Index checking, 135
- Infix calls, 118
- Info, 237
- Init,222
- Initialization, 122
- Input
- direct, 180
- file, 146, 182
- formatted from files, 191
- formatted, 177
- keyboard, 146, 173
- redirection, 180
- Insert,152
- InsLine, 240
- Install, 220
- INTEGER type, 101
- representation, 128
- Interrupt directive, 135
- Interrupt handlers, 140
- InterruptRegisters, 206
- Interrupt
- disable, 208
- Intr, 165
- IntToStr, 154
- IO module, 146, 173
- lOresult, 188
- IOTRANSFER, 206
- Item, 151
- Item, 137
- Items, 152
- KeyPressed, 180
- Keys, 48, 50, 62, 84
- Label declaration, 115
- Language, 95
- Length, 150
- Lib module, 145, 156
- Libraries
- suppress, 73
- Library modules
- FIO, 182
- FloatExc, 217
- Graph, 226
- IO, 173
- Lib, 156
- MATHLIB, 211
- Process, 220
- ProcTrace, 218
- Storage, 197
- Str, 148
- SYSTEM, 202
- Window, 231
- Library
- /J option, 133
- Line, 229
- Line number
- /N option, 133
- Linker, 71
- Linker
- batch, 78
- case sensitive, 74
- errors, 71
- line numbers, 73
- map file, 74
- options, 74, 79
- segments, 137
- suppress warnings, 74
- trace references, 74
- Listen, 208
- Literal expression, 109
- Load file, 59
- LoadControlWord, 216
- Local declaration, 116
- Lock, 224
- Log, 212
- LoglO, 213
- LONGCARD type, 100
- LONGINT type, 101
- LongJmp, 168
- LONGREAL type, 101
- LongToBcd, 215
- LONGWORD type, 105, 118
- LOOP statement, 25, 113
- Main menu, 50
- Main module, 68
- Make, 69
- /M option, 133
- main module, 57, 68
- MakeHeap,199
- MAP-file, See File
- Match, 153
- MathError and MathError2, 169
- MATHLIB module, 144, 211
- MAX function, 120
- Memory models, 137
- Menu
- actions, 86
- customization, 79
- definition file, 83
- definition, 85
- editor, 59
- external commands, 82, 88
- keys, 48
- main, 50
- options, 72
- pop up, 59, 80, 83, 90
- pull down, 83
- MIN function, 120
- MkDir, 194
- Mod, 214
- MOD operator, 110
- MODULE keyword, 121
- Module
- case study, 25
- initialization, 122
- local, 124
- priority, 122, 203, 207
- Modulus, 110
- Monitor, 218
- Move, 160
- Multiplying, 110
- Name, 99
- qualified, 123
- Named constant, 107
- NEAR, 135, 139
- Nesting, 99
- NEW procedure, 121
- NewPriority, 207
- NEWPROCESS, 204
- NIL pointer checking, 136
- NIL value, 107
- NoSound, 172
- NOT operator, 110
- Notify, 223
- NULLPROC
- procedure value, 119 Number
- decimal, 97
- hexadecimal, 97
- octal, 97
- real, 97
- OBJ-file, See File
- ObscuredAt, 238
- Octal numbers, 97
- ODD function, 120
- Ofs, 208
- Open, 183, 233
- Open array parameter, 27
- Open array, 116, 131
- Operands
- Compatible, 110
- Option, 132
- See also: Directive
- compiler, 73
- editor, 65. 75
- linker, 74, 79
- load, 77
- menu, 72
- run, 74
- save, 77
- setup, 76
- OR operator, 110
- ORD function, 120
- Out, 209
- Output
- file, 146, 182
- formatted to files, 188
- formatted, 174
- redirection, 180
- screen, 146, 173
- Overflow checking, 135
- Palette Constants and Types, 243
- PaletteColor, 244 PaletteColorUsed, 245
- PaletteOpen, 244 ParamCount, 160 ParamCount, 34 Parameter, 115
- actual, 118
- case study, 24 compatible, 118 declaration, 116 formal, 116
- passing conventions, 131
- string, 118
- value, 116
- VAR, 116
- ParamStr, 34, 160 Permutations
- of a string, 22
- Plot, 228
- Point, 229
- POINTER, 105
- keyword, 104
- representation, 129 Pointer
- absolute, 104
- based, 104
- case study, 35 constructor, 109 designate type, 99 normalized, 166 opaque, 122
- Polygon, 230
- Pop up menus, 48, 59, 80, 83
- Pop up, 90
- Pos, 151
- Pow, 213
- Predefined identifier, 100
- Priority
- module, 122
- Procedure declaration, 115
- Procedure, 28
- activation, 130
- body, 116
- case study, 21, 24, 37
- FAR/NEAR directive, 135 predefined, 119 representation, 129
- type, 119
- Process module, 145, 220
- Process
- high-level, 220
- low-level, 203
- priority, 221
- scheduler, 220
- signals, 221
- ProcTrace module, 147, 218
- Production, 98
- Program
- terminate, 172
- Pull down menus, 83
- PutBeneath, 235
- PutOnTop, 235
- Pythagorean triples, 18
- QSort, 157
- Quicksort, 37, 156
- Quit
- to DOS, 58
- RAND,158
- RANDOM, 158
- RANDOMIZE, 158
- Range, See subrange
- RdBin, 194
- RdBool, 178, 192
- RdCard, 178, 192
- RdChar, 178, 192
- RdHex, 178, 192
- Rdlnt, 178, 192
- Rdltem, 179, 193
- RdKey, 180
- RdLn, 179
- RdLngCard, 178, 192
- RdLngHex, 178, 192
- RdLnglnt, 178, 192
- RdLngReal, 178, 192
- RdReal, 178, 192
- RdShtCard, 178, 192
- RdShtHex, 178, 192
- RdShtlnt, 178, 192
- RdStr, 178, 193
- Rd'simple type’, 177, 192
- ReadFirstEntry, 195
- ReadNextEntry, 196
- REAL type, 101
- representation, 128
- Real
- Number, 97
- RealToStr, 154
- Recoloring
- help lines, 91
- RECORD keyword, 103
- RECORD type, 105
- representation, 129 Record
- aggregate, 107
- case study, 32, 41
- field selection, 108
- variant, 104
- RedirectInput, 181
- Redirection file, 77
- RedirectOutput, 181
- Register
- segment, 139
- $C directive, 135
- Registers, 130
- Remainder, 110
- Rename, 186
- REPEAT statement, 25, 113
- Representation
- data types, 128
- Resident programs, 141
- RETURN statement, 117
- Rexp, 214
- RmDir, 195
- Run-time
- default checks, 73
- error, 70 Segment, 137
- based pointer, 104
- code, 135
- compiler generated, 138
- data, 135
- register, 139
- SEND, 222
- Separator, 97
- Session file, 58
- SET keyword, 102
- SET type, 105
- representation, 129
- Set
- element, 102
- operations, 110
- SetFlags, 210
- SetFrame, 234
- SetJmp and LongJmp, 168
- SetJmp, 168
- SetPalette, 244
- SetPaletteColor, 245
- SetProcessLocks,243
- SetReturnCode,171
- SetTitle, 234
- Setup
- options, 76
- SetWrap, 242
- Shifting, 110
- SHORTADR type, 105
- SHORTCARD type, 100
- ShortCut keys, 84
- SHORTINT type, 101
- Sin, 211
- SinH, 212
- Size, 187
- SIZE function, 120
- Slice, 151
- Save file, 61
- ScanL, 162
- ScanNeL, 163
- ScanNeR, 163
- ScanR, 162
- Scope, 124
- Seek, 187
- Seg, 209 Snow check, 76
- Sorting
- lines of a text file, 32
- Sound, 20, 171
- Sqrt, 215
- Stack
- checking, 136
- frame, 130
- $S directive, 136
- StartProcess, 221
- Startscheduler, 221
- StopScheduler, 221
- Storage module, 145, 197
- Storage
- heaps, 145, 197
- segment lay out, 137
- StoreControlWord, 216 StoreEnvironment, 217 Str module, 144, 148 String
- assignment, 111
- constant, 107 conversions, 148, 153 handling, 144
- literal, 97
- parameter, 118 permutations, 22 procedures, 149 zero-termination, 148
- StrToCard, 156
- StrToInt, 155
- StrToReal,156
- SubAddr, 167
- Subprogram, See procedure
- Subrange checking, 136
- Subrange
- case study, 29
- Subroutines, See procedure
- Substring, 151
- Subtracting, 110
- Suffix, 107
- Syntax, 95, 98
- Syntax error, 95
- SYSTEM module, 144, 202
- Tail recursion, 38
- Tan, 211
- TanH, 212
- Terminate,172
- TextBackground, 241
- TextColor, 241
- TextMode, 228
- Token
- alternatives, 97 definition of, 96 generic, 96 Top, 237 Top scroll zone, 76 Trace directive, 136 TRANSFER, 205 Tree
- data structure, 38 Trigonometric functions, 211 TRUNC function, 120 Truncate, 186 Type
- ARRAY, 102 base, 102 BOOLEAN, 101 CARDINAL, 100 case study, 20 cast, 120 compatibility, 105, 118 compound, 105 designated, 104, 99 enumeration, 101 INTEGER, 101 numeric, 101 ordinal, 101 POINTER, 104 procedure, 119 REAL, 101 RECORD,103 SET, 102 subrange, 102 transfer, 120
- Type conversion case study, 22
- TYPE declaration, 100, 122
- Unlock, 225 Use, 235 Used, 237 UserBreak, 169
- VAL conversion, 120 VAL function, 120 Value parameter, 116
- VAR declaration, 106
- WrLngCard, 174, 188
- WrLngHex, 174, 188
- WrLnglnt, 174, 188
- WrLngReal, 174, 188
- WrReal, 174, 188
- WrShtCard, 174, 188
- WrShtHex, 174, 188
- WrShtlnt, 174, 188
- WrStr, 176, 190
- WrStrAdj, 176, 190
- VAR parameter, 116 Variable absolute, 106 control, 114 declaration, 106 global, 122 local, 116 procedure, 119 volatile /V option, 133 volatile option, 73 volatile $W directive, 136
- Visibility, 123
- Volatile, 133, 136
- VS I ZE function, 120
- WAIT, 223
- WhereX, 239
- WhereY, 239
- WHILE statement, 25, 112
- Window module, 147, 231 Window
- changing, 90
- classes, 91 definition, 233 frame, 233 management, 233 output, 240
- palette, 243 recoloring, 91 repositioning, 90 resizing, 90
- zoom, 52
- WITH statement, 32, 114
- WORD type, 105, 118
- WordFill, 162 WordMove, 161 WrBin, 191 WrBool, 174, 188 WrCard, 174, 188 WrChar, 174, 188 WrCharRep, 177, 191 WrHex, 174, 188 Wrlnt, 174, 188 WrLn, 177, 191
- Jensen & Partners UK Ltd. 63 Clerkenwell Road London EC1M 5NP England
- Jensen & Partners International, Inc.
- 1101 San Antonio Road. Suite 301 Mountain View. CA 94043
- • Press |lAfil|[R]| to Run a program
- • Type
- prog7 followed by ||Enter||.
- FIGURE 4-2 TopSpeed Modula-2 screen after specifying command line arguments
- The system will compile, make, and link your program, and will then execute it — as if you had typed
- prog7 stest.raw stest.srt
- at the main DOS command line.
- The program uses an array of pointers to represent the file. If x is a pointer variable, xA denotes the object which x points at — that is, the object whose address is the current value of x. Each line of the file is allocated the exact amount of storage it requires. The FIO module (file input/output) is used to read and write disk files. The calls to FIO.AssignBuffer could be omitted, but this would cause the program to run much more slowly. The size of the buffer supplied has been chosen to optimize the disk accesses.
- Note that you need to close the output file, using FIO. Close, as otherwise the buffer assigned for this file would not be flushed.
- The procedure Lib. HSort sorts information using an algorithm known as a Heapsort. This procedure takes three parameters: the number of elements in the array to be sorted, and two procedure parameters, which are routines to compare and exchange elements.
- Another sorting routine, Lib. QSort, could have been used instead. This procedure uses Quicksort, a different sorting algorithm, which is faster than Heapsort on the average, but is much slower in its worst case performance than Heapsort.
- Implementing Quicksort The implementation of Lib. QSort is instructive because it uses a recursive (nested) procedure. Let’s take a look at it. Here are the relevant extracts from lib. def:
- DEFINITION MODULE Lib;
- TYPE
- CompareProc = PROCEDURE(CARDINAL, CARDINAL):BOOLEAN;
- SwapProc » PROCEDURE(CARDINAL, CARDINAL);
- PROCEDURE QSort(n:CARDINAL; Less:CompareProc; Swap:SwapProc);
- END Lib.
- And here is the relevant material from the implementation module, lib .mod:
- IMPLEMENTATION MODULE Lib;
- The module definition contains type definitions for two procedure types. These are used as parameters for QSort. Notice that the actual procedure definitions are not provided in the Lib module. You must provide these two procedures when you call QSort (or Lib. QSort). The procedure parameter enables you to pass in the information needed for QSort to use your procedures.
- ShortCut |Alt||R||
- To run your completed program within the environment do either of the following:
- • Select the Run command on the Main Menu
- • Use the ShortCut command |Alt||[R||
- Providing the Auto Make Option is set ON, this function will first perform an automatic Make, if any editing has taken place since the last Make. Then a full screen window is opened in which your program is executed. When your program has finished, you are prompted to press IIEscll to return to the environment. This environment will be in exactly the same state as it was when you left. You may move the prompt window using |ScrollLock|| if you need to view beneath (see “Repositioning Windows,” on page 90).
- To time the execution of your program exactly, you can set the Timed Run option (see “Timed Run,” page 75).
- Run-Time Errors You can get TopSpeed Modula-2 to report run-time errors when running your program — by setting the appropriate compiler directives. If you are running within the environment then you can be taken to the exact position in your source where the error occurred. This powerful feature allows you to quickly find and correct common run-time errors.
- Here is a list of the compiler directives that enable it to report the run-time errors, and a brief description of the check performed:
- (* *$!+*) Index Out Of Range
- Checks for out of range array index values.
- (*$O+*) Arithmetic Overflow
- Checks on arithmetical operations for overflow.
- (* $ S+*) Stack Overflow
- Checks for stack overflow on procedure calls. (NOTE: you cannot continue the program after such an error).
|