glpmpl01.c 172 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716
  1. /* glpmpl01.c */
  2. /***********************************************************************
  3. * This code is part of GLPK (GNU Linear Programming Kit).
  4. *
  5. * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  6. * 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  7. * Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  8. * E-mail: <mao@gnu.org>.
  9. *
  10. * GLPK is free software: you can redistribute it and/or modify it
  11. * under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation, either version 3 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * GLPK is distributed in the hope that it will be useful, but WITHOUT
  16. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  17. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  18. * License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  22. ***********************************************************************/
  23. #define _GLPSTD_STDIO
  24. #include "glpmpl.h"
  25. #define dmp_get_atomv dmp_get_atom
  26. /**********************************************************************/
  27. /* * * PROCESSING MODEL SECTION * * */
  28. /**********************************************************************/
  29. /*----------------------------------------------------------------------
  30. -- enter_context - enter current token into context queue.
  31. --
  32. -- This routine enters the current token into the context queue. */
  33. void enter_context(MPL *mpl)
  34. { char *image, *s;
  35. if (mpl->token == T_EOF)
  36. image = "_|_";
  37. else if (mpl->token == T_STRING)
  38. image = "'...'";
  39. else
  40. image = mpl->image;
  41. xassert(0 <= mpl->c_ptr && mpl->c_ptr < CONTEXT_SIZE);
  42. mpl->context[mpl->c_ptr++] = ' ';
  43. if (mpl->c_ptr == CONTEXT_SIZE) mpl->c_ptr = 0;
  44. for (s = image; *s != '\0'; s++)
  45. { mpl->context[mpl->c_ptr++] = *s;
  46. if (mpl->c_ptr == CONTEXT_SIZE) mpl->c_ptr = 0;
  47. }
  48. return;
  49. }
  50. /*----------------------------------------------------------------------
  51. -- print_context - print current content of context queue.
  52. --
  53. -- This routine prints current content of the context queue. */
  54. void print_context(MPL *mpl)
  55. { int c;
  56. while (mpl->c_ptr > 0)
  57. { mpl->c_ptr--;
  58. c = mpl->context[0];
  59. memmove(mpl->context, mpl->context+1, CONTEXT_SIZE-1);
  60. mpl->context[CONTEXT_SIZE-1] = (char)c;
  61. }
  62. xprintf("Context: %s%.*s\n", mpl->context[0] == ' ' ? "" : "...",
  63. CONTEXT_SIZE, mpl->context);
  64. return;
  65. }
  66. /*----------------------------------------------------------------------
  67. -- get_char - scan next character from input text file.
  68. --
  69. -- This routine scans a next ASCII character from the input text file.
  70. -- In case of end-of-file, the character is assigned EOF. */
  71. void get_char(MPL *mpl)
  72. { int c;
  73. if (mpl->c == EOF) goto done;
  74. if (mpl->c == '\n') mpl->line++;
  75. c = read_char(mpl);
  76. if (c == EOF)
  77. { if (mpl->c == '\n')
  78. mpl->line--;
  79. else
  80. warning(mpl, "final NL missing before end of file");
  81. }
  82. else if (c == '\n')
  83. ;
  84. else if (isspace(c))
  85. c = ' ';
  86. else if (iscntrl(c))
  87. { enter_context(mpl);
  88. mpl_error(mpl, "control character 0x%02X not allowed", c);
  89. }
  90. mpl->c = c;
  91. done: return;
  92. }
  93. /*----------------------------------------------------------------------
  94. -- append_char - append character to current token.
  95. --
  96. -- This routine appends the current character to the current token and
  97. -- then scans a next character. */
  98. void append_char(MPL *mpl)
  99. { xassert(0 <= mpl->imlen && mpl->imlen <= MAX_LENGTH);
  100. if (mpl->imlen == MAX_LENGTH)
  101. { switch (mpl->token)
  102. { case T_NAME:
  103. enter_context(mpl);
  104. mpl_error(mpl, "symbolic name %s... too long", mpl->image);
  105. case T_SYMBOL:
  106. enter_context(mpl);
  107. mpl_error(mpl, "symbol %s... too long", mpl->image);
  108. case T_NUMBER:
  109. enter_context(mpl);
  110. mpl_error(mpl, "numeric literal %s... too long", mpl->image);
  111. case T_STRING:
  112. enter_context(mpl);
  113. mpl_error(mpl, "string literal too long");
  114. default:
  115. xassert(mpl != mpl);
  116. }
  117. }
  118. mpl->image[mpl->imlen++] = (char)mpl->c;
  119. mpl->image[mpl->imlen] = '\0';
  120. get_char(mpl);
  121. return;
  122. }
  123. /*----------------------------------------------------------------------
  124. -- get_token - scan next token from input text file.
  125. --
  126. -- This routine scans a next token from the input text file using the
  127. -- standard finite automation technique. */
  128. void get_token(MPL *mpl)
  129. { /* save the current token */
  130. mpl->b_token = mpl->token;
  131. mpl->b_imlen = mpl->imlen;
  132. strcpy(mpl->b_image, mpl->image);
  133. mpl->b_value = mpl->value;
  134. /* if the next token is already scanned, make it current */
  135. if (mpl->f_scan)
  136. { mpl->f_scan = 0;
  137. mpl->token = mpl->f_token;
  138. mpl->imlen = mpl->f_imlen;
  139. strcpy(mpl->image, mpl->f_image);
  140. mpl->value = mpl->f_value;
  141. goto done;
  142. }
  143. loop: /* nothing has been scanned so far */
  144. mpl->token = 0;
  145. mpl->imlen = 0;
  146. mpl->image[0] = '\0';
  147. mpl->value = 0.0;
  148. /* skip any uninteresting characters */
  149. while (mpl->c == ' ' || mpl->c == '\n') get_char(mpl);
  150. /* recognize and construct the token */
  151. if (mpl->c == EOF)
  152. { /* end-of-file reached */
  153. mpl->token = T_EOF;
  154. }
  155. else if (mpl->c == '#')
  156. { /* comment; skip anything until end-of-line */
  157. while (mpl->c != '\n' && mpl->c != EOF) get_char(mpl);
  158. goto loop;
  159. }
  160. else if (!mpl->flag_d && (isalpha(mpl->c) || mpl->c == '_'))
  161. { /* symbolic name or reserved keyword */
  162. mpl->token = T_NAME;
  163. while (isalnum(mpl->c) || mpl->c == '_') append_char(mpl);
  164. if (strcmp(mpl->image, "and") == 0)
  165. mpl->token = T_AND;
  166. else if (strcmp(mpl->image, "by") == 0)
  167. mpl->token = T_BY;
  168. else if (strcmp(mpl->image, "cross") == 0)
  169. mpl->token = T_CROSS;
  170. else if (strcmp(mpl->image, "diff") == 0)
  171. mpl->token = T_DIFF;
  172. else if (strcmp(mpl->image, "div") == 0)
  173. mpl->token = T_DIV;
  174. else if (strcmp(mpl->image, "else") == 0)
  175. mpl->token = T_ELSE;
  176. else if (strcmp(mpl->image, "if") == 0)
  177. mpl->token = T_IF;
  178. else if (strcmp(mpl->image, "in") == 0)
  179. mpl->token = T_IN;
  180. #if 1 /* 21/VII-2006 */
  181. else if (strcmp(mpl->image, "Infinity") == 0)
  182. mpl->token = T_INFINITY;
  183. #endif
  184. else if (strcmp(mpl->image, "inter") == 0)
  185. mpl->token = T_INTER;
  186. else if (strcmp(mpl->image, "less") == 0)
  187. mpl->token = T_LESS;
  188. else if (strcmp(mpl->image, "mod") == 0)
  189. mpl->token = T_MOD;
  190. else if (strcmp(mpl->image, "not") == 0)
  191. mpl->token = T_NOT;
  192. else if (strcmp(mpl->image, "or") == 0)
  193. mpl->token = T_OR;
  194. else if (strcmp(mpl->image, "s") == 0 && mpl->c == '.')
  195. { mpl->token = T_SPTP;
  196. append_char(mpl);
  197. if (mpl->c != 't')
  198. sptp: { enter_context(mpl);
  199. mpl_error(mpl, "keyword s.t. incomplete");
  200. }
  201. append_char(mpl);
  202. if (mpl->c != '.') goto sptp;
  203. append_char(mpl);
  204. }
  205. else if (strcmp(mpl->image, "symdiff") == 0)
  206. mpl->token = T_SYMDIFF;
  207. else if (strcmp(mpl->image, "then") == 0)
  208. mpl->token = T_THEN;
  209. else if (strcmp(mpl->image, "union") == 0)
  210. mpl->token = T_UNION;
  211. else if (strcmp(mpl->image, "within") == 0)
  212. mpl->token = T_WITHIN;
  213. }
  214. else if (!mpl->flag_d && isdigit(mpl->c))
  215. { /* numeric literal */
  216. mpl->token = T_NUMBER;
  217. /* scan integer part */
  218. while (isdigit(mpl->c)) append_char(mpl);
  219. /* scan optional fractional part */
  220. if (mpl->c == '.')
  221. { append_char(mpl);
  222. if (mpl->c == '.')
  223. { /* hmm, it is not the fractional part, it is dots that
  224. follow the integer part */
  225. mpl->imlen--;
  226. mpl->image[mpl->imlen] = '\0';
  227. mpl->f_dots = 1;
  228. goto conv;
  229. }
  230. frac: while (isdigit(mpl->c)) append_char(mpl);
  231. }
  232. /* scan optional decimal exponent */
  233. if (mpl->c == 'e' || mpl->c == 'E')
  234. { append_char(mpl);
  235. if (mpl->c == '+' || mpl->c == '-') append_char(mpl);
  236. if (!isdigit(mpl->c))
  237. { enter_context(mpl);
  238. mpl_error(mpl, "numeric literal %s incomplete", mpl->image);
  239. }
  240. while (isdigit(mpl->c)) append_char(mpl);
  241. }
  242. /* there must be no letter following the numeric literal */
  243. if (isalpha(mpl->c) || mpl->c == '_')
  244. { enter_context(mpl);
  245. mpl_error(mpl, "symbol %s%c... should be enclosed in quotes",
  246. mpl->image, mpl->c);
  247. }
  248. conv: /* convert numeric literal to floating-point */
  249. if (str2num(mpl->image, &mpl->value))
  250. err: { enter_context(mpl);
  251. mpl_error(mpl, "cannot convert numeric literal %s to floating-p"
  252. "oint number", mpl->image);
  253. }
  254. }
  255. else if (mpl->c == '\'' || mpl->c == '"')
  256. { /* character string */
  257. int quote = mpl->c;
  258. mpl->token = T_STRING;
  259. get_char(mpl);
  260. for (;;)
  261. { if (mpl->c == '\n' || mpl->c == EOF)
  262. { enter_context(mpl);
  263. mpl_error(mpl, "unexpected end of line; string literal incom"
  264. "plete");
  265. }
  266. if (mpl->c == quote)
  267. { get_char(mpl);
  268. if (mpl->c != quote) break;
  269. }
  270. append_char(mpl);
  271. }
  272. }
  273. else if (!mpl->flag_d && mpl->c == '+')
  274. mpl->token = T_PLUS, append_char(mpl);
  275. else if (!mpl->flag_d && mpl->c == '-')
  276. mpl->token = T_MINUS, append_char(mpl);
  277. else if (mpl->c == '*')
  278. { mpl->token = T_ASTERISK, append_char(mpl);
  279. if (mpl->c == '*')
  280. mpl->token = T_POWER, append_char(mpl);
  281. }
  282. else if (mpl->c == '/')
  283. { mpl->token = T_SLASH, append_char(mpl);
  284. if (mpl->c == '*')
  285. { /* comment sequence */
  286. get_char(mpl);
  287. for (;;)
  288. { if (mpl->c == EOF)
  289. { /* do not call enter_context at this point */
  290. mpl_error(mpl, "unexpected end of file; comment sequence "
  291. "incomplete");
  292. }
  293. else if (mpl->c == '*')
  294. { get_char(mpl);
  295. if (mpl->c == '/') break;
  296. }
  297. else
  298. get_char(mpl);
  299. }
  300. get_char(mpl);
  301. goto loop;
  302. }
  303. }
  304. else if (mpl->c == '^')
  305. mpl->token = T_POWER, append_char(mpl);
  306. else if (mpl->c == '<')
  307. { mpl->token = T_LT, append_char(mpl);
  308. if (mpl->c == '=')
  309. mpl->token = T_LE, append_char(mpl);
  310. else if (mpl->c == '>')
  311. mpl->token = T_NE, append_char(mpl);
  312. #if 1 /* 11/II-2008 */
  313. else if (mpl->c == '-')
  314. mpl->token = T_INPUT, append_char(mpl);
  315. #endif
  316. }
  317. else if (mpl->c == '=')
  318. { mpl->token = T_EQ, append_char(mpl);
  319. if (mpl->c == '=') append_char(mpl);
  320. }
  321. else if (mpl->c == '>')
  322. { mpl->token = T_GT, append_char(mpl);
  323. if (mpl->c == '=')
  324. mpl->token = T_GE, append_char(mpl);
  325. #if 1 /* 14/VII-2006 */
  326. else if (mpl->c == '>')
  327. mpl->token = T_APPEND, append_char(mpl);
  328. #endif
  329. }
  330. else if (mpl->c == '!')
  331. { mpl->token = T_NOT, append_char(mpl);
  332. if (mpl->c == '=')
  333. mpl->token = T_NE, append_char(mpl);
  334. }
  335. else if (mpl->c == '&')
  336. { mpl->token = T_CONCAT, append_char(mpl);
  337. if (mpl->c == '&')
  338. mpl->token = T_AND, append_char(mpl);
  339. }
  340. else if (mpl->c == '|')
  341. { mpl->token = T_BAR, append_char(mpl);
  342. if (mpl->c == '|')
  343. mpl->token = T_OR, append_char(mpl);
  344. }
  345. else if (!mpl->flag_d && mpl->c == '.')
  346. { mpl->token = T_POINT, append_char(mpl);
  347. if (mpl->f_dots)
  348. { /* dots; the first dot was read on the previous call to the
  349. scanner, so the current character is the second dot */
  350. mpl->token = T_DOTS;
  351. mpl->imlen = 2;
  352. strcpy(mpl->image, "..");
  353. mpl->f_dots = 0;
  354. }
  355. else if (mpl->c == '.')
  356. mpl->token = T_DOTS, append_char(mpl);
  357. else if (isdigit(mpl->c))
  358. { /* numeric literal that begins with the decimal point */
  359. mpl->token = T_NUMBER, append_char(mpl);
  360. goto frac;
  361. }
  362. }
  363. else if (mpl->c == ',')
  364. mpl->token = T_COMMA, append_char(mpl);
  365. else if (mpl->c == ':')
  366. { mpl->token = T_COLON, append_char(mpl);
  367. if (mpl->c == '=')
  368. mpl->token = T_ASSIGN, append_char(mpl);
  369. }
  370. else if (mpl->c == ';')
  371. mpl->token = T_SEMICOLON, append_char(mpl);
  372. else if (mpl->c == '(')
  373. mpl->token = T_LEFT, append_char(mpl);
  374. else if (mpl->c == ')')
  375. mpl->token = T_RIGHT, append_char(mpl);
  376. else if (mpl->c == '[')
  377. mpl->token = T_LBRACKET, append_char(mpl);
  378. else if (mpl->c == ']')
  379. mpl->token = T_RBRACKET, append_char(mpl);
  380. else if (mpl->c == '{')
  381. mpl->token = T_LBRACE, append_char(mpl);
  382. else if (mpl->c == '}')
  383. mpl->token = T_RBRACE, append_char(mpl);
  384. #if 1 /* 11/II-2008 */
  385. else if (mpl->c == '~')
  386. mpl->token = T_TILDE, append_char(mpl);
  387. #endif
  388. else if (isalnum(mpl->c) || strchr("+-._", mpl->c) != NULL)
  389. { /* symbol */
  390. xassert(mpl->flag_d);
  391. mpl->token = T_SYMBOL;
  392. while (isalnum(mpl->c) || strchr("+-._", mpl->c) != NULL)
  393. append_char(mpl);
  394. switch (str2num(mpl->image, &mpl->value))
  395. { case 0:
  396. mpl->token = T_NUMBER;
  397. break;
  398. case 1:
  399. goto err;
  400. case 2:
  401. break;
  402. default:
  403. xassert(mpl != mpl);
  404. }
  405. }
  406. else
  407. { enter_context(mpl);
  408. mpl_error(mpl, "character %c not allowed", mpl->c);
  409. }
  410. /* enter the current token into the context queue */
  411. enter_context(mpl);
  412. /* reset the flag, which may be set by indexing_expression() and
  413. is used by expression_list() */
  414. mpl->flag_x = 0;
  415. done: return;
  416. }
  417. /*----------------------------------------------------------------------
  418. -- unget_token - return current token back to input stream.
  419. --
  420. -- This routine returns the current token back to the input stream, so
  421. -- the previously scanned token becomes the current one. */
  422. void unget_token(MPL *mpl)
  423. { /* save the current token, which becomes the next one */
  424. xassert(!mpl->f_scan);
  425. mpl->f_scan = 1;
  426. mpl->f_token = mpl->token;
  427. mpl->f_imlen = mpl->imlen;
  428. strcpy(mpl->f_image, mpl->image);
  429. mpl->f_value = mpl->value;
  430. /* restore the previous token, which becomes the current one */
  431. mpl->token = mpl->b_token;
  432. mpl->imlen = mpl->b_imlen;
  433. strcpy(mpl->image, mpl->b_image);
  434. mpl->value = mpl->b_value;
  435. return;
  436. }
  437. /*----------------------------------------------------------------------
  438. -- is_keyword - check if current token is given non-reserved keyword.
  439. --
  440. -- If the current token is given (non-reserved) keyword, this routine
  441. -- returns non-zero. Otherwise zero is returned. */
  442. int is_keyword(MPL *mpl, char *keyword)
  443. { return
  444. mpl->token == T_NAME && strcmp(mpl->image, keyword) == 0;
  445. }
  446. /*----------------------------------------------------------------------
  447. -- is_reserved - check if current token is reserved keyword.
  448. --
  449. -- If the current token is a reserved keyword, this routine returns
  450. -- non-zero. Otherwise zero is returned. */
  451. int is_reserved(MPL *mpl)
  452. { return
  453. mpl->token == T_AND && mpl->image[0] == 'a' ||
  454. mpl->token == T_BY ||
  455. mpl->token == T_CROSS ||
  456. mpl->token == T_DIFF ||
  457. mpl->token == T_DIV ||
  458. mpl->token == T_ELSE ||
  459. mpl->token == T_IF ||
  460. mpl->token == T_IN ||
  461. mpl->token == T_INTER ||
  462. mpl->token == T_LESS ||
  463. mpl->token == T_MOD ||
  464. mpl->token == T_NOT && mpl->image[0] == 'n' ||
  465. mpl->token == T_OR && mpl->image[0] == 'o' ||
  466. mpl->token == T_SYMDIFF ||
  467. mpl->token == T_THEN ||
  468. mpl->token == T_UNION ||
  469. mpl->token == T_WITHIN;
  470. }
  471. /*----------------------------------------------------------------------
  472. -- make_code - generate pseudo-code (basic routine).
  473. --
  474. -- This routine generates specified pseudo-code. It is assumed that all
  475. -- other translator routines use this basic routine. */
  476. CODE *make_code(MPL *mpl, int op, OPERANDS *arg, int type, int dim)
  477. { CODE *code;
  478. DOMAIN *domain;
  479. DOMAIN_BLOCK *block;
  480. ARG_LIST *e;
  481. /* generate pseudo-code */
  482. code = alloc(CODE);
  483. code->op = op;
  484. code->vflag = 0; /* is inherited from operand(s) */
  485. /* copy operands and also make them referring to the pseudo-code
  486. being generated, because the latter becomes the parent for all
  487. its operands */
  488. memset(&code->arg, '?', sizeof(OPERANDS));
  489. switch (op)
  490. { case O_NUMBER:
  491. code->arg.num = arg->num;
  492. break;
  493. case O_STRING:
  494. code->arg.str = arg->str;
  495. break;
  496. case O_INDEX:
  497. code->arg.index.slot = arg->index.slot;
  498. code->arg.index.next = arg->index.next;
  499. break;
  500. case O_MEMNUM:
  501. case O_MEMSYM:
  502. for (e = arg->par.list; e != NULL; e = e->next)
  503. { xassert(e->x != NULL);
  504. xassert(e->x->up == NULL);
  505. e->x->up = code;
  506. code->vflag |= e->x->vflag;
  507. }
  508. code->arg.par.par = arg->par.par;
  509. code->arg.par.list = arg->par.list;
  510. break;
  511. case O_MEMSET:
  512. for (e = arg->set.list; e != NULL; e = e->next)
  513. { xassert(e->x != NULL);
  514. xassert(e->x->up == NULL);
  515. e->x->up = code;
  516. code->vflag |= e->x->vflag;
  517. }
  518. code->arg.set.set = arg->set.set;
  519. code->arg.set.list = arg->set.list;
  520. break;
  521. case O_MEMVAR:
  522. for (e = arg->var.list; e != NULL; e = e->next)
  523. { xassert(e->x != NULL);
  524. xassert(e->x->up == NULL);
  525. e->x->up = code;
  526. code->vflag |= e->x->vflag;
  527. }
  528. code->arg.var.var = arg->var.var;
  529. code->arg.var.list = arg->var.list;
  530. #if 1 /* 15/V-2010 */
  531. code->arg.var.suff = arg->var.suff;
  532. #endif
  533. break;
  534. #if 1 /* 15/V-2010 */
  535. case O_MEMCON:
  536. for (e = arg->con.list; e != NULL; e = e->next)
  537. { xassert(e->x != NULL);
  538. xassert(e->x->up == NULL);
  539. e->x->up = code;
  540. code->vflag |= e->x->vflag;
  541. }
  542. code->arg.con.con = arg->con.con;
  543. code->arg.con.list = arg->con.list;
  544. code->arg.con.suff = arg->con.suff;
  545. break;
  546. #endif
  547. case O_TUPLE:
  548. case O_MAKE:
  549. for (e = arg->list; e != NULL; e = e->next)
  550. { xassert(e->x != NULL);
  551. xassert(e->x->up == NULL);
  552. e->x->up = code;
  553. code->vflag |= e->x->vflag;
  554. }
  555. code->arg.list = arg->list;
  556. break;
  557. case O_SLICE:
  558. xassert(arg->slice != NULL);
  559. code->arg.slice = arg->slice;
  560. break;
  561. case O_IRAND224:
  562. case O_UNIFORM01:
  563. case O_NORMAL01:
  564. case O_GMTIME:
  565. code->vflag = 1;
  566. break;
  567. case O_CVTNUM:
  568. case O_CVTSYM:
  569. case O_CVTLOG:
  570. case O_CVTTUP:
  571. case O_CVTLFM:
  572. case O_PLUS:
  573. case O_MINUS:
  574. case O_NOT:
  575. case O_ABS:
  576. case O_CEIL:
  577. case O_FLOOR:
  578. case O_EXP:
  579. case O_LOG:
  580. case O_LOG10:
  581. case O_SQRT:
  582. case O_SIN:
  583. case O_COS:
  584. case O_ATAN:
  585. case O_ROUND:
  586. case O_TRUNC:
  587. case O_CARD:
  588. case O_LENGTH:
  589. /* unary operation */
  590. xassert(arg->arg.x != NULL);
  591. xassert(arg->arg.x->up == NULL);
  592. arg->arg.x->up = code;
  593. code->vflag |= arg->arg.x->vflag;
  594. code->arg.arg.x = arg->arg.x;
  595. break;
  596. case O_ADD:
  597. case O_SUB:
  598. case O_LESS:
  599. case O_MUL:
  600. case O_DIV:
  601. case O_IDIV:
  602. case O_MOD:
  603. case O_POWER:
  604. case O_ATAN2:
  605. case O_ROUND2:
  606. case O_TRUNC2:
  607. case O_UNIFORM:
  608. if (op == O_UNIFORM) code->vflag = 1;
  609. case O_NORMAL:
  610. if (op == O_NORMAL) code->vflag = 1;
  611. case O_CONCAT:
  612. case O_LT:
  613. case O_LE:
  614. case O_EQ:
  615. case O_GE:
  616. case O_GT:
  617. case O_NE:
  618. case O_AND:
  619. case O_OR:
  620. case O_UNION:
  621. case O_DIFF:
  622. case O_SYMDIFF:
  623. case O_INTER:
  624. case O_CROSS:
  625. case O_IN:
  626. case O_NOTIN:
  627. case O_WITHIN:
  628. case O_NOTWITHIN:
  629. case O_SUBSTR:
  630. case O_STR2TIME:
  631. case O_TIME2STR:
  632. /* binary operation */
  633. xassert(arg->arg.x != NULL);
  634. xassert(arg->arg.x->up == NULL);
  635. arg->arg.x->up = code;
  636. code->vflag |= arg->arg.x->vflag;
  637. xassert(arg->arg.y != NULL);
  638. xassert(arg->arg.y->up == NULL);
  639. arg->arg.y->up = code;
  640. code->vflag |= arg->arg.y->vflag;
  641. code->arg.arg.x = arg->arg.x;
  642. code->arg.arg.y = arg->arg.y;
  643. break;
  644. case O_DOTS:
  645. case O_FORK:
  646. case O_SUBSTR3:
  647. /* ternary operation */
  648. xassert(arg->arg.x != NULL);
  649. xassert(arg->arg.x->up == NULL);
  650. arg->arg.x->up = code;
  651. code->vflag |= arg->arg.x->vflag;
  652. xassert(arg->arg.y != NULL);
  653. xassert(arg->arg.y->up == NULL);
  654. arg->arg.y->up = code;
  655. code->vflag |= arg->arg.y->vflag;
  656. if (arg->arg.z != NULL)
  657. { xassert(arg->arg.z->up == NULL);
  658. arg->arg.z->up = code;
  659. code->vflag |= arg->arg.z->vflag;
  660. }
  661. code->arg.arg.x = arg->arg.x;
  662. code->arg.arg.y = arg->arg.y;
  663. code->arg.arg.z = arg->arg.z;
  664. break;
  665. case O_MIN:
  666. case O_MAX:
  667. /* n-ary operation */
  668. for (e = arg->list; e != NULL; e = e->next)
  669. { xassert(e->x != NULL);
  670. xassert(e->x->up == NULL);
  671. e->x->up = code;
  672. code->vflag |= e->x->vflag;
  673. }
  674. code->arg.list = arg->list;
  675. break;
  676. case O_SUM:
  677. case O_PROD:
  678. case O_MINIMUM:
  679. case O_MAXIMUM:
  680. case O_FORALL:
  681. case O_EXISTS:
  682. case O_SETOF:
  683. case O_BUILD:
  684. /* iterated operation */
  685. domain = arg->loop.domain;
  686. xassert(domain != NULL);
  687. if (domain->code != NULL)
  688. { xassert(domain->code->up == NULL);
  689. domain->code->up = code;
  690. code->vflag |= domain->code->vflag;
  691. }
  692. for (block = domain->list; block != NULL; block =
  693. block->next)
  694. { xassert(block->code != NULL);
  695. xassert(block->code->up == NULL);
  696. block->code->up = code;
  697. code->vflag |= block->code->vflag;
  698. }
  699. if (arg->loop.x != NULL)
  700. { xassert(arg->loop.x->up == NULL);
  701. arg->loop.x->up = code;
  702. code->vflag |= arg->loop.x->vflag;
  703. }
  704. code->arg.loop.domain = arg->loop.domain;
  705. code->arg.loop.x = arg->loop.x;
  706. break;
  707. default:
  708. xassert(op != op);
  709. }
  710. /* set other attributes of the pseudo-code */
  711. code->type = type;
  712. code->dim = dim;
  713. code->up = NULL;
  714. code->valid = 0;
  715. memset(&code->value, '?', sizeof(VALUE));
  716. return code;
  717. }
  718. /*----------------------------------------------------------------------
  719. -- make_unary - generate pseudo-code for unary operation.
  720. --
  721. -- This routine generates pseudo-code for unary operation. */
  722. CODE *make_unary(MPL *mpl, int op, CODE *x, int type, int dim)
  723. { CODE *code;
  724. OPERANDS arg;
  725. xassert(x != NULL);
  726. arg.arg.x = x;
  727. code = make_code(mpl, op, &arg, type, dim);
  728. return code;
  729. }
  730. /*----------------------------------------------------------------------
  731. -- make_binary - generate pseudo-code for binary operation.
  732. --
  733. -- This routine generates pseudo-code for binary operation. */
  734. CODE *make_binary(MPL *mpl, int op, CODE *x, CODE *y, int type,
  735. int dim)
  736. { CODE *code;
  737. OPERANDS arg;
  738. xassert(x != NULL);
  739. xassert(y != NULL);
  740. arg.arg.x = x;
  741. arg.arg.y = y;
  742. code = make_code(mpl, op, &arg, type, dim);
  743. return code;
  744. }
  745. /*----------------------------------------------------------------------
  746. -- make_ternary - generate pseudo-code for ternary operation.
  747. --
  748. -- This routine generates pseudo-code for ternary operation. */
  749. CODE *make_ternary(MPL *mpl, int op, CODE *x, CODE *y, CODE *z,
  750. int type, int dim)
  751. { CODE *code;
  752. OPERANDS arg;
  753. xassert(x != NULL);
  754. xassert(y != NULL);
  755. /* third operand can be NULL */
  756. arg.arg.x = x;
  757. arg.arg.y = y;
  758. arg.arg.z = z;
  759. code = make_code(mpl, op, &arg, type, dim);
  760. return code;
  761. }
  762. /*----------------------------------------------------------------------
  763. -- numeric_literal - parse reference to numeric literal.
  764. --
  765. -- This routine parses primary expression using the syntax:
  766. --
  767. -- <primary expression> ::= <numeric literal> */
  768. CODE *numeric_literal(MPL *mpl)
  769. { CODE *code;
  770. OPERANDS arg;
  771. xassert(mpl->token == T_NUMBER);
  772. arg.num = mpl->value;
  773. code = make_code(mpl, O_NUMBER, &arg, A_NUMERIC, 0);
  774. get_token(mpl /* <numeric literal> */);
  775. return code;
  776. }
  777. /*----------------------------------------------------------------------
  778. -- string_literal - parse reference to string literal.
  779. --
  780. -- This routine parses primary expression using the syntax:
  781. --
  782. -- <primary expression> ::= <string literal> */
  783. CODE *string_literal(MPL *mpl)
  784. { CODE *code;
  785. OPERANDS arg;
  786. xassert(mpl->token == T_STRING);
  787. arg.str = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  788. strcpy(arg.str, mpl->image);
  789. code = make_code(mpl, O_STRING, &arg, A_SYMBOLIC, 0);
  790. get_token(mpl /* <string literal> */);
  791. return code;
  792. }
  793. /*----------------------------------------------------------------------
  794. -- create_arg_list - create empty operands list.
  795. --
  796. -- This routine creates operands list, which is initially empty. */
  797. ARG_LIST *create_arg_list(MPL *mpl)
  798. { ARG_LIST *list;
  799. xassert(mpl == mpl);
  800. list = NULL;
  801. return list;
  802. }
  803. /*----------------------------------------------------------------------
  804. -- expand_arg_list - append operand to operands list.
  805. --
  806. -- This routine appends new operand to specified operands list. */
  807. ARG_LIST *expand_arg_list(MPL *mpl, ARG_LIST *list, CODE *x)
  808. { ARG_LIST *tail, *temp;
  809. xassert(x != NULL);
  810. /* create new operands list entry */
  811. tail = alloc(ARG_LIST);
  812. tail->x = x;
  813. tail->next = NULL;
  814. /* and append it to the operands list */
  815. if (list == NULL)
  816. list = tail;
  817. else
  818. { for (temp = list; temp->next != NULL; temp = temp->next);
  819. temp->next = tail;
  820. }
  821. return list;
  822. }
  823. /*----------------------------------------------------------------------
  824. -- arg_list_len - determine length of operands list.
  825. --
  826. -- This routine returns the number of operands in operands list. */
  827. int arg_list_len(MPL *mpl, ARG_LIST *list)
  828. { ARG_LIST *temp;
  829. int len;
  830. xassert(mpl == mpl);
  831. len = 0;
  832. for (temp = list; temp != NULL; temp = temp->next) len++;
  833. return len;
  834. }
  835. /*----------------------------------------------------------------------
  836. -- subscript_list - parse subscript list.
  837. --
  838. -- This routine parses subscript list using the syntax:
  839. --
  840. -- <subscript list> ::= <subscript>
  841. -- <subscript list> ::= <subscript list> , <subscript>
  842. -- <subscript> ::= <expression 5> */
  843. ARG_LIST *subscript_list(MPL *mpl)
  844. { ARG_LIST *list;
  845. CODE *x;
  846. list = create_arg_list(mpl);
  847. for (;;)
  848. { /* parse subscript expression */
  849. x = expression_5(mpl);
  850. /* convert it to symbolic type, if necessary */
  851. if (x->type == A_NUMERIC)
  852. x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
  853. /* check that now the expression is of symbolic type */
  854. if (x->type != A_SYMBOLIC)
  855. mpl_error(mpl, "subscript expression has invalid type");
  856. xassert(x->dim == 0);
  857. /* and append it to the subscript list */
  858. list = expand_arg_list(mpl, list, x);
  859. /* check a token that follows the subscript expression */
  860. if (mpl->token == T_COMMA)
  861. get_token(mpl /* , */);
  862. else if (mpl->token == T_RBRACKET)
  863. break;
  864. else
  865. mpl_error(mpl, "syntax error in subscript list");
  866. }
  867. return list;
  868. }
  869. #if 1 /* 15/V-2010 */
  870. /*----------------------------------------------------------------------
  871. -- object_reference - parse reference to named object.
  872. --
  873. -- This routine parses primary expression using the syntax:
  874. --
  875. -- <primary expression> ::= <dummy index>
  876. -- <primary expression> ::= <set name>
  877. -- <primary expression> ::= <set name> [ <subscript list> ]
  878. -- <primary expression> ::= <parameter name>
  879. -- <primary expression> ::= <parameter name> [ <subscript list> ]
  880. -- <primary expression> ::= <variable name> <suffix>
  881. -- <primary expression> ::= <variable name> [ <subscript list> ]
  882. -- <suffix>
  883. -- <primary expression> ::= <constraint name> <suffix>
  884. -- <primary expression> ::= <constraint name> [ <subscript list> ]
  885. -- <suffix>
  886. -- <dummy index> ::= <symbolic name>
  887. -- <set name> ::= <symbolic name>
  888. -- <parameter name> ::= <symbolic name>
  889. -- <variable name> ::= <symbolic name>
  890. -- <constraint name> ::= <symbolic name>
  891. -- <suffix> ::= <empty> | .lb | .ub | .status | .val | .dual */
  892. CODE *object_reference(MPL *mpl)
  893. { AVLNODE *node;
  894. DOMAIN_SLOT *slot;
  895. SET *set;
  896. PARAMETER *par;
  897. VARIABLE *var;
  898. CONSTRAINT *con;
  899. ARG_LIST *list;
  900. OPERANDS arg;
  901. CODE *code;
  902. char *name;
  903. int dim, suff;
  904. /* find the object in the symbolic name table */
  905. xassert(mpl->token == T_NAME);
  906. node = avl_find_node(mpl->tree, mpl->image);
  907. if (node == NULL)
  908. mpl_error(mpl, "%s not defined", mpl->image);
  909. /* check the object type and obtain its dimension */
  910. switch (avl_get_node_type(node))
  911. { case A_INDEX:
  912. /* dummy index */
  913. slot = (DOMAIN_SLOT *)avl_get_node_link(node);
  914. name = slot->name;
  915. dim = 0;
  916. break;
  917. case A_SET:
  918. /* model set */
  919. set = (SET *)avl_get_node_link(node);
  920. name = set->name;
  921. dim = set->dim;
  922. /* if a set object is referenced in its own declaration and
  923. the dimen attribute is not specified yet, use dimen 1 by
  924. default */
  925. if (set->dimen == 0) set->dimen = 1;
  926. break;
  927. case A_PARAMETER:
  928. /* model parameter */
  929. par = (PARAMETER *)avl_get_node_link(node);
  930. name = par->name;
  931. dim = par->dim;
  932. break;
  933. case A_VARIABLE:
  934. /* model variable */
  935. var = (VARIABLE *)avl_get_node_link(node);
  936. name = var->name;
  937. dim = var->dim;
  938. break;
  939. case A_CONSTRAINT:
  940. /* model constraint or objective */
  941. con = (CONSTRAINT *)avl_get_node_link(node);
  942. name = con->name;
  943. dim = con->dim;
  944. break;
  945. default:
  946. xassert(node != node);
  947. }
  948. get_token(mpl /* <symbolic name> */);
  949. /* parse optional subscript list */
  950. if (mpl->token == T_LBRACKET)
  951. { /* subscript list is specified */
  952. if (dim == 0)
  953. mpl_error(mpl, "%s cannot be subscripted", name);
  954. get_token(mpl /* [ */);
  955. list = subscript_list(mpl);
  956. if (dim != arg_list_len(mpl, list))
  957. mpl_error(mpl, "%s must have %d subscript%s rather than %d",
  958. name, dim, dim == 1 ? "" : "s", arg_list_len(mpl, list));
  959. xassert(mpl->token == T_RBRACKET);
  960. get_token(mpl /* ] */);
  961. }
  962. else
  963. { /* subscript list is not specified */
  964. if (dim != 0)
  965. mpl_error(mpl, "%s must be subscripted", name);
  966. list = create_arg_list(mpl);
  967. }
  968. /* parse optional suffix */
  969. if (!mpl->flag_s && avl_get_node_type(node) == A_VARIABLE)
  970. suff = DOT_NONE;
  971. else
  972. suff = DOT_VAL;
  973. if (mpl->token == T_POINT)
  974. { get_token(mpl /* . */);
  975. if (mpl->token != T_NAME)
  976. mpl_error(mpl, "invalid use of period");
  977. if (!(avl_get_node_type(node) == A_VARIABLE ||
  978. avl_get_node_type(node) == A_CONSTRAINT))
  979. mpl_error(mpl, "%s cannot have a suffix", name);
  980. if (strcmp(mpl->image, "lb") == 0)
  981. suff = DOT_LB;
  982. else if (strcmp(mpl->image, "ub") == 0)
  983. suff = DOT_UB;
  984. else if (strcmp(mpl->image, "status") == 0)
  985. suff = DOT_STATUS;
  986. else if (strcmp(mpl->image, "val") == 0)
  987. suff = DOT_VAL;
  988. else if (strcmp(mpl->image, "dual") == 0)
  989. suff = DOT_DUAL;
  990. else
  991. mpl_error(mpl, "suffix .%s invalid", mpl->image);
  992. get_token(mpl /* suffix */);
  993. }
  994. /* generate pseudo-code to take value of the object */
  995. switch (avl_get_node_type(node))
  996. { case A_INDEX:
  997. arg.index.slot = slot;
  998. arg.index.next = slot->list;
  999. code = make_code(mpl, O_INDEX, &arg, A_SYMBOLIC, 0);
  1000. slot->list = code;
  1001. break;
  1002. case A_SET:
  1003. arg.set.set = set;
  1004. arg.set.list = list;
  1005. code = make_code(mpl, O_MEMSET, &arg, A_ELEMSET,
  1006. set->dimen);
  1007. break;
  1008. case A_PARAMETER:
  1009. arg.par.par = par;
  1010. arg.par.list = list;
  1011. if (par->type == A_SYMBOLIC)
  1012. code = make_code(mpl, O_MEMSYM, &arg, A_SYMBOLIC, 0);
  1013. else
  1014. code = make_code(mpl, O_MEMNUM, &arg, A_NUMERIC, 0);
  1015. break;
  1016. case A_VARIABLE:
  1017. if (!mpl->flag_s && (suff == DOT_STATUS || suff == DOT_VAL
  1018. || suff == DOT_DUAL))
  1019. mpl_error(mpl, "invalid reference to status, primal value, o"
  1020. "r dual value of variable %s above solve statement",
  1021. var->name);
  1022. arg.var.var = var;
  1023. arg.var.list = list;
  1024. arg.var.suff = suff;
  1025. code = make_code(mpl, O_MEMVAR, &arg, suff == DOT_NONE ?
  1026. A_FORMULA : A_NUMERIC, 0);
  1027. break;
  1028. case A_CONSTRAINT:
  1029. if (!mpl->flag_s && (suff == DOT_STATUS || suff == DOT_VAL
  1030. || suff == DOT_DUAL))
  1031. mpl_error(mpl, "invalid reference to status, primal value, o"
  1032. "r dual value of %s %s above solve statement",
  1033. con->type == A_CONSTRAINT ? "constraint" : "objective"
  1034. , con->name);
  1035. arg.con.con = con;
  1036. arg.con.list = list;
  1037. arg.con.suff = suff;
  1038. code = make_code(mpl, O_MEMCON, &arg, A_NUMERIC, 0);
  1039. break;
  1040. default:
  1041. xassert(node != node);
  1042. }
  1043. return code;
  1044. }
  1045. #endif
  1046. /*----------------------------------------------------------------------
  1047. -- numeric_argument - parse argument passed to built-in function.
  1048. --
  1049. -- This routine parses an argument passed to numeric built-in function
  1050. -- using the syntax:
  1051. --
  1052. -- <arg> ::= <expression 5> */
  1053. CODE *numeric_argument(MPL *mpl, char *func)
  1054. { CODE *x;
  1055. x = expression_5(mpl);
  1056. /* convert the argument to numeric type, if necessary */
  1057. if (x->type == A_SYMBOLIC)
  1058. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  1059. /* check that now the argument is of numeric type */
  1060. if (x->type != A_NUMERIC)
  1061. mpl_error(mpl, "argument for %s has invalid type", func);
  1062. xassert(x->dim == 0);
  1063. return x;
  1064. }
  1065. #if 1 /* 15/VII-2006 */
  1066. CODE *symbolic_argument(MPL *mpl, char *func)
  1067. { CODE *x;
  1068. x = expression_5(mpl);
  1069. /* convert the argument to symbolic type, if necessary */
  1070. if (x->type == A_NUMERIC)
  1071. x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
  1072. /* check that now the argument is of symbolic type */
  1073. if (x->type != A_SYMBOLIC)
  1074. mpl_error(mpl, "argument for %s has invalid type", func);
  1075. xassert(x->dim == 0);
  1076. return x;
  1077. }
  1078. #endif
  1079. #if 1 /* 15/VII-2006 */
  1080. CODE *elemset_argument(MPL *mpl, char *func)
  1081. { CODE *x;
  1082. x = expression_9(mpl);
  1083. if (x->type != A_ELEMSET)
  1084. mpl_error(mpl, "argument for %s has invalid type", func);
  1085. xassert(x->dim > 0);
  1086. return x;
  1087. }
  1088. #endif
  1089. /*----------------------------------------------------------------------
  1090. -- function_reference - parse reference to built-in function.
  1091. --
  1092. -- This routine parses primary expression using the syntax:
  1093. --
  1094. -- <primary expression> ::= abs ( <arg> )
  1095. -- <primary expression> ::= ceil ( <arg> )
  1096. -- <primary expression> ::= floor ( <arg> )
  1097. -- <primary expression> ::= exp ( <arg> )
  1098. -- <primary expression> ::= log ( <arg> )
  1099. -- <primary expression> ::= log10 ( <arg> )
  1100. -- <primary expression> ::= max ( <arg list> )
  1101. -- <primary expression> ::= min ( <arg list> )
  1102. -- <primary expression> ::= sqrt ( <arg> )
  1103. -- <primary expression> ::= sin ( <arg> )
  1104. -- <primary expression> ::= cos ( <arg> )
  1105. -- <primary expression> ::= atan ( <arg> )
  1106. -- <primary expression> ::= atan2 ( <arg> , <arg> )
  1107. -- <primary expression> ::= round ( <arg> )
  1108. -- <primary expression> ::= round ( <arg> , <arg> )
  1109. -- <primary expression> ::= trunc ( <arg> )
  1110. -- <primary expression> ::= trunc ( <arg> , <arg> )
  1111. -- <primary expression> ::= Irand224 ( )
  1112. -- <primary expression> ::= Uniform01 ( )
  1113. -- <primary expression> ::= Uniform ( <arg> , <arg> )
  1114. -- <primary expression> ::= Normal01 ( )
  1115. -- <primary expression> ::= Normal ( <arg> , <arg> )
  1116. -- <primary expression> ::= card ( <arg> )
  1117. -- <primary expression> ::= length ( <arg> )
  1118. -- <primary expression> ::= substr ( <arg> , <arg> )
  1119. -- <primary expression> ::= substr ( <arg> , <arg> , <arg> )
  1120. -- <primary expression> ::= str2time ( <arg> , <arg> )
  1121. -- <primary expression> ::= time2str ( <arg> , <arg> )
  1122. -- <primary expression> ::= gmtime ( )
  1123. -- <arg list> ::= <arg>
  1124. -- <arg list> ::= <arg list> , <arg> */
  1125. CODE *function_reference(MPL *mpl)
  1126. { CODE *code;
  1127. OPERANDS arg;
  1128. int op;
  1129. char func[15+1];
  1130. /* determine operation code */
  1131. xassert(mpl->token == T_NAME);
  1132. if (strcmp(mpl->image, "abs") == 0)
  1133. op = O_ABS;
  1134. else if (strcmp(mpl->image, "ceil") == 0)
  1135. op = O_CEIL;
  1136. else if (strcmp(mpl->image, "floor") == 0)
  1137. op = O_FLOOR;
  1138. else if (strcmp(mpl->image, "exp") == 0)
  1139. op = O_EXP;
  1140. else if (strcmp(mpl->image, "log") == 0)
  1141. op = O_LOG;
  1142. else if (strcmp(mpl->image, "log10") == 0)
  1143. op = O_LOG10;
  1144. else if (strcmp(mpl->image, "sqrt") == 0)
  1145. op = O_SQRT;
  1146. else if (strcmp(mpl->image, "sin") == 0)
  1147. op = O_SIN;
  1148. else if (strcmp(mpl->image, "cos") == 0)
  1149. op = O_COS;
  1150. else if (strcmp(mpl->image, "atan") == 0)
  1151. op = O_ATAN;
  1152. else if (strcmp(mpl->image, "min") == 0)
  1153. op = O_MIN;
  1154. else if (strcmp(mpl->image, "max") == 0)
  1155. op = O_MAX;
  1156. else if (strcmp(mpl->image, "round") == 0)
  1157. op = O_ROUND;
  1158. else if (strcmp(mpl->image, "trunc") == 0)
  1159. op = O_TRUNC;
  1160. else if (strcmp(mpl->image, "Irand224") == 0)
  1161. op = O_IRAND224;
  1162. else if (strcmp(mpl->image, "Uniform01") == 0)
  1163. op = O_UNIFORM01;
  1164. else if (strcmp(mpl->image, "Uniform") == 0)
  1165. op = O_UNIFORM;
  1166. else if (strcmp(mpl->image, "Normal01") == 0)
  1167. op = O_NORMAL01;
  1168. else if (strcmp(mpl->image, "Normal") == 0)
  1169. op = O_NORMAL;
  1170. else if (strcmp(mpl->image, "card") == 0)
  1171. op = O_CARD;
  1172. else if (strcmp(mpl->image, "length") == 0)
  1173. op = O_LENGTH;
  1174. else if (strcmp(mpl->image, "substr") == 0)
  1175. op = O_SUBSTR;
  1176. else if (strcmp(mpl->image, "str2time") == 0)
  1177. op = O_STR2TIME;
  1178. else if (strcmp(mpl->image, "time2str") == 0)
  1179. op = O_TIME2STR;
  1180. else if (strcmp(mpl->image, "gmtime") == 0)
  1181. op = O_GMTIME;
  1182. else
  1183. mpl_error(mpl, "function %s unknown", mpl->image);
  1184. /* save symbolic name of the function */
  1185. strcpy(func, mpl->image);
  1186. xassert(strlen(func) < sizeof(func));
  1187. get_token(mpl /* <symbolic name> */);
  1188. /* check the left parenthesis that follows the function name */
  1189. xassert(mpl->token == T_LEFT);
  1190. get_token(mpl /* ( */);
  1191. /* parse argument list */
  1192. if (op == O_MIN || op == O_MAX)
  1193. { /* min and max allow arbitrary number of arguments */
  1194. arg.list = create_arg_list(mpl);
  1195. /* parse argument list */
  1196. for (;;)
  1197. { /* parse argument and append it to the operands list */
  1198. arg.list = expand_arg_list(mpl, arg.list,
  1199. numeric_argument(mpl, func));
  1200. /* check a token that follows the argument */
  1201. if (mpl->token == T_COMMA)
  1202. get_token(mpl /* , */);
  1203. else if (mpl->token == T_RIGHT)
  1204. break;
  1205. else
  1206. mpl_error(mpl, "syntax error in argument list for %s", func);
  1207. }
  1208. }
  1209. else if (op == O_IRAND224 || op == O_UNIFORM01 || op ==
  1210. O_NORMAL01 || op == O_GMTIME)
  1211. { /* Irand224, Uniform01, Normal01, gmtime need no arguments */
  1212. if (mpl->token != T_RIGHT)
  1213. mpl_error(mpl, "%s needs no arguments", func);
  1214. }
  1215. else if (op == O_UNIFORM || op == O_NORMAL)
  1216. { /* Uniform and Normal need two arguments */
  1217. /* parse the first argument */
  1218. arg.arg.x = numeric_argument(mpl, func);
  1219. /* check a token that follows the first argument */
  1220. if (mpl->token == T_COMMA)
  1221. ;
  1222. else if (mpl->token == T_RIGHT)
  1223. mpl_error(mpl, "%s needs two arguments", func);
  1224. else
  1225. mpl_error(mpl, "syntax error in argument for %s", func);
  1226. get_token(mpl /* , */);
  1227. /* parse the second argument */
  1228. arg.arg.y = numeric_argument(mpl, func);
  1229. /* check a token that follows the second argument */
  1230. if (mpl->token == T_COMMA)
  1231. mpl_error(mpl, "%s needs two argument", func);
  1232. else if (mpl->token == T_RIGHT)
  1233. ;
  1234. else
  1235. mpl_error(mpl, "syntax error in argument for %s", func);
  1236. }
  1237. else if (op == O_ATAN || op == O_ROUND || op == O_TRUNC)
  1238. { /* atan, round, and trunc need one or two arguments */
  1239. /* parse the first argument */
  1240. arg.arg.x = numeric_argument(mpl, func);
  1241. /* parse the second argument, if specified */
  1242. if (mpl->token == T_COMMA)
  1243. { switch (op)
  1244. { case O_ATAN: op = O_ATAN2; break;
  1245. case O_ROUND: op = O_ROUND2; break;
  1246. case O_TRUNC: op = O_TRUNC2; break;
  1247. default: xassert(op != op);
  1248. }
  1249. get_token(mpl /* , */);
  1250. arg.arg.y = numeric_argument(mpl, func);
  1251. }
  1252. /* check a token that follows the last argument */
  1253. if (mpl->token == T_COMMA)
  1254. mpl_error(mpl, "%s needs one or two arguments", func);
  1255. else if (mpl->token == T_RIGHT)
  1256. ;
  1257. else
  1258. mpl_error(mpl, "syntax error in argument for %s", func);
  1259. }
  1260. else if (op == O_SUBSTR)
  1261. { /* substr needs two or three arguments */
  1262. /* parse the first argument */
  1263. arg.arg.x = symbolic_argument(mpl, func);
  1264. /* check a token that follows the first argument */
  1265. if (mpl->token == T_COMMA)
  1266. ;
  1267. else if (mpl->token == T_RIGHT)
  1268. mpl_error(mpl, "%s needs two or three arguments", func);
  1269. else
  1270. mpl_error(mpl, "syntax error in argument for %s", func);
  1271. get_token(mpl /* , */);
  1272. /* parse the second argument */
  1273. arg.arg.y = numeric_argument(mpl, func);
  1274. /* parse the third argument, if specified */
  1275. if (mpl->token == T_COMMA)
  1276. { op = O_SUBSTR3;
  1277. get_token(mpl /* , */);
  1278. arg.arg.z = numeric_argument(mpl, func);
  1279. }
  1280. /* check a token that follows the last argument */
  1281. if (mpl->token == T_COMMA)
  1282. mpl_error(mpl, "%s needs two or three arguments", func);
  1283. else if (mpl->token == T_RIGHT)
  1284. ;
  1285. else
  1286. mpl_error(mpl, "syntax error in argument for %s", func);
  1287. }
  1288. else if (op == O_STR2TIME)
  1289. { /* str2time needs two arguments, both symbolic */
  1290. /* parse the first argument */
  1291. arg.arg.x = symbolic_argument(mpl, func);
  1292. /* check a token that follows the first argument */
  1293. if (mpl->token == T_COMMA)
  1294. ;
  1295. else if (mpl->token == T_RIGHT)
  1296. mpl_error(mpl, "%s needs two arguments", func);
  1297. else
  1298. mpl_error(mpl, "syntax error in argument for %s", func);
  1299. get_token(mpl /* , */);
  1300. /* parse the second argument */
  1301. arg.arg.y = symbolic_argument(mpl, func);
  1302. /* check a token that follows the second argument */
  1303. if (mpl->token == T_COMMA)
  1304. mpl_error(mpl, "%s needs two argument", func);
  1305. else if (mpl->token == T_RIGHT)
  1306. ;
  1307. else
  1308. mpl_error(mpl, "syntax error in argument for %s", func);
  1309. }
  1310. else if (op == O_TIME2STR)
  1311. { /* time2str needs two arguments, numeric and symbolic */
  1312. /* parse the first argument */
  1313. arg.arg.x = numeric_argument(mpl, func);
  1314. /* check a token that follows the first argument */
  1315. if (mpl->token == T_COMMA)
  1316. ;
  1317. else if (mpl->token == T_RIGHT)
  1318. mpl_error(mpl, "%s needs two arguments", func);
  1319. else
  1320. mpl_error(mpl, "syntax error in argument for %s", func);
  1321. get_token(mpl /* , */);
  1322. /* parse the second argument */
  1323. arg.arg.y = symbolic_argument(mpl, func);
  1324. /* check a token that follows the second argument */
  1325. if (mpl->token == T_COMMA)
  1326. mpl_error(mpl, "%s needs two argument", func);
  1327. else if (mpl->token == T_RIGHT)
  1328. ;
  1329. else
  1330. mpl_error(mpl, "syntax error in argument for %s", func);
  1331. }
  1332. else
  1333. { /* other functions need one argument */
  1334. if (op == O_CARD)
  1335. arg.arg.x = elemset_argument(mpl, func);
  1336. else if (op == O_LENGTH)
  1337. arg.arg.x = symbolic_argument(mpl, func);
  1338. else
  1339. arg.arg.x = numeric_argument(mpl, func);
  1340. /* check a token that follows the argument */
  1341. if (mpl->token == T_COMMA)
  1342. mpl_error(mpl, "%s needs one argument", func);
  1343. else if (mpl->token == T_RIGHT)
  1344. ;
  1345. else
  1346. mpl_error(mpl, "syntax error in argument for %s", func);
  1347. }
  1348. /* make pseudo-code to call the built-in function */
  1349. if (op == O_SUBSTR || op == O_SUBSTR3 || op == O_TIME2STR)
  1350. code = make_code(mpl, op, &arg, A_SYMBOLIC, 0);
  1351. else
  1352. code = make_code(mpl, op, &arg, A_NUMERIC, 0);
  1353. /* the reference ends with the right parenthesis */
  1354. xassert(mpl->token == T_RIGHT);
  1355. get_token(mpl /* ) */);
  1356. return code;
  1357. }
  1358. /*----------------------------------------------------------------------
  1359. -- create_domain - create empty domain.
  1360. --
  1361. -- This routine creates empty domain, which is initially empty, i.e.
  1362. -- has no domain blocks. */
  1363. DOMAIN *create_domain(MPL *mpl)
  1364. { DOMAIN *domain;
  1365. domain = alloc(DOMAIN);
  1366. domain->list = NULL;
  1367. domain->code = NULL;
  1368. return domain;
  1369. }
  1370. /*----------------------------------------------------------------------
  1371. -- create_block - create empty domain block.
  1372. --
  1373. -- This routine creates empty domain block, which is initially empty,
  1374. -- i.e. has no domain slots. */
  1375. DOMAIN_BLOCK *create_block(MPL *mpl)
  1376. { DOMAIN_BLOCK *block;
  1377. block = alloc(DOMAIN_BLOCK);
  1378. block->list = NULL;
  1379. block->code = NULL;
  1380. block->backup = NULL;
  1381. block->next = NULL;
  1382. return block;
  1383. }
  1384. /*----------------------------------------------------------------------
  1385. -- append_block - append domain block to specified domain.
  1386. --
  1387. -- This routine adds given domain block to the end of the block list of
  1388. -- specified domain. */
  1389. void append_block(MPL *mpl, DOMAIN *domain, DOMAIN_BLOCK *block)
  1390. { DOMAIN_BLOCK *temp;
  1391. xassert(mpl == mpl);
  1392. xassert(domain != NULL);
  1393. xassert(block != NULL);
  1394. xassert(block->next == NULL);
  1395. if (domain->list == NULL)
  1396. domain->list = block;
  1397. else
  1398. { for (temp = domain->list; temp->next != NULL; temp =
  1399. temp->next);
  1400. temp->next = block;
  1401. }
  1402. return;
  1403. }
  1404. /*----------------------------------------------------------------------
  1405. -- append_slot - create and append new slot to domain block.
  1406. --
  1407. -- This routine creates new domain slot and adds it to the end of slot
  1408. -- list of specified domain block.
  1409. --
  1410. -- The parameter name is symbolic name of the dummy index associated
  1411. -- with the slot (the character string must be allocated). NULL means
  1412. -- the dummy index is not explicitly specified.
  1413. --
  1414. -- The parameter code is pseudo-code for computing symbolic value, at
  1415. -- which the dummy index is bounded. NULL means the dummy index is free
  1416. -- in the domain scope. */
  1417. DOMAIN_SLOT *append_slot(MPL *mpl, DOMAIN_BLOCK *block, char *name,
  1418. CODE *code)
  1419. { DOMAIN_SLOT *slot, *temp;
  1420. xassert(block != NULL);
  1421. slot = alloc(DOMAIN_SLOT);
  1422. slot->name = name;
  1423. slot->code = code;
  1424. slot->value = NULL;
  1425. slot->list = NULL;
  1426. slot->next = NULL;
  1427. if (block->list == NULL)
  1428. block->list = slot;
  1429. else
  1430. { for (temp = block->list; temp->next != NULL; temp =
  1431. temp->next);
  1432. temp->next = slot;
  1433. }
  1434. return slot;
  1435. }
  1436. /*----------------------------------------------------------------------
  1437. -- expression_list - parse expression list.
  1438. --
  1439. -- This routine parses a list of one or more expressions enclosed into
  1440. -- the parentheses using the syntax:
  1441. --
  1442. -- <primary expression> ::= ( <expression list> )
  1443. -- <expression list> ::= <expression 13>
  1444. -- <expression list> ::= <expression 13> , <expression list>
  1445. --
  1446. -- Note that this construction may have three different meanings:
  1447. --
  1448. -- 1. If <expression list> consists of only one expression, <primary
  1449. -- expression> is a parenthesized expression, which may be of any
  1450. -- valid type (not necessarily 1-tuple).
  1451. --
  1452. -- 2. If <expression list> consists of several expressions separated by
  1453. -- commae, where no expression is undeclared symbolic name, <primary
  1454. -- expression> is a n-tuple.
  1455. --
  1456. -- 3. If <expression list> consists of several expressions separated by
  1457. -- commae, where at least one expression is undeclared symbolic name
  1458. -- (that denotes a dummy index), <primary expression> is a slice and
  1459. -- can be only used as constituent of indexing expression. */
  1460. #define max_dim 20
  1461. /* maximal number of components allowed within parentheses */
  1462. CODE *expression_list(MPL *mpl)
  1463. { CODE *code;
  1464. OPERANDS arg;
  1465. struct { char *name; CODE *code; } list[1+max_dim];
  1466. int flag_x, next_token, dim, j, slice = 0;
  1467. xassert(mpl->token == T_LEFT);
  1468. /* the flag, which allows recognizing undeclared symbolic names
  1469. as dummy indices, will be automatically reset by get_token(),
  1470. so save it before scanning the next token */
  1471. flag_x = mpl->flag_x;
  1472. get_token(mpl /* ( */);
  1473. /* parse <expression list> */
  1474. for (dim = 1; ; dim++)
  1475. { if (dim > max_dim)
  1476. mpl_error(mpl, "too many components within parentheses");
  1477. /* current component of <expression list> can be either dummy
  1478. index or expression */
  1479. if (mpl->token == T_NAME)
  1480. { /* symbolic name is recognized as dummy index only if:
  1481. the flag, which allows that, is set, and
  1482. the name is followed by comma or right parenthesis, and
  1483. the name is undeclared */
  1484. get_token(mpl /* <symbolic name> */);
  1485. next_token = mpl->token;
  1486. unget_token(mpl);
  1487. if (!(flag_x &&
  1488. (next_token == T_COMMA || next_token == T_RIGHT) &&
  1489. avl_find_node(mpl->tree, mpl->image) == NULL))
  1490. { /* this is not dummy index */
  1491. goto expr;
  1492. }
  1493. /* all dummy indices within the same slice must have unique
  1494. symbolic names */
  1495. for (j = 1; j < dim; j++)
  1496. { if (list[j].name != NULL && strcmp(list[j].name,
  1497. mpl->image) == 0)
  1498. mpl_error(mpl, "duplicate dummy index %s not allowed",
  1499. mpl->image);
  1500. }
  1501. /* current component of <expression list> is dummy index */
  1502. list[dim].name
  1503. = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  1504. strcpy(list[dim].name, mpl->image);
  1505. list[dim].code = NULL;
  1506. get_token(mpl /* <symbolic name> */);
  1507. /* <expression list> is a slice, because at least one dummy
  1508. index has appeared */
  1509. slice = 1;
  1510. /* note that the context ( <dummy index> ) is not allowed,
  1511. i.e. in this case <primary expression> is considered as
  1512. a parenthesized expression */
  1513. if (dim == 1 && mpl->token == T_RIGHT)
  1514. mpl_error(mpl, "%s not defined", list[dim].name);
  1515. }
  1516. else
  1517. expr: { /* current component of <expression list> is expression */
  1518. code = expression_13(mpl);
  1519. /* if the current expression is followed by comma or it is
  1520. not the very first expression, entire <expression list>
  1521. is n-tuple or slice, in which case the current expression
  1522. should be converted to symbolic type, if necessary */
  1523. if (mpl->token == T_COMMA || dim > 1)
  1524. { if (code->type == A_NUMERIC)
  1525. code = make_unary(mpl, O_CVTSYM, code, A_SYMBOLIC, 0);
  1526. /* now the expression must be of symbolic type */
  1527. if (code->type != A_SYMBOLIC)
  1528. mpl_error(mpl, "component expression has invalid type");
  1529. xassert(code->dim == 0);
  1530. }
  1531. list[dim].name = NULL;
  1532. list[dim].code = code;
  1533. }
  1534. /* check a token that follows the current component */
  1535. if (mpl->token == T_COMMA)
  1536. get_token(mpl /* , */);
  1537. else if (mpl->token == T_RIGHT)
  1538. break;
  1539. else
  1540. mpl_error(mpl, "right parenthesis missing where expected");
  1541. }
  1542. /* generate pseudo-code for <primary expression> */
  1543. if (dim == 1 && !slice)
  1544. { /* <primary expression> is a parenthesized expression */
  1545. code = list[1].code;
  1546. }
  1547. else if (!slice)
  1548. { /* <primary expression> is a n-tuple */
  1549. arg.list = create_arg_list(mpl);
  1550. for (j = 1; j <= dim; j++)
  1551. arg.list = expand_arg_list(mpl, arg.list, list[j].code);
  1552. code = make_code(mpl, O_TUPLE, &arg, A_TUPLE, dim);
  1553. }
  1554. else
  1555. { /* <primary expression> is a slice */
  1556. arg.slice = create_block(mpl);
  1557. for (j = 1; j <= dim; j++)
  1558. append_slot(mpl, arg.slice, list[j].name, list[j].code);
  1559. /* note that actually pseudo-codes with op = O_SLICE are never
  1560. evaluated */
  1561. code = make_code(mpl, O_SLICE, &arg, A_TUPLE, dim);
  1562. }
  1563. get_token(mpl /* ) */);
  1564. /* if <primary expression> is a slice, there must be the keyword
  1565. 'in', which follows the right parenthesis */
  1566. if (slice && mpl->token != T_IN)
  1567. mpl_error(mpl, "keyword in missing where expected");
  1568. /* if the slice flag is set and there is the keyword 'in', which
  1569. follows <primary expression>, the latter must be a slice */
  1570. if (flag_x && mpl->token == T_IN && !slice)
  1571. { if (dim == 1)
  1572. mpl_error(mpl, "syntax error in indexing expression");
  1573. else
  1574. mpl_error(mpl, "0-ary slice not allowed");
  1575. }
  1576. return code;
  1577. }
  1578. /*----------------------------------------------------------------------
  1579. -- literal set - parse literal set.
  1580. --
  1581. -- This routine parses literal set using the syntax:
  1582. --
  1583. -- <literal set> ::= { <member list> }
  1584. -- <member list> ::= <member expression>
  1585. -- <member list> ::= <member list> , <member expression>
  1586. -- <member expression> ::= <expression 5>
  1587. --
  1588. -- It is assumed that the left curly brace and the very first member
  1589. -- expression that follows it are already parsed. The right curly brace
  1590. -- remains unscanned on exit. */
  1591. CODE *literal_set(MPL *mpl, CODE *code)
  1592. { OPERANDS arg;
  1593. int j;
  1594. xassert(code != NULL);
  1595. arg.list = create_arg_list(mpl);
  1596. /* parse <member list> */
  1597. for (j = 1; ; j++)
  1598. { /* all member expressions must be n-tuples; so, if the current
  1599. expression is not n-tuple, convert it to 1-tuple */
  1600. if (code->type == A_NUMERIC)
  1601. code = make_unary(mpl, O_CVTSYM, code, A_SYMBOLIC, 0);
  1602. if (code->type == A_SYMBOLIC)
  1603. code = make_unary(mpl, O_CVTTUP, code, A_TUPLE, 1);
  1604. /* now the expression must be n-tuple */
  1605. if (code->type != A_TUPLE)
  1606. mpl_error(mpl, "member expression has invalid type");
  1607. /* all member expressions must have identical dimension */
  1608. if (arg.list != NULL && arg.list->x->dim != code->dim)
  1609. mpl_error(mpl, "member %d has %d component%s while member %d ha"
  1610. "s %d component%s",
  1611. j-1, arg.list->x->dim, arg.list->x->dim == 1 ? "" : "s",
  1612. j, code->dim, code->dim == 1 ? "" : "s");
  1613. /* append the current expression to the member list */
  1614. arg.list = expand_arg_list(mpl, arg.list, code);
  1615. /* check a token that follows the current expression */
  1616. if (mpl->token == T_COMMA)
  1617. get_token(mpl /* , */);
  1618. else if (mpl->token == T_RBRACE)
  1619. break;
  1620. else
  1621. mpl_error(mpl, "syntax error in literal set");
  1622. /* parse the next expression that follows the comma */
  1623. code = expression_5(mpl);
  1624. }
  1625. /* generate pseudo-code for <literal set> */
  1626. code = make_code(mpl, O_MAKE, &arg, A_ELEMSET, arg.list->x->dim);
  1627. return code;
  1628. }
  1629. /*----------------------------------------------------------------------
  1630. -- indexing_expression - parse indexing expression.
  1631. --
  1632. -- This routine parses indexing expression using the syntax:
  1633. --
  1634. -- <indexing expression> ::= <literal set>
  1635. -- <indexing expression> ::= { <indexing list> }
  1636. -- <indexing expression> ::= { <indexing list> : <logical expression> }
  1637. -- <indexing list> ::= <indexing element>
  1638. -- <indexing list> ::= <indexing list> , <indexing element>
  1639. -- <indexing element> ::= <basic expression>
  1640. -- <indexing element> ::= <dummy index> in <basic expression>
  1641. -- <indexing element> ::= <slice> in <basic expression>
  1642. -- <dummy index> ::= <symbolic name>
  1643. -- <slice> ::= ( <expression list> )
  1644. -- <basic expression> ::= <expression 9>
  1645. -- <logical expression> ::= <expression 13>
  1646. --
  1647. -- This routine creates domain for <indexing expression>, where each
  1648. -- domain block corresponds to <indexing element>, and each domain slot
  1649. -- corresponds to individual indexing position. */
  1650. DOMAIN *indexing_expression(MPL *mpl)
  1651. { DOMAIN *domain;
  1652. DOMAIN_BLOCK *block;
  1653. DOMAIN_SLOT *slot;
  1654. CODE *code;
  1655. xassert(mpl->token == T_LBRACE);
  1656. get_token(mpl /* { */);
  1657. if (mpl->token == T_RBRACE)
  1658. mpl_error(mpl, "empty indexing expression not allowed");
  1659. /* create domain to be constructed */
  1660. domain = create_domain(mpl);
  1661. /* parse either <member list> or <indexing list> that follows the
  1662. left brace */
  1663. for (;;)
  1664. { /* domain block for <indexing element> is not created yet */
  1665. block = NULL;
  1666. /* pseudo-code for <basic expression> is not generated yet */
  1667. code = NULL;
  1668. /* check a token, which <indexing element> begins with */
  1669. if (mpl->token == T_NAME)
  1670. { /* it is a symbolic name */
  1671. int next_token;
  1672. char *name;
  1673. /* symbolic name is recognized as dummy index only if it is
  1674. followed by the keyword 'in' and not declared */
  1675. get_token(mpl /* <symbolic name> */);
  1676. next_token = mpl->token;
  1677. unget_token(mpl);
  1678. if (!(next_token == T_IN &&
  1679. avl_find_node(mpl->tree, mpl->image) == NULL))
  1680. { /* this is not dummy index; the symbolic name begins an
  1681. expression, which is either <basic expression> or the
  1682. very first <member expression> in <literal set> */
  1683. goto expr;
  1684. }
  1685. /* create domain block with one slot, which is assigned the
  1686. dummy index */
  1687. block = create_block(mpl);
  1688. name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  1689. strcpy(name, mpl->image);
  1690. append_slot(mpl, block, name, NULL);
  1691. get_token(mpl /* <symbolic name> */);
  1692. /* the keyword 'in' is already checked above */
  1693. xassert(mpl->token == T_IN);
  1694. get_token(mpl /* in */);
  1695. /* <basic expression> that follows the keyword 'in' will be
  1696. parsed below */
  1697. }
  1698. else if (mpl->token == T_LEFT)
  1699. { /* it is the left parenthesis; parse expression that begins
  1700. with this parenthesis (the flag is set in order to allow
  1701. recognizing slices; see the routine expression_list) */
  1702. mpl->flag_x = 1;
  1703. code = expression_9(mpl);
  1704. if (code->op != O_SLICE)
  1705. { /* this is either <basic expression> or the very first
  1706. <member expression> in <literal set> */
  1707. goto expr;
  1708. }
  1709. /* this is a slice; besides the corresponding domain block
  1710. is already created by expression_list() */
  1711. block = code->arg.slice;
  1712. code = NULL; /* <basic expression> is not parsed yet */
  1713. /* the keyword 'in' following the slice is already checked
  1714. by expression_list() */
  1715. xassert(mpl->token == T_IN);
  1716. get_token(mpl /* in */);
  1717. /* <basic expression> that follows the keyword 'in' will be
  1718. parsed below */
  1719. }
  1720. expr: /* parse expression that follows either the keyword 'in' (in
  1721. which case it can be <basic expression) or the left brace
  1722. (in which case it can be <basic expression> as well as the
  1723. very first <member expression> in <literal set>); note that
  1724. this expression can be already parsed above */
  1725. if (code == NULL) code = expression_9(mpl);
  1726. /* check the type of the expression just parsed */
  1727. if (code->type != A_ELEMSET)
  1728. { /* it is not <basic expression> and therefore it can only
  1729. be the very first <member expression> in <literal set>;
  1730. however, then there must be no dummy index neither slice
  1731. between the left brace and this expression */
  1732. if (block != NULL)
  1733. mpl_error(mpl, "domain expression has invalid type");
  1734. /* parse the rest part of <literal set> and make this set
  1735. be <basic expression>, i.e. the construction {a, b, c}
  1736. is parsed as it were written as {A}, where A = {a, b, c}
  1737. is a temporary elemental set */
  1738. code = literal_set(mpl, code);
  1739. }
  1740. /* now pseudo-code for <basic set> has been built */
  1741. xassert(code != NULL);
  1742. xassert(code->type == A_ELEMSET);
  1743. xassert(code->dim > 0);
  1744. /* if domain block for the current <indexing element> is still
  1745. not created, create it for fake slice of the same dimension
  1746. as <basic set> */
  1747. if (block == NULL)
  1748. { int j;
  1749. block = create_block(mpl);
  1750. for (j = 1; j <= code->dim; j++)
  1751. append_slot(mpl, block, NULL, NULL);
  1752. }
  1753. /* number of indexing positions in <indexing element> must be
  1754. the same as dimension of n-tuples in basic set */
  1755. { int dim = 0;
  1756. for (slot = block->list; slot != NULL; slot = slot->next)
  1757. dim++;
  1758. if (dim != code->dim)
  1759. mpl_error(mpl,"%d %s specified for set of dimension %d",
  1760. dim, dim == 1 ? "index" : "indices", code->dim);
  1761. }
  1762. /* store pseudo-code for <basic set> in the domain block */
  1763. xassert(block->code == NULL);
  1764. block->code = code;
  1765. /* and append the domain block to the domain */
  1766. append_block(mpl, domain, block);
  1767. /* the current <indexing element> has been completely parsed;
  1768. include all its dummy indices into the symbolic name table
  1769. to make them available for referencing from expressions;
  1770. implicit declarations of dummy indices remain valid while
  1771. the corresponding domain scope is valid */
  1772. for (slot = block->list; slot != NULL; slot = slot->next)
  1773. if (slot->name != NULL)
  1774. { AVLNODE *node;
  1775. xassert(avl_find_node(mpl->tree, slot->name) == NULL);
  1776. node = avl_insert_node(mpl->tree, slot->name);
  1777. avl_set_node_type(node, A_INDEX);
  1778. avl_set_node_link(node, (void *)slot);
  1779. }
  1780. /* check a token that follows <indexing element> */
  1781. if (mpl->token == T_COMMA)
  1782. get_token(mpl /* , */);
  1783. else if (mpl->token == T_COLON || mpl->token == T_RBRACE)
  1784. break;
  1785. else
  1786. mpl_error(mpl, "syntax error in indexing expression");
  1787. }
  1788. /* parse <logical expression> that follows the colon */
  1789. if (mpl->token == T_COLON)
  1790. { get_token(mpl /* : */);
  1791. code = expression_13(mpl);
  1792. /* convert the expression to logical type, if necessary */
  1793. if (code->type == A_SYMBOLIC)
  1794. code = make_unary(mpl, O_CVTNUM, code, A_NUMERIC, 0);
  1795. if (code->type == A_NUMERIC)
  1796. code = make_unary(mpl, O_CVTLOG, code, A_LOGICAL, 0);
  1797. /* now the expression must be of logical type */
  1798. if (code->type != A_LOGICAL)
  1799. mpl_error(mpl, "expression following colon has invalid type");
  1800. xassert(code->dim == 0);
  1801. domain->code = code;
  1802. /* the right brace must follow the logical expression */
  1803. if (mpl->token != T_RBRACE)
  1804. mpl_error(mpl, "syntax error in indexing expression");
  1805. }
  1806. get_token(mpl /* } */);
  1807. return domain;
  1808. }
  1809. /*----------------------------------------------------------------------
  1810. -- close_scope - close scope of indexing expression.
  1811. --
  1812. -- The routine closes the scope of indexing expression specified by its
  1813. -- domain and thereby makes all dummy indices introduced in the indexing
  1814. -- expression no longer available for referencing. */
  1815. void close_scope(MPL *mpl, DOMAIN *domain)
  1816. { DOMAIN_BLOCK *block;
  1817. DOMAIN_SLOT *slot;
  1818. AVLNODE *node;
  1819. xassert(domain != NULL);
  1820. /* remove all dummy indices from the symbolic names table */
  1821. for (block = domain->list; block != NULL; block = block->next)
  1822. { for (slot = block->list; slot != NULL; slot = slot->next)
  1823. { if (slot->name != NULL)
  1824. { node = avl_find_node(mpl->tree, slot->name);
  1825. xassert(node != NULL);
  1826. xassert(avl_get_node_type(node) == A_INDEX);
  1827. avl_delete_node(mpl->tree, node);
  1828. }
  1829. }
  1830. }
  1831. return;
  1832. }
  1833. /*----------------------------------------------------------------------
  1834. -- iterated_expression - parse iterated expression.
  1835. --
  1836. -- This routine parses primary expression using the syntax:
  1837. --
  1838. -- <primary expression> ::= <iterated expression>
  1839. -- <iterated expression> ::= sum <indexing expression> <expression 3>
  1840. -- <iterated expression> ::= prod <indexing expression> <expression 3>
  1841. -- <iterated expression> ::= min <indexing expression> <expression 3>
  1842. -- <iterated expression> ::= max <indexing expression> <expression 3>
  1843. -- <iterated expression> ::= exists <indexing expression>
  1844. -- <expression 12>
  1845. -- <iterated expression> ::= forall <indexing expression>
  1846. -- <expression 12>
  1847. -- <iterated expression> ::= setof <indexing expression> <expression 5>
  1848. --
  1849. -- Note that parsing "integrand" depends on the iterated operator. */
  1850. #if 1 /* 07/IX-2008 */
  1851. static void link_up(CODE *code)
  1852. { /* if we have something like sum{(i+1,j,k-1) in E} x[i,j,k],
  1853. where i and k are dummy indices defined out of the iterated
  1854. expression, we should link up pseudo-code for computing i+1
  1855. and k-1 to pseudo-code for computing the iterated expression;
  1856. this is needed to invalidate current value of the iterated
  1857. expression once i or k have been changed */
  1858. DOMAIN_BLOCK *block;
  1859. DOMAIN_SLOT *slot;
  1860. for (block = code->arg.loop.domain->list; block != NULL;
  1861. block = block->next)
  1862. { for (slot = block->list; slot != NULL; slot = slot->next)
  1863. { if (slot->code != NULL)
  1864. { xassert(slot->code->up == NULL);
  1865. slot->code->up = code;
  1866. }
  1867. }
  1868. }
  1869. return;
  1870. }
  1871. #endif
  1872. CODE *iterated_expression(MPL *mpl)
  1873. { CODE *code;
  1874. OPERANDS arg;
  1875. int op;
  1876. char opstr[8];
  1877. /* determine operation code */
  1878. xassert(mpl->token == T_NAME);
  1879. if (strcmp(mpl->image, "sum") == 0)
  1880. op = O_SUM;
  1881. else if (strcmp(mpl->image, "prod") == 0)
  1882. op = O_PROD;
  1883. else if (strcmp(mpl->image, "min") == 0)
  1884. op = O_MINIMUM;
  1885. else if (strcmp(mpl->image, "max") == 0)
  1886. op = O_MAXIMUM;
  1887. else if (strcmp(mpl->image, "forall") == 0)
  1888. op = O_FORALL;
  1889. else if (strcmp(mpl->image, "exists") == 0)
  1890. op = O_EXISTS;
  1891. else if (strcmp(mpl->image, "setof") == 0)
  1892. op = O_SETOF;
  1893. else
  1894. mpl_error(mpl, "operator %s unknown", mpl->image);
  1895. strcpy(opstr, mpl->image);
  1896. xassert(strlen(opstr) < sizeof(opstr));
  1897. get_token(mpl /* <symbolic name> */);
  1898. /* check the left brace that follows the operator name */
  1899. xassert(mpl->token == T_LBRACE);
  1900. /* parse indexing expression that controls iterating */
  1901. arg.loop.domain = indexing_expression(mpl);
  1902. /* parse "integrand" expression and generate pseudo-code */
  1903. switch (op)
  1904. { case O_SUM:
  1905. case O_PROD:
  1906. case O_MINIMUM:
  1907. case O_MAXIMUM:
  1908. arg.loop.x = expression_3(mpl);
  1909. /* convert the integrand to numeric type, if necessary */
  1910. if (arg.loop.x->type == A_SYMBOLIC)
  1911. arg.loop.x = make_unary(mpl, O_CVTNUM, arg.loop.x,
  1912. A_NUMERIC, 0);
  1913. /* now the integrand must be of numeric type or linear form
  1914. (the latter is only allowed for the sum operator) */
  1915. if (!(arg.loop.x->type == A_NUMERIC ||
  1916. op == O_SUM && arg.loop.x->type == A_FORMULA))
  1917. err: mpl_error(mpl, "integrand following %s{...} has invalid type"
  1918. , opstr);
  1919. xassert(arg.loop.x->dim == 0);
  1920. /* generate pseudo-code */
  1921. code = make_code(mpl, op, &arg, arg.loop.x->type, 0);
  1922. break;
  1923. case O_FORALL:
  1924. case O_EXISTS:
  1925. arg.loop.x = expression_12(mpl);
  1926. /* convert the integrand to logical type, if necessary */
  1927. if (arg.loop.x->type == A_SYMBOLIC)
  1928. arg.loop.x = make_unary(mpl, O_CVTNUM, arg.loop.x,
  1929. A_NUMERIC, 0);
  1930. if (arg.loop.x->type == A_NUMERIC)
  1931. arg.loop.x = make_unary(mpl, O_CVTLOG, arg.loop.x,
  1932. A_LOGICAL, 0);
  1933. /* now the integrand must be of logical type */
  1934. if (arg.loop.x->type != A_LOGICAL) goto err;
  1935. xassert(arg.loop.x->dim == 0);
  1936. /* generate pseudo-code */
  1937. code = make_code(mpl, op, &arg, A_LOGICAL, 0);
  1938. break;
  1939. case O_SETOF:
  1940. arg.loop.x = expression_5(mpl);
  1941. /* convert the integrand to 1-tuple, if necessary */
  1942. if (arg.loop.x->type == A_NUMERIC)
  1943. arg.loop.x = make_unary(mpl, O_CVTSYM, arg.loop.x,
  1944. A_SYMBOLIC, 0);
  1945. if (arg.loop.x->type == A_SYMBOLIC)
  1946. arg.loop.x = make_unary(mpl, O_CVTTUP, arg.loop.x,
  1947. A_TUPLE, 1);
  1948. /* now the integrand must be n-tuple */
  1949. if (arg.loop.x->type != A_TUPLE) goto err;
  1950. xassert(arg.loop.x->dim > 0);
  1951. /* generate pseudo-code */
  1952. code = make_code(mpl, op, &arg, A_ELEMSET, arg.loop.x->dim);
  1953. break;
  1954. default:
  1955. xassert(op != op);
  1956. }
  1957. /* close the scope of the indexing expression */
  1958. close_scope(mpl, arg.loop.domain);
  1959. #if 1 /* 07/IX-2008 */
  1960. link_up(code);
  1961. #endif
  1962. return code;
  1963. }
  1964. /*----------------------------------------------------------------------
  1965. -- domain_arity - determine arity of domain.
  1966. --
  1967. -- This routine returns arity of specified domain, which is number of
  1968. -- its free dummy indices. */
  1969. int domain_arity(MPL *mpl, DOMAIN *domain)
  1970. { DOMAIN_BLOCK *block;
  1971. DOMAIN_SLOT *slot;
  1972. int arity;
  1973. xassert(mpl == mpl);
  1974. arity = 0;
  1975. for (block = domain->list; block != NULL; block = block->next)
  1976. for (slot = block->list; slot != NULL; slot = slot->next)
  1977. if (slot->code == NULL) arity++;
  1978. return arity;
  1979. }
  1980. /*----------------------------------------------------------------------
  1981. -- set_expression - parse set expression.
  1982. --
  1983. -- This routine parses primary expression using the syntax:
  1984. --
  1985. -- <primary expression> ::= { }
  1986. -- <primary expression> ::= <indexing expression> */
  1987. CODE *set_expression(MPL *mpl)
  1988. { CODE *code;
  1989. OPERANDS arg;
  1990. xassert(mpl->token == T_LBRACE);
  1991. get_token(mpl /* { */);
  1992. /* check a token that follows the left brace */
  1993. if (mpl->token == T_RBRACE)
  1994. { /* it is the right brace, so the resultant is an empty set of
  1995. dimension 1 */
  1996. arg.list = NULL;
  1997. /* generate pseudo-code to build the resultant set */
  1998. code = make_code(mpl, O_MAKE, &arg, A_ELEMSET, 1);
  1999. get_token(mpl /* } */);
  2000. }
  2001. else
  2002. { /* the next token begins an indexing expression */
  2003. unget_token(mpl);
  2004. arg.loop.domain = indexing_expression(mpl);
  2005. arg.loop.x = NULL; /* integrand is not used */
  2006. /* close the scope of the indexing expression */
  2007. close_scope(mpl, arg.loop.domain);
  2008. /* generate pseudo-code to build the resultant set */
  2009. code = make_code(mpl, O_BUILD, &arg, A_ELEMSET,
  2010. domain_arity(mpl, arg.loop.domain));
  2011. #if 1 /* 07/IX-2008 */
  2012. link_up(code);
  2013. #endif
  2014. }
  2015. return code;
  2016. }
  2017. /*----------------------------------------------------------------------
  2018. -- branched_expression - parse conditional expression.
  2019. --
  2020. -- This routine parses primary expression using the syntax:
  2021. --
  2022. -- <primary expression> ::= <branched expression>
  2023. -- <branched expression> ::= if <logical expression> then <expression 9>
  2024. -- <branched expression> ::= if <logical expression> then <expression 9>
  2025. -- else <expression 9>
  2026. -- <logical expression> ::= <expression 13> */
  2027. CODE *branched_expression(MPL *mpl)
  2028. { CODE *code, *x, *y, *z;
  2029. xassert(mpl->token == T_IF);
  2030. get_token(mpl /* if */);
  2031. /* parse <logical expression> that follows 'if' */
  2032. x = expression_13(mpl);
  2033. /* convert the expression to logical type, if necessary */
  2034. if (x->type == A_SYMBOLIC)
  2035. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2036. if (x->type == A_NUMERIC)
  2037. x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0);
  2038. /* now the expression must be of logical type */
  2039. if (x->type != A_LOGICAL)
  2040. mpl_error(mpl, "expression following if has invalid type");
  2041. xassert(x->dim == 0);
  2042. /* the keyword 'then' must follow the logical expression */
  2043. if (mpl->token != T_THEN)
  2044. mpl_error(mpl, "keyword then missing where expected");
  2045. get_token(mpl /* then */);
  2046. /* parse <expression> that follows 'then' and check its type */
  2047. y = expression_9(mpl);
  2048. if (!(y->type == A_NUMERIC || y->type == A_SYMBOLIC ||
  2049. y->type == A_ELEMSET || y->type == A_FORMULA))
  2050. mpl_error(mpl, "expression following then has invalid type");
  2051. /* if the expression that follows the keyword 'then' is elemental
  2052. set, the keyword 'else' cannot be omitted; otherwise else-part
  2053. is optional */
  2054. if (mpl->token != T_ELSE)
  2055. { if (y->type == A_ELEMSET)
  2056. mpl_error(mpl, "keyword else missing where expected");
  2057. z = NULL;
  2058. goto skip;
  2059. }
  2060. get_token(mpl /* else */);
  2061. /* parse <expression> that follow 'else' and check its type */
  2062. z = expression_9(mpl);
  2063. if (!(z->type == A_NUMERIC || z->type == A_SYMBOLIC ||
  2064. z->type == A_ELEMSET || z->type == A_FORMULA))
  2065. mpl_error(mpl, "expression following else has invalid type");
  2066. /* convert to identical types, if necessary */
  2067. if (y->type == A_FORMULA || z->type == A_FORMULA)
  2068. { if (y->type == A_SYMBOLIC)
  2069. y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
  2070. if (y->type == A_NUMERIC)
  2071. y = make_unary(mpl, O_CVTLFM, y, A_FORMULA, 0);
  2072. if (z->type == A_SYMBOLIC)
  2073. z = make_unary(mpl, O_CVTNUM, z, A_NUMERIC, 0);
  2074. if (z->type == A_NUMERIC)
  2075. z = make_unary(mpl, O_CVTLFM, z, A_FORMULA, 0);
  2076. }
  2077. if (y->type == A_SYMBOLIC || z->type == A_SYMBOLIC)
  2078. { if (y->type == A_NUMERIC)
  2079. y = make_unary(mpl, O_CVTSYM, y, A_SYMBOLIC, 0);
  2080. if (z->type == A_NUMERIC)
  2081. z = make_unary(mpl, O_CVTSYM, z, A_SYMBOLIC, 0);
  2082. }
  2083. /* now both expressions must have identical types */
  2084. if (y->type != z->type)
  2085. mpl_error(mpl, "expressions following then and else have incompati"
  2086. "ble types");
  2087. /* and identical dimensions */
  2088. if (y->dim != z->dim)
  2089. mpl_error(mpl, "expressions following then and else have different"
  2090. " dimensions %d and %d, respectively", y->dim, z->dim);
  2091. skip: /* generate pseudo-code to perform branching */
  2092. code = make_ternary(mpl, O_FORK, x, y, z, y->type, y->dim);
  2093. return code;
  2094. }
  2095. /*----------------------------------------------------------------------
  2096. -- primary_expression - parse primary expression.
  2097. --
  2098. -- This routine parses primary expression using the syntax:
  2099. --
  2100. -- <primary expression> ::= <numeric literal>
  2101. -- <primary expression> ::= Infinity
  2102. -- <primary expression> ::= <string literal>
  2103. -- <primary expression> ::= <dummy index>
  2104. -- <primary expression> ::= <set name>
  2105. -- <primary expression> ::= <set name> [ <subscript list> ]
  2106. -- <primary expression> ::= <parameter name>
  2107. -- <primary expression> ::= <parameter name> [ <subscript list> ]
  2108. -- <primary expression> ::= <variable name>
  2109. -- <primary expression> ::= <variable name> [ <subscript list> ]
  2110. -- <primary expression> ::= <built-in function> ( <argument list> )
  2111. -- <primary expression> ::= ( <expression list> )
  2112. -- <primary expression> ::= <iterated expression>
  2113. -- <primary expression> ::= { }
  2114. -- <primary expression> ::= <indexing expression>
  2115. -- <primary expression> ::= <branched expression>
  2116. --
  2117. -- For complete list of syntactic rules for <primary expression> see
  2118. -- comments to the corresponding parsing routines. */
  2119. CODE *primary_expression(MPL *mpl)
  2120. { CODE *code;
  2121. if (mpl->token == T_NUMBER)
  2122. { /* parse numeric literal */
  2123. code = numeric_literal(mpl);
  2124. }
  2125. #if 1 /* 21/VII-2006 */
  2126. else if (mpl->token == T_INFINITY)
  2127. { /* parse "infinity" */
  2128. OPERANDS arg;
  2129. arg.num = DBL_MAX;
  2130. code = make_code(mpl, O_NUMBER, &arg, A_NUMERIC, 0);
  2131. get_token(mpl /* Infinity */);
  2132. }
  2133. #endif
  2134. else if (mpl->token == T_STRING)
  2135. { /* parse string literal */
  2136. code = string_literal(mpl);
  2137. }
  2138. else if (mpl->token == T_NAME)
  2139. { int next_token;
  2140. get_token(mpl /* <symbolic name> */);
  2141. next_token = mpl->token;
  2142. unget_token(mpl);
  2143. /* check a token that follows <symbolic name> */
  2144. switch (next_token)
  2145. { case T_LBRACKET:
  2146. /* parse reference to subscripted object */
  2147. code = object_reference(mpl);
  2148. break;
  2149. case T_LEFT:
  2150. /* parse reference to built-in function */
  2151. code = function_reference(mpl);
  2152. break;
  2153. case T_LBRACE:
  2154. /* parse iterated expression */
  2155. code = iterated_expression(mpl);
  2156. break;
  2157. default:
  2158. /* parse reference to unsubscripted object */
  2159. code = object_reference(mpl);
  2160. break;
  2161. }
  2162. }
  2163. else if (mpl->token == T_LEFT)
  2164. { /* parse parenthesized expression */
  2165. code = expression_list(mpl);
  2166. }
  2167. else if (mpl->token == T_LBRACE)
  2168. { /* parse set expression */
  2169. code = set_expression(mpl);
  2170. }
  2171. else if (mpl->token == T_IF)
  2172. { /* parse conditional expression */
  2173. code = branched_expression(mpl);
  2174. }
  2175. else if (is_reserved(mpl))
  2176. { /* other reserved keywords cannot be used here */
  2177. mpl_error(mpl, "invalid use of reserved keyword %s", mpl->image);
  2178. }
  2179. else
  2180. mpl_error(mpl, "syntax error in expression");
  2181. return code;
  2182. }
  2183. /*----------------------------------------------------------------------
  2184. -- error_preceding - raise error if preceding operand has wrong type.
  2185. --
  2186. -- This routine is called to raise error if operand that precedes some
  2187. -- infix operator has invalid type. */
  2188. void error_preceding(MPL *mpl, char *opstr)
  2189. { mpl_error(mpl, "operand preceding %s has invalid type", opstr);
  2190. /* no return */
  2191. }
  2192. /*----------------------------------------------------------------------
  2193. -- error_following - raise error if following operand has wrong type.
  2194. --
  2195. -- This routine is called to raise error if operand that follows some
  2196. -- infix operator has invalid type. */
  2197. void error_following(MPL *mpl, char *opstr)
  2198. { mpl_error(mpl, "operand following %s has invalid type", opstr);
  2199. /* no return */
  2200. }
  2201. /*----------------------------------------------------------------------
  2202. -- error_dimension - raise error if operands have different dimension.
  2203. --
  2204. -- This routine is called to raise error if two operands of some infix
  2205. -- operator have different dimension. */
  2206. void error_dimension(MPL *mpl, char *opstr, int dim1, int dim2)
  2207. { mpl_error(mpl, "operands preceding and following %s have different di"
  2208. "mensions %d and %d, respectively", opstr, dim1, dim2);
  2209. /* no return */
  2210. }
  2211. /*----------------------------------------------------------------------
  2212. -- expression_0 - parse expression of level 0.
  2213. --
  2214. -- This routine parses expression of level 0 using the syntax:
  2215. --
  2216. -- <expression 0> ::= <primary expression> */
  2217. CODE *expression_0(MPL *mpl)
  2218. { CODE *code;
  2219. code = primary_expression(mpl);
  2220. return code;
  2221. }
  2222. /*----------------------------------------------------------------------
  2223. -- expression_1 - parse expression of level 1.
  2224. --
  2225. -- This routine parses expression of level 1 using the syntax:
  2226. --
  2227. -- <expression 1> ::= <expression 0>
  2228. -- <expression 1> ::= <expression 0> <power> <expression 1>
  2229. -- <expression 1> ::= <expression 0> <power> <expression 2>
  2230. -- <power> ::= ^ | ** */
  2231. CODE *expression_1(MPL *mpl)
  2232. { CODE *x, *y;
  2233. char opstr[8];
  2234. x = expression_0(mpl);
  2235. if (mpl->token == T_POWER)
  2236. { strcpy(opstr, mpl->image);
  2237. xassert(strlen(opstr) < sizeof(opstr));
  2238. if (x->type == A_SYMBOLIC)
  2239. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2240. if (x->type != A_NUMERIC)
  2241. error_preceding(mpl, opstr);
  2242. get_token(mpl /* ^ | ** */);
  2243. if (mpl->token == T_PLUS || mpl->token == T_MINUS)
  2244. y = expression_2(mpl);
  2245. else
  2246. y = expression_1(mpl);
  2247. if (y->type == A_SYMBOLIC)
  2248. y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
  2249. if (y->type != A_NUMERIC)
  2250. error_following(mpl, opstr);
  2251. x = make_binary(mpl, O_POWER, x, y, A_NUMERIC, 0);
  2252. }
  2253. return x;
  2254. }
  2255. /*----------------------------------------------------------------------
  2256. -- expression_2 - parse expression of level 2.
  2257. --
  2258. -- This routine parses expression of level 2 using the syntax:
  2259. --
  2260. -- <expression 2> ::= <expression 1>
  2261. -- <expression 2> ::= + <expression 1>
  2262. -- <expression 2> ::= - <expression 1> */
  2263. CODE *expression_2(MPL *mpl)
  2264. { CODE *x;
  2265. if (mpl->token == T_PLUS)
  2266. { get_token(mpl /* + */);
  2267. x = expression_1(mpl);
  2268. if (x->type == A_SYMBOLIC)
  2269. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2270. if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
  2271. error_following(mpl, "+");
  2272. x = make_unary(mpl, O_PLUS, x, x->type, 0);
  2273. }
  2274. else if (mpl->token == T_MINUS)
  2275. { get_token(mpl /* - */);
  2276. x = expression_1(mpl);
  2277. if (x->type == A_SYMBOLIC)
  2278. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2279. if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
  2280. error_following(mpl, "-");
  2281. x = make_unary(mpl, O_MINUS, x, x->type, 0);
  2282. }
  2283. else
  2284. x = expression_1(mpl);
  2285. return x;
  2286. }
  2287. /*----------------------------------------------------------------------
  2288. -- expression_3 - parse expression of level 3.
  2289. --
  2290. -- This routine parses expression of level 3 using the syntax:
  2291. --
  2292. -- <expression 3> ::= <expression 2>
  2293. -- <expression 3> ::= <expression 3> * <expression 2>
  2294. -- <expression 3> ::= <expression 3> / <expression 2>
  2295. -- <expression 3> ::= <expression 3> div <expression 2>
  2296. -- <expression 3> ::= <expression 3> mod <expression 2> */
  2297. CODE *expression_3(MPL *mpl)
  2298. { CODE *x, *y;
  2299. x = expression_2(mpl);
  2300. for (;;)
  2301. { if (mpl->token == T_ASTERISK)
  2302. { if (x->type == A_SYMBOLIC)
  2303. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2304. if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
  2305. error_preceding(mpl, "*");
  2306. get_token(mpl /* * */);
  2307. y = expression_2(mpl);
  2308. if (y->type == A_SYMBOLIC)
  2309. y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
  2310. if (!(y->type == A_NUMERIC || y->type == A_FORMULA))
  2311. error_following(mpl, "*");
  2312. if (x->type == A_FORMULA && y->type == A_FORMULA)
  2313. mpl_error(mpl, "multiplication of linear forms not allowed");
  2314. if (x->type == A_NUMERIC && y->type == A_NUMERIC)
  2315. x = make_binary(mpl, O_MUL, x, y, A_NUMERIC, 0);
  2316. else
  2317. x = make_binary(mpl, O_MUL, x, y, A_FORMULA, 0);
  2318. }
  2319. else if (mpl->token == T_SLASH)
  2320. { if (x->type == A_SYMBOLIC)
  2321. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2322. if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
  2323. error_preceding(mpl, "/");
  2324. get_token(mpl /* / */);
  2325. y = expression_2(mpl);
  2326. if (y->type == A_SYMBOLIC)
  2327. y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
  2328. if (y->type != A_NUMERIC)
  2329. error_following(mpl, "/");
  2330. if (x->type == A_NUMERIC)
  2331. x = make_binary(mpl, O_DIV, x, y, A_NUMERIC, 0);
  2332. else
  2333. x = make_binary(mpl, O_DIV, x, y, A_FORMULA, 0);
  2334. }
  2335. else if (mpl->token == T_DIV)
  2336. { if (x->type == A_SYMBOLIC)
  2337. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2338. if (x->type != A_NUMERIC)
  2339. error_preceding(mpl, "div");
  2340. get_token(mpl /* div */);
  2341. y = expression_2(mpl);
  2342. if (y->type == A_SYMBOLIC)
  2343. y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
  2344. if (y->type != A_NUMERIC)
  2345. error_following(mpl, "div");
  2346. x = make_binary(mpl, O_IDIV, x, y, A_NUMERIC, 0);
  2347. }
  2348. else if (mpl->token == T_MOD)
  2349. { if (x->type == A_SYMBOLIC)
  2350. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2351. if (x->type != A_NUMERIC)
  2352. error_preceding(mpl, "mod");
  2353. get_token(mpl /* mod */);
  2354. y = expression_2(mpl);
  2355. if (y->type == A_SYMBOLIC)
  2356. y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
  2357. if (y->type != A_NUMERIC)
  2358. error_following(mpl, "mod");
  2359. x = make_binary(mpl, O_MOD, x, y, A_NUMERIC, 0);
  2360. }
  2361. else
  2362. break;
  2363. }
  2364. return x;
  2365. }
  2366. /*----------------------------------------------------------------------
  2367. -- expression_4 - parse expression of level 4.
  2368. --
  2369. -- This routine parses expression of level 4 using the syntax:
  2370. --
  2371. -- <expression 4> ::= <expression 3>
  2372. -- <expression 4> ::= <expression 4> + <expression 3>
  2373. -- <expression 4> ::= <expression 4> - <expression 3>
  2374. -- <expression 4> ::= <expression 4> less <expression 3> */
  2375. CODE *expression_4(MPL *mpl)
  2376. { CODE *x, *y;
  2377. x = expression_3(mpl);
  2378. for (;;)
  2379. { if (mpl->token == T_PLUS)
  2380. { if (x->type == A_SYMBOLIC)
  2381. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2382. if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
  2383. error_preceding(mpl, "+");
  2384. get_token(mpl /* + */);
  2385. y = expression_3(mpl);
  2386. if (y->type == A_SYMBOLIC)
  2387. y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
  2388. if (!(y->type == A_NUMERIC || y->type == A_FORMULA))
  2389. error_following(mpl, "+");
  2390. if (x->type == A_NUMERIC && y->type == A_FORMULA)
  2391. x = make_unary(mpl, O_CVTLFM, x, A_FORMULA, 0);
  2392. if (x->type == A_FORMULA && y->type == A_NUMERIC)
  2393. y = make_unary(mpl, O_CVTLFM, y, A_FORMULA, 0);
  2394. x = make_binary(mpl, O_ADD, x, y, x->type, 0);
  2395. }
  2396. else if (mpl->token == T_MINUS)
  2397. { if (x->type == A_SYMBOLIC)
  2398. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2399. if (!(x->type == A_NUMERIC || x->type == A_FORMULA))
  2400. error_preceding(mpl, "-");
  2401. get_token(mpl /* - */);
  2402. y = expression_3(mpl);
  2403. if (y->type == A_SYMBOLIC)
  2404. y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
  2405. if (!(y->type == A_NUMERIC || y->type == A_FORMULA))
  2406. error_following(mpl, "-");
  2407. if (x->type == A_NUMERIC && y->type == A_FORMULA)
  2408. x = make_unary(mpl, O_CVTLFM, x, A_FORMULA, 0);
  2409. if (x->type == A_FORMULA && y->type == A_NUMERIC)
  2410. y = make_unary(mpl, O_CVTLFM, y, A_FORMULA, 0);
  2411. x = make_binary(mpl, O_SUB, x, y, x->type, 0);
  2412. }
  2413. else if (mpl->token == T_LESS)
  2414. { if (x->type == A_SYMBOLIC)
  2415. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2416. if (x->type != A_NUMERIC)
  2417. error_preceding(mpl, "less");
  2418. get_token(mpl /* less */);
  2419. y = expression_3(mpl);
  2420. if (y->type == A_SYMBOLIC)
  2421. y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
  2422. if (y->type != A_NUMERIC)
  2423. error_following(mpl, "less");
  2424. x = make_binary(mpl, O_LESS, x, y, A_NUMERIC, 0);
  2425. }
  2426. else
  2427. break;
  2428. }
  2429. return x;
  2430. }
  2431. /*----------------------------------------------------------------------
  2432. -- expression_5 - parse expression of level 5.
  2433. --
  2434. -- This routine parses expression of level 5 using the syntax:
  2435. --
  2436. -- <expression 5> ::= <expression 4>
  2437. -- <expression 5> ::= <expression 5> & <expression 4> */
  2438. CODE *expression_5(MPL *mpl)
  2439. { CODE *x, *y;
  2440. x = expression_4(mpl);
  2441. for (;;)
  2442. { if (mpl->token == T_CONCAT)
  2443. { if (x->type == A_NUMERIC)
  2444. x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
  2445. if (x->type != A_SYMBOLIC)
  2446. error_preceding(mpl, "&");
  2447. get_token(mpl /* & */);
  2448. y = expression_4(mpl);
  2449. if (y->type == A_NUMERIC)
  2450. y = make_unary(mpl, O_CVTSYM, y, A_SYMBOLIC, 0);
  2451. if (y->type != A_SYMBOLIC)
  2452. error_following(mpl, "&");
  2453. x = make_binary(mpl, O_CONCAT, x, y, A_SYMBOLIC, 0);
  2454. }
  2455. else
  2456. break;
  2457. }
  2458. return x;
  2459. }
  2460. /*----------------------------------------------------------------------
  2461. -- expression_6 - parse expression of level 6.
  2462. --
  2463. -- This routine parses expression of level 6 using the syntax:
  2464. --
  2465. -- <expression 6> ::= <expression 5>
  2466. -- <expression 6> ::= <expression 5> .. <expression 5>
  2467. -- <expression 6> ::= <expression 5> .. <expression 5> by
  2468. -- <expression 5> */
  2469. CODE *expression_6(MPL *mpl)
  2470. { CODE *x, *y, *z;
  2471. x = expression_5(mpl);
  2472. if (mpl->token == T_DOTS)
  2473. { if (x->type == A_SYMBOLIC)
  2474. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2475. if (x->type != A_NUMERIC)
  2476. error_preceding(mpl, "..");
  2477. get_token(mpl /* .. */);
  2478. y = expression_5(mpl);
  2479. if (y->type == A_SYMBOLIC)
  2480. y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
  2481. if (y->type != A_NUMERIC)
  2482. error_following(mpl, "..");
  2483. if (mpl->token == T_BY)
  2484. { get_token(mpl /* by */);
  2485. z = expression_5(mpl);
  2486. if (z->type == A_SYMBOLIC)
  2487. z = make_unary(mpl, O_CVTNUM, z, A_NUMERIC, 0);
  2488. if (z->type != A_NUMERIC)
  2489. error_following(mpl, "by");
  2490. }
  2491. else
  2492. z = NULL;
  2493. x = make_ternary(mpl, O_DOTS, x, y, z, A_ELEMSET, 1);
  2494. }
  2495. return x;
  2496. }
  2497. /*----------------------------------------------------------------------
  2498. -- expression_7 - parse expression of level 7.
  2499. --
  2500. -- This routine parses expression of level 7 using the syntax:
  2501. --
  2502. -- <expression 7> ::= <expression 6>
  2503. -- <expression 7> ::= <expression 7> cross <expression 6> */
  2504. CODE *expression_7(MPL *mpl)
  2505. { CODE *x, *y;
  2506. x = expression_6(mpl);
  2507. for (;;)
  2508. { if (mpl->token == T_CROSS)
  2509. { if (x->type != A_ELEMSET)
  2510. error_preceding(mpl, "cross");
  2511. get_token(mpl /* cross */);
  2512. y = expression_6(mpl);
  2513. if (y->type != A_ELEMSET)
  2514. error_following(mpl, "cross");
  2515. x = make_binary(mpl, O_CROSS, x, y, A_ELEMSET,
  2516. x->dim + y->dim);
  2517. }
  2518. else
  2519. break;
  2520. }
  2521. return x;
  2522. }
  2523. /*----------------------------------------------------------------------
  2524. -- expression_8 - parse expression of level 8.
  2525. --
  2526. -- This routine parses expression of level 8 using the syntax:
  2527. --
  2528. -- <expression 8> ::= <expression 7>
  2529. -- <expression 8> ::= <expression 8> inter <expression 7> */
  2530. CODE *expression_8(MPL *mpl)
  2531. { CODE *x, *y;
  2532. x = expression_7(mpl);
  2533. for (;;)
  2534. { if (mpl->token == T_INTER)
  2535. { if (x->type != A_ELEMSET)
  2536. error_preceding(mpl, "inter");
  2537. get_token(mpl /* inter */);
  2538. y = expression_7(mpl);
  2539. if (y->type != A_ELEMSET)
  2540. error_following(mpl, "inter");
  2541. if (x->dim != y->dim)
  2542. error_dimension(mpl, "inter", x->dim, y->dim);
  2543. x = make_binary(mpl, O_INTER, x, y, A_ELEMSET, x->dim);
  2544. }
  2545. else
  2546. break;
  2547. }
  2548. return x;
  2549. }
  2550. /*----------------------------------------------------------------------
  2551. -- expression_9 - parse expression of level 9.
  2552. --
  2553. -- This routine parses expression of level 9 using the syntax:
  2554. --
  2555. -- <expression 9> ::= <expression 8>
  2556. -- <expression 9> ::= <expression 9> union <expression 8>
  2557. -- <expression 9> ::= <expression 9> diff <expression 8>
  2558. -- <expression 9> ::= <expression 9> symdiff <expression 8> */
  2559. CODE *expression_9(MPL *mpl)
  2560. { CODE *x, *y;
  2561. x = expression_8(mpl);
  2562. for (;;)
  2563. { if (mpl->token == T_UNION)
  2564. { if (x->type != A_ELEMSET)
  2565. error_preceding(mpl, "union");
  2566. get_token(mpl /* union */);
  2567. y = expression_8(mpl);
  2568. if (y->type != A_ELEMSET)
  2569. error_following(mpl, "union");
  2570. if (x->dim != y->dim)
  2571. error_dimension(mpl, "union", x->dim, y->dim);
  2572. x = make_binary(mpl, O_UNION, x, y, A_ELEMSET, x->dim);
  2573. }
  2574. else if (mpl->token == T_DIFF)
  2575. { if (x->type != A_ELEMSET)
  2576. error_preceding(mpl, "diff");
  2577. get_token(mpl /* diff */);
  2578. y = expression_8(mpl);
  2579. if (y->type != A_ELEMSET)
  2580. error_following(mpl, "diff");
  2581. if (x->dim != y->dim)
  2582. error_dimension(mpl, "diff", x->dim, y->dim);
  2583. x = make_binary(mpl, O_DIFF, x, y, A_ELEMSET, x->dim);
  2584. }
  2585. else if (mpl->token == T_SYMDIFF)
  2586. { if (x->type != A_ELEMSET)
  2587. error_preceding(mpl, "symdiff");
  2588. get_token(mpl /* symdiff */);
  2589. y = expression_8(mpl);
  2590. if (y->type != A_ELEMSET)
  2591. error_following(mpl, "symdiff");
  2592. if (x->dim != y->dim)
  2593. error_dimension(mpl, "symdiff", x->dim, y->dim);
  2594. x = make_binary(mpl, O_SYMDIFF, x, y, A_ELEMSET, x->dim);
  2595. }
  2596. else
  2597. break;
  2598. }
  2599. return x;
  2600. }
  2601. /*----------------------------------------------------------------------
  2602. -- expression_10 - parse expression of level 10.
  2603. --
  2604. -- This routine parses expression of level 10 using the syntax:
  2605. --
  2606. -- <expression 10> ::= <expression 9>
  2607. -- <expression 10> ::= <expression 9> <rho> <expression 9>
  2608. -- <rho> ::= < | <= | = | == | >= | > | <> | != | in | not in | ! in |
  2609. -- within | not within | ! within */
  2610. CODE *expression_10(MPL *mpl)
  2611. { CODE *x, *y;
  2612. int op = -1;
  2613. char opstr[16];
  2614. x = expression_9(mpl);
  2615. strcpy(opstr, "");
  2616. switch (mpl->token)
  2617. { case T_LT:
  2618. op = O_LT; break;
  2619. case T_LE:
  2620. op = O_LE; break;
  2621. case T_EQ:
  2622. op = O_EQ; break;
  2623. case T_GE:
  2624. op = O_GE; break;
  2625. case T_GT:
  2626. op = O_GT; break;
  2627. case T_NE:
  2628. op = O_NE; break;
  2629. case T_IN:
  2630. op = O_IN; break;
  2631. case T_WITHIN:
  2632. op = O_WITHIN; break;
  2633. case T_NOT:
  2634. strcpy(opstr, mpl->image);
  2635. get_token(mpl /* not | ! */);
  2636. if (mpl->token == T_IN)
  2637. op = O_NOTIN;
  2638. else if (mpl->token == T_WITHIN)
  2639. op = O_NOTWITHIN;
  2640. else
  2641. mpl_error(mpl, "invalid use of %s", opstr);
  2642. strcat(opstr, " ");
  2643. break;
  2644. default:
  2645. goto done;
  2646. }
  2647. strcat(opstr, mpl->image);
  2648. xassert(strlen(opstr) < sizeof(opstr));
  2649. switch (op)
  2650. { case O_EQ:
  2651. case O_NE:
  2652. #if 1 /* 02/VIII-2008 */
  2653. case O_LT:
  2654. case O_LE:
  2655. case O_GT:
  2656. case O_GE:
  2657. #endif
  2658. if (!(x->type == A_NUMERIC || x->type == A_SYMBOLIC))
  2659. error_preceding(mpl, opstr);
  2660. get_token(mpl /* <rho> */);
  2661. y = expression_9(mpl);
  2662. if (!(y->type == A_NUMERIC || y->type == A_SYMBOLIC))
  2663. error_following(mpl, opstr);
  2664. if (x->type == A_NUMERIC && y->type == A_SYMBOLIC)
  2665. x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
  2666. if (x->type == A_SYMBOLIC && y->type == A_NUMERIC)
  2667. y = make_unary(mpl, O_CVTSYM, y, A_SYMBOLIC, 0);
  2668. x = make_binary(mpl, op, x, y, A_LOGICAL, 0);
  2669. break;
  2670. #if 0 /* 02/VIII-2008 */
  2671. case O_LT:
  2672. case O_LE:
  2673. case O_GT:
  2674. case O_GE:
  2675. if (x->type == A_SYMBOLIC)
  2676. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2677. if (x->type != A_NUMERIC)
  2678. error_preceding(mpl, opstr);
  2679. get_token(mpl /* <rho> */);
  2680. y = expression_9(mpl);
  2681. if (y->type == A_SYMBOLIC)
  2682. y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
  2683. if (y->type != A_NUMERIC)
  2684. error_following(mpl, opstr);
  2685. x = make_binary(mpl, op, x, y, A_LOGICAL, 0);
  2686. break;
  2687. #endif
  2688. case O_IN:
  2689. case O_NOTIN:
  2690. if (x->type == A_NUMERIC)
  2691. x = make_unary(mpl, O_CVTSYM, x, A_SYMBOLIC, 0);
  2692. if (x->type == A_SYMBOLIC)
  2693. x = make_unary(mpl, O_CVTTUP, x, A_TUPLE, 1);
  2694. if (x->type != A_TUPLE)
  2695. error_preceding(mpl, opstr);
  2696. get_token(mpl /* <rho> */);
  2697. y = expression_9(mpl);
  2698. if (y->type != A_ELEMSET)
  2699. error_following(mpl, opstr);
  2700. if (x->dim != y->dim)
  2701. error_dimension(mpl, opstr, x->dim, y->dim);
  2702. x = make_binary(mpl, op, x, y, A_LOGICAL, 0);
  2703. break;
  2704. case O_WITHIN:
  2705. case O_NOTWITHIN:
  2706. if (x->type != A_ELEMSET)
  2707. error_preceding(mpl, opstr);
  2708. get_token(mpl /* <rho> */);
  2709. y = expression_9(mpl);
  2710. if (y->type != A_ELEMSET)
  2711. error_following(mpl, opstr);
  2712. if (x->dim != y->dim)
  2713. error_dimension(mpl, opstr, x->dim, y->dim);
  2714. x = make_binary(mpl, op, x, y, A_LOGICAL, 0);
  2715. break;
  2716. default:
  2717. xassert(op != op);
  2718. }
  2719. done: return x;
  2720. }
  2721. /*----------------------------------------------------------------------
  2722. -- expression_11 - parse expression of level 11.
  2723. --
  2724. -- This routine parses expression of level 11 using the syntax:
  2725. --
  2726. -- <expression 11> ::= <expression 10>
  2727. -- <expression 11> ::= not <expression 10>
  2728. -- <expression 11> ::= ! <expression 10> */
  2729. CODE *expression_11(MPL *mpl)
  2730. { CODE *x;
  2731. char opstr[8];
  2732. if (mpl->token == T_NOT)
  2733. { strcpy(opstr, mpl->image);
  2734. xassert(strlen(opstr) < sizeof(opstr));
  2735. get_token(mpl /* not | ! */);
  2736. x = expression_10(mpl);
  2737. if (x->type == A_SYMBOLIC)
  2738. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2739. if (x->type == A_NUMERIC)
  2740. x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0);
  2741. if (x->type != A_LOGICAL)
  2742. error_following(mpl, opstr);
  2743. x = make_unary(mpl, O_NOT, x, A_LOGICAL, 0);
  2744. }
  2745. else
  2746. x = expression_10(mpl);
  2747. return x;
  2748. }
  2749. /*----------------------------------------------------------------------
  2750. -- expression_12 - parse expression of level 12.
  2751. --
  2752. -- This routine parses expression of level 12 using the syntax:
  2753. --
  2754. -- <expression 12> ::= <expression 11>
  2755. -- <expression 12> ::= <expression 12> and <expression 11>
  2756. -- <expression 12> ::= <expression 12> && <expression 11> */
  2757. CODE *expression_12(MPL *mpl)
  2758. { CODE *x, *y;
  2759. char opstr[8];
  2760. x = expression_11(mpl);
  2761. for (;;)
  2762. { if (mpl->token == T_AND)
  2763. { strcpy(opstr, mpl->image);
  2764. xassert(strlen(opstr) < sizeof(opstr));
  2765. if (x->type == A_SYMBOLIC)
  2766. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2767. if (x->type == A_NUMERIC)
  2768. x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0);
  2769. if (x->type != A_LOGICAL)
  2770. error_preceding(mpl, opstr);
  2771. get_token(mpl /* and | && */);
  2772. y = expression_11(mpl);
  2773. if (y->type == A_SYMBOLIC)
  2774. y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
  2775. if (y->type == A_NUMERIC)
  2776. y = make_unary(mpl, O_CVTLOG, y, A_LOGICAL, 0);
  2777. if (y->type != A_LOGICAL)
  2778. error_following(mpl, opstr);
  2779. x = make_binary(mpl, O_AND, x, y, A_LOGICAL, 0);
  2780. }
  2781. else
  2782. break;
  2783. }
  2784. return x;
  2785. }
  2786. /*----------------------------------------------------------------------
  2787. -- expression_13 - parse expression of level 13.
  2788. --
  2789. -- This routine parses expression of level 13 using the syntax:
  2790. --
  2791. -- <expression 13> ::= <expression 12>
  2792. -- <expression 13> ::= <expression 13> or <expression 12>
  2793. -- <expression 13> ::= <expression 13> || <expression 12> */
  2794. CODE *expression_13(MPL *mpl)
  2795. { CODE *x, *y;
  2796. char opstr[8];
  2797. x = expression_12(mpl);
  2798. for (;;)
  2799. { if (mpl->token == T_OR)
  2800. { strcpy(opstr, mpl->image);
  2801. xassert(strlen(opstr) < sizeof(opstr));
  2802. if (x->type == A_SYMBOLIC)
  2803. x = make_unary(mpl, O_CVTNUM, x, A_NUMERIC, 0);
  2804. if (x->type == A_NUMERIC)
  2805. x = make_unary(mpl, O_CVTLOG, x, A_LOGICAL, 0);
  2806. if (x->type != A_LOGICAL)
  2807. error_preceding(mpl, opstr);
  2808. get_token(mpl /* or | || */);
  2809. y = expression_12(mpl);
  2810. if (y->type == A_SYMBOLIC)
  2811. y = make_unary(mpl, O_CVTNUM, y, A_NUMERIC, 0);
  2812. if (y->type == A_NUMERIC)
  2813. y = make_unary(mpl, O_CVTLOG, y, A_LOGICAL, 0);
  2814. if (y->type != A_LOGICAL)
  2815. error_following(mpl, opstr);
  2816. x = make_binary(mpl, O_OR, x, y, A_LOGICAL, 0);
  2817. }
  2818. else
  2819. break;
  2820. }
  2821. return x;
  2822. }
  2823. /*----------------------------------------------------------------------
  2824. -- set_statement - parse set statement.
  2825. --
  2826. -- This routine parses set statement using the syntax:
  2827. --
  2828. -- <set statement> ::= set <symbolic name> <alias> <domain>
  2829. -- <attributes> ;
  2830. -- <alias> ::= <empty>
  2831. -- <alias> ::= <string literal>
  2832. -- <domain> ::= <empty>
  2833. -- <domain> ::= <indexing expression>
  2834. -- <attributes> ::= <empty>
  2835. -- <attributes> ::= <attributes> , dimen <numeric literal>
  2836. -- <attributes> ::= <attributes> , within <expression 9>
  2837. -- <attributes> ::= <attributes> , := <expression 9>
  2838. -- <attributes> ::= <attributes> , default <expression 9>
  2839. --
  2840. -- Commae in <attributes> are optional and may be omitted anywhere. */
  2841. SET *set_statement(MPL *mpl)
  2842. { SET *set;
  2843. int dimen_used = 0;
  2844. xassert(is_keyword(mpl, "set"));
  2845. get_token(mpl /* set */);
  2846. /* symbolic name must follow the keyword 'set' */
  2847. if (mpl->token == T_NAME)
  2848. ;
  2849. else if (is_reserved(mpl))
  2850. mpl_error(mpl, "invalid use of reserved keyword %s", mpl->image);
  2851. else
  2852. mpl_error(mpl, "symbolic name missing where expected");
  2853. /* there must be no other object with the same name */
  2854. if (avl_find_node(mpl->tree, mpl->image) != NULL)
  2855. mpl_error(mpl, "%s multiply declared", mpl->image);
  2856. /* create model set */
  2857. set = alloc(SET);
  2858. set->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  2859. strcpy(set->name, mpl->image);
  2860. set->alias = NULL;
  2861. set->dim = 0;
  2862. set->domain = NULL;
  2863. set->dimen = 0;
  2864. set->within = NULL;
  2865. set->assign = NULL;
  2866. set->option = NULL;
  2867. set->gadget = NULL;
  2868. set->data = 0;
  2869. set->array = NULL;
  2870. get_token(mpl /* <symbolic name> */);
  2871. /* parse optional alias */
  2872. if (mpl->token == T_STRING)
  2873. { set->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  2874. strcpy(set->alias, mpl->image);
  2875. get_token(mpl /* <string literal> */);
  2876. }
  2877. /* parse optional indexing expression */
  2878. if (mpl->token == T_LBRACE)
  2879. { set->domain = indexing_expression(mpl);
  2880. set->dim = domain_arity(mpl, set->domain);
  2881. }
  2882. /* include the set name in the symbolic names table */
  2883. { AVLNODE *node;
  2884. node = avl_insert_node(mpl->tree, set->name);
  2885. avl_set_node_type(node, A_SET);
  2886. avl_set_node_link(node, (void *)set);
  2887. }
  2888. /* parse the list of optional attributes */
  2889. for (;;)
  2890. { if (mpl->token == T_COMMA)
  2891. get_token(mpl /* , */);
  2892. else if (mpl->token == T_SEMICOLON)
  2893. break;
  2894. if (is_keyword(mpl, "dimen"))
  2895. { /* dimension of set members */
  2896. int dimen;
  2897. get_token(mpl /* dimen */);
  2898. if (!(mpl->token == T_NUMBER &&
  2899. 1.0 <= mpl->value && mpl->value <= 20.0 &&
  2900. floor(mpl->value) == mpl->value))
  2901. mpl_error(mpl, "dimension must be integer between 1 and 20");
  2902. dimen = (int)(mpl->value + 0.5);
  2903. if (dimen_used)
  2904. mpl_error(mpl, "at most one dimension attribute allowed");
  2905. if (set->dimen > 0)
  2906. mpl_error(mpl, "dimension %d conflicts with dimension %d alr"
  2907. "eady determined", dimen, set->dimen);
  2908. set->dimen = dimen;
  2909. dimen_used = 1;
  2910. get_token(mpl /* <numeric literal> */);
  2911. }
  2912. else if (mpl->token == T_WITHIN || mpl->token == T_IN)
  2913. { /* restricting superset */
  2914. WITHIN *within, *temp;
  2915. if (mpl->token == T_IN && !mpl->as_within)
  2916. { warning(mpl, "keyword in understood as within");
  2917. mpl->as_within = 1;
  2918. }
  2919. get_token(mpl /* within */);
  2920. /* create new restricting superset list entry and append it
  2921. to the within-list */
  2922. within = alloc(WITHIN);
  2923. within->code = NULL;
  2924. within->next = NULL;
  2925. if (set->within == NULL)
  2926. set->within = within;
  2927. else
  2928. { for (temp = set->within; temp->next != NULL; temp =
  2929. temp->next);
  2930. temp->next = within;
  2931. }
  2932. /* parse an expression that follows 'within' */
  2933. within->code = expression_9(mpl);
  2934. if (within->code->type != A_ELEMSET)
  2935. mpl_error(mpl, "expression following within has invalid type"
  2936. );
  2937. xassert(within->code->dim > 0);
  2938. /* check/set dimension of set members */
  2939. if (set->dimen == 0) set->dimen = within->code->dim;
  2940. if (set->dimen != within->code->dim)
  2941. mpl_error(mpl, "set expression following within must have di"
  2942. "mension %d rather than %d",
  2943. set->dimen, within->code->dim);
  2944. }
  2945. else if (mpl->token == T_ASSIGN)
  2946. { /* assignment expression */
  2947. if (!(set->assign == NULL && set->option == NULL &&
  2948. set->gadget == NULL))
  2949. err: mpl_error(mpl, "at most one := or default/data allowed");
  2950. get_token(mpl /* := */);
  2951. /* parse an expression that follows ':=' */
  2952. set->assign = expression_9(mpl);
  2953. if (set->assign->type != A_ELEMSET)
  2954. mpl_error(mpl, "expression following := has invalid type");
  2955. xassert(set->assign->dim > 0);
  2956. /* check/set dimension of set members */
  2957. if (set->dimen == 0) set->dimen = set->assign->dim;
  2958. if (set->dimen != set->assign->dim)
  2959. mpl_error(mpl, "set expression following := must have dimens"
  2960. "ion %d rather than %d",
  2961. set->dimen, set->assign->dim);
  2962. }
  2963. else if (is_keyword(mpl, "default"))
  2964. { /* expression for default value */
  2965. if (!(set->assign == NULL && set->option == NULL)) goto err;
  2966. get_token(mpl /* := */);
  2967. /* parse an expression that follows 'default' */
  2968. set->option = expression_9(mpl);
  2969. if (set->option->type != A_ELEMSET)
  2970. mpl_error(mpl, "expression following default has invalid typ"
  2971. "e");
  2972. xassert(set->option->dim > 0);
  2973. /* check/set dimension of set members */
  2974. if (set->dimen == 0) set->dimen = set->option->dim;
  2975. if (set->dimen != set->option->dim)
  2976. mpl_error(mpl, "set expression following default must have d"
  2977. "imension %d rather than %d",
  2978. set->dimen, set->option->dim);
  2979. }
  2980. #if 1 /* 12/XII-2008 */
  2981. else if (is_keyword(mpl, "data"))
  2982. { /* gadget to initialize the set by data from plain set */
  2983. GADGET *gadget;
  2984. AVLNODE *node;
  2985. int i, k, fff[20];
  2986. if (!(set->assign == NULL && set->gadget == NULL)) goto err;
  2987. get_token(mpl /* data */);
  2988. set->gadget = gadget = alloc(GADGET);
  2989. /* set name must follow the keyword 'data' */
  2990. if (mpl->token == T_NAME)
  2991. ;
  2992. else if (is_reserved(mpl))
  2993. mpl_error(mpl, "invalid use of reserved keyword %s",
  2994. mpl->image);
  2995. else
  2996. mpl_error(mpl, "set name missing where expected");
  2997. /* find the set in the symbolic name table */
  2998. node = avl_find_node(mpl->tree, mpl->image);
  2999. if (node == NULL)
  3000. mpl_error(mpl, "%s not defined", mpl->image);
  3001. if (avl_get_node_type(node) != A_SET)
  3002. err1: mpl_error(mpl, "%s not a plain set", mpl->image);
  3003. gadget->set = avl_get_node_link(node);
  3004. if (gadget->set->dim != 0) goto err1;
  3005. if (gadget->set == set)
  3006. mpl_error(mpl, "set cannot be initialized by itself");
  3007. /* check and set dimensions */
  3008. if (set->dim >= gadget->set->dimen)
  3009. err2: mpl_error(mpl, "dimension of %s too small", mpl->image);
  3010. if (set->dimen == 0)
  3011. set->dimen = gadget->set->dimen - set->dim;
  3012. if (set->dim + set->dimen > gadget->set->dimen)
  3013. goto err2;
  3014. else if (set->dim + set->dimen < gadget->set->dimen)
  3015. mpl_error(mpl, "dimension of %s too big", mpl->image);
  3016. get_token(mpl /* set name */);
  3017. /* left parenthesis must follow the set name */
  3018. if (mpl->token == T_LEFT)
  3019. get_token(mpl /* ( */);
  3020. else
  3021. mpl_error(mpl, "left parenthesis missing where expected");
  3022. /* parse permutation of component numbers */
  3023. for (k = 0; k < gadget->set->dimen; k++) fff[k] = 0;
  3024. k = 0;
  3025. for (;;)
  3026. { if (mpl->token != T_NUMBER)
  3027. mpl_error(mpl, "component number missing where expected");
  3028. if (str2int(mpl->image, &i) != 0)
  3029. err3: mpl_error(mpl, "component number must be integer between "
  3030. "1 and %d", gadget->set->dimen);
  3031. if (!(1 <= i && i <= gadget->set->dimen)) goto err3;
  3032. if (fff[i-1] != 0)
  3033. mpl_error(mpl, "component %d multiply specified", i);
  3034. gadget->ind[k++] = i, fff[i-1] = 1;
  3035. xassert(k <= gadget->set->dimen);
  3036. get_token(mpl /* number */);
  3037. if (mpl->token == T_COMMA)
  3038. get_token(mpl /* , */);
  3039. else if (mpl->token == T_RIGHT)
  3040. break;
  3041. else
  3042. mpl_error(mpl, "syntax error in data attribute");
  3043. }
  3044. if (k < gadget->set->dimen)
  3045. mpl_error(mpl, "there are must be %d components rather than "
  3046. "%d", gadget->set->dimen, k);
  3047. get_token(mpl /* ) */);
  3048. }
  3049. #endif
  3050. else
  3051. mpl_error(mpl, "syntax error in set statement");
  3052. }
  3053. /* close the domain scope */
  3054. if (set->domain != NULL) close_scope(mpl, set->domain);
  3055. /* if dimension of set members is still unknown, set it to 1 */
  3056. if (set->dimen == 0) set->dimen = 1;
  3057. /* the set statement has been completely parsed */
  3058. xassert(mpl->token == T_SEMICOLON);
  3059. get_token(mpl /* ; */);
  3060. return set;
  3061. }
  3062. /*----------------------------------------------------------------------
  3063. -- parameter_statement - parse parameter statement.
  3064. --
  3065. -- This routine parses parameter statement using the syntax:
  3066. --
  3067. -- <parameter statement> ::= param <symbolic name> <alias> <domain>
  3068. -- <attributes> ;
  3069. -- <alias> ::= <empty>
  3070. -- <alias> ::= <string literal>
  3071. -- <domain> ::= <empty>
  3072. -- <domain> ::= <indexing expression>
  3073. -- <attributes> ::= <empty>
  3074. -- <attributes> ::= <attributes> , integer
  3075. -- <attributes> ::= <attributes> , binary
  3076. -- <attributes> ::= <attributes> , symbolic
  3077. -- <attributes> ::= <attributes> , <rho> <expression 5>
  3078. -- <attributes> ::= <attributes> , in <expression 9>
  3079. -- <attributes> ::= <attributes> , := <expression 5>
  3080. -- <attributes> ::= <attributes> , default <expression 5>
  3081. -- <rho> ::= < | <= | = | == | >= | > | <> | !=
  3082. --
  3083. -- Commae in <attributes> are optional and may be omitted anywhere. */
  3084. PARAMETER *parameter_statement(MPL *mpl)
  3085. { PARAMETER *par;
  3086. int integer_used = 0, binary_used = 0, symbolic_used = 0;
  3087. xassert(is_keyword(mpl, "param"));
  3088. get_token(mpl /* param */);
  3089. /* symbolic name must follow the keyword 'param' */
  3090. if (mpl->token == T_NAME)
  3091. ;
  3092. else if (is_reserved(mpl))
  3093. mpl_error(mpl, "invalid use of reserved keyword %s", mpl->image);
  3094. else
  3095. mpl_error(mpl, "symbolic name missing where expected");
  3096. /* there must be no other object with the same name */
  3097. if (avl_find_node(mpl->tree, mpl->image) != NULL)
  3098. mpl_error(mpl, "%s multiply declared", mpl->image);
  3099. /* create model parameter */
  3100. par = alloc(PARAMETER);
  3101. par->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  3102. strcpy(par->name, mpl->image);
  3103. par->alias = NULL;
  3104. par->dim = 0;
  3105. par->domain = NULL;
  3106. par->type = A_NUMERIC;
  3107. par->cond = NULL;
  3108. par->in = NULL;
  3109. par->assign = NULL;
  3110. par->option = NULL;
  3111. par->data = 0;
  3112. par->defval = NULL;
  3113. par->array = NULL;
  3114. get_token(mpl /* <symbolic name> */);
  3115. /* parse optional alias */
  3116. if (mpl->token == T_STRING)
  3117. { par->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  3118. strcpy(par->alias, mpl->image);
  3119. get_token(mpl /* <string literal> */);
  3120. }
  3121. /* parse optional indexing expression */
  3122. if (mpl->token == T_LBRACE)
  3123. { par->domain = indexing_expression(mpl);
  3124. par->dim = domain_arity(mpl, par->domain);
  3125. }
  3126. /* include the parameter name in the symbolic names table */
  3127. { AVLNODE *node;
  3128. node = avl_insert_node(mpl->tree, par->name);
  3129. avl_set_node_type(node, A_PARAMETER);
  3130. avl_set_node_link(node, (void *)par);
  3131. }
  3132. /* parse the list of optional attributes */
  3133. for (;;)
  3134. { if (mpl->token == T_COMMA)
  3135. get_token(mpl /* , */);
  3136. else if (mpl->token == T_SEMICOLON)
  3137. break;
  3138. if (is_keyword(mpl, "integer"))
  3139. { if (integer_used)
  3140. mpl_error(mpl, "at most one integer allowed");
  3141. if (par->type == A_SYMBOLIC)
  3142. mpl_error(mpl, "symbolic parameter cannot be integer");
  3143. if (par->type != A_BINARY) par->type = A_INTEGER;
  3144. integer_used = 1;
  3145. get_token(mpl /* integer */);
  3146. }
  3147. else if (is_keyword(mpl, "binary"))
  3148. bin: { if (binary_used)
  3149. mpl_error(mpl, "at most one binary allowed");
  3150. if (par->type == A_SYMBOLIC)
  3151. mpl_error(mpl, "symbolic parameter cannot be binary");
  3152. par->type = A_BINARY;
  3153. binary_used = 1;
  3154. get_token(mpl /* binary */);
  3155. }
  3156. else if (is_keyword(mpl, "logical"))
  3157. { if (!mpl->as_binary)
  3158. { warning(mpl, "keyword logical understood as binary");
  3159. mpl->as_binary = 1;
  3160. }
  3161. goto bin;
  3162. }
  3163. else if (is_keyword(mpl, "symbolic"))
  3164. { if (symbolic_used)
  3165. mpl_error(mpl, "at most one symbolic allowed");
  3166. if (par->type != A_NUMERIC)
  3167. mpl_error(mpl, "integer or binary parameter cannot be symbol"
  3168. "ic");
  3169. /* the parameter may be referenced from expressions given
  3170. in the same parameter declaration, so its type must be
  3171. completed before parsing that expressions */
  3172. if (!(par->cond == NULL && par->in == NULL &&
  3173. par->assign == NULL && par->option == NULL))
  3174. mpl_error(mpl, "keyword symbolic must precede any other para"
  3175. "meter attributes");
  3176. par->type = A_SYMBOLIC;
  3177. symbolic_used = 1;
  3178. get_token(mpl /* symbolic */);
  3179. }
  3180. else if (mpl->token == T_LT || mpl->token == T_LE ||
  3181. mpl->token == T_EQ || mpl->token == T_GE ||
  3182. mpl->token == T_GT || mpl->token == T_NE)
  3183. { /* restricting condition */
  3184. CONDITION *cond, *temp;
  3185. char opstr[8];
  3186. /* create new restricting condition list entry and append
  3187. it to the conditions list */
  3188. cond = alloc(CONDITION);
  3189. switch (mpl->token)
  3190. { case T_LT:
  3191. cond->rho = O_LT, strcpy(opstr, mpl->image); break;
  3192. case T_LE:
  3193. cond->rho = O_LE, strcpy(opstr, mpl->image); break;
  3194. case T_EQ:
  3195. cond->rho = O_EQ, strcpy(opstr, mpl->image); break;
  3196. case T_GE:
  3197. cond->rho = O_GE, strcpy(opstr, mpl->image); break;
  3198. case T_GT:
  3199. cond->rho = O_GT, strcpy(opstr, mpl->image); break;
  3200. case T_NE:
  3201. cond->rho = O_NE, strcpy(opstr, mpl->image); break;
  3202. default:
  3203. xassert(mpl->token != mpl->token);
  3204. }
  3205. xassert(strlen(opstr) < sizeof(opstr));
  3206. cond->code = NULL;
  3207. cond->next = NULL;
  3208. if (par->cond == NULL)
  3209. par->cond = cond;
  3210. else
  3211. { for (temp = par->cond; temp->next != NULL; temp =
  3212. temp->next);
  3213. temp->next = cond;
  3214. }
  3215. #if 0 /* 13/VIII-2008 */
  3216. if (par->type == A_SYMBOLIC &&
  3217. !(cond->rho == O_EQ || cond->rho == O_NE))
  3218. mpl_error(mpl, "inequality restriction not allowed");
  3219. #endif
  3220. get_token(mpl /* rho */);
  3221. /* parse an expression that follows relational operator */
  3222. cond->code = expression_5(mpl);
  3223. if (!(cond->code->type == A_NUMERIC ||
  3224. cond->code->type == A_SYMBOLIC))
  3225. mpl_error(mpl, "expression following %s has invalid type",
  3226. opstr);
  3227. xassert(cond->code->dim == 0);
  3228. /* convert to the parameter type, if necessary */
  3229. if (par->type != A_SYMBOLIC && cond->code->type ==
  3230. A_SYMBOLIC)
  3231. cond->code = make_unary(mpl, O_CVTNUM, cond->code,
  3232. A_NUMERIC, 0);
  3233. if (par->type == A_SYMBOLIC && cond->code->type !=
  3234. A_SYMBOLIC)
  3235. cond->code = make_unary(mpl, O_CVTSYM, cond->code,
  3236. A_SYMBOLIC, 0);
  3237. }
  3238. else if (mpl->token == T_IN || mpl->token == T_WITHIN)
  3239. { /* restricting superset */
  3240. WITHIN *in, *temp;
  3241. if (mpl->token == T_WITHIN && !mpl->as_in)
  3242. { warning(mpl, "keyword within understood as in");
  3243. mpl->as_in = 1;
  3244. }
  3245. get_token(mpl /* in */);
  3246. /* create new restricting superset list entry and append it
  3247. to the in-list */
  3248. in = alloc(WITHIN);
  3249. in->code = NULL;
  3250. in->next = NULL;
  3251. if (par->in == NULL)
  3252. par->in = in;
  3253. else
  3254. { for (temp = par->in; temp->next != NULL; temp =
  3255. temp->next);
  3256. temp->next = in;
  3257. }
  3258. /* parse an expression that follows 'in' */
  3259. in->code = expression_9(mpl);
  3260. if (in->code->type != A_ELEMSET)
  3261. mpl_error(mpl, "expression following in has invalid type");
  3262. xassert(in->code->dim > 0);
  3263. if (in->code->dim != 1)
  3264. mpl_error(mpl, "set expression following in must have dimens"
  3265. "ion 1 rather than %d", in->code->dim);
  3266. }
  3267. else if (mpl->token == T_ASSIGN)
  3268. { /* assignment expression */
  3269. if (!(par->assign == NULL && par->option == NULL))
  3270. err: mpl_error(mpl, "at most one := or default allowed");
  3271. get_token(mpl /* := */);
  3272. /* parse an expression that follows ':=' */
  3273. par->assign = expression_5(mpl);
  3274. /* the expression must be of numeric/symbolic type */
  3275. if (!(par->assign->type == A_NUMERIC ||
  3276. par->assign->type == A_SYMBOLIC))
  3277. mpl_error(mpl, "expression following := has invalid type");
  3278. xassert(par->assign->dim == 0);
  3279. /* convert to the parameter type, if necessary */
  3280. if (par->type != A_SYMBOLIC && par->assign->type ==
  3281. A_SYMBOLIC)
  3282. par->assign = make_unary(mpl, O_CVTNUM, par->assign,
  3283. A_NUMERIC, 0);
  3284. if (par->type == A_SYMBOLIC && par->assign->type !=
  3285. A_SYMBOLIC)
  3286. par->assign = make_unary(mpl, O_CVTSYM, par->assign,
  3287. A_SYMBOLIC, 0);
  3288. }
  3289. else if (is_keyword(mpl, "default"))
  3290. { /* expression for default value */
  3291. if (!(par->assign == NULL && par->option == NULL)) goto err;
  3292. get_token(mpl /* default */);
  3293. /* parse an expression that follows 'default' */
  3294. par->option = expression_5(mpl);
  3295. if (!(par->option->type == A_NUMERIC ||
  3296. par->option->type == A_SYMBOLIC))
  3297. mpl_error(mpl, "expression following default has invalid typ"
  3298. "e");
  3299. xassert(par->option->dim == 0);
  3300. /* convert to the parameter type, if necessary */
  3301. if (par->type != A_SYMBOLIC && par->option->type ==
  3302. A_SYMBOLIC)
  3303. par->option = make_unary(mpl, O_CVTNUM, par->option,
  3304. A_NUMERIC, 0);
  3305. if (par->type == A_SYMBOLIC && par->option->type !=
  3306. A_SYMBOLIC)
  3307. par->option = make_unary(mpl, O_CVTSYM, par->option,
  3308. A_SYMBOLIC, 0);
  3309. }
  3310. else
  3311. mpl_error(mpl, "syntax error in parameter statement");
  3312. }
  3313. /* close the domain scope */
  3314. if (par->domain != NULL) close_scope(mpl, par->domain);
  3315. /* the parameter statement has been completely parsed */
  3316. xassert(mpl->token == T_SEMICOLON);
  3317. get_token(mpl /* ; */);
  3318. return par;
  3319. }
  3320. /*----------------------------------------------------------------------
  3321. -- variable_statement - parse variable statement.
  3322. --
  3323. -- This routine parses variable statement using the syntax:
  3324. --
  3325. -- <variable statement> ::= var <symbolic name> <alias> <domain>
  3326. -- <attributes> ;
  3327. -- <alias> ::= <empty>
  3328. -- <alias> ::= <string literal>
  3329. -- <domain> ::= <empty>
  3330. -- <domain> ::= <indexing expression>
  3331. -- <attributes> ::= <empty>
  3332. -- <attributes> ::= <attributes> , integer
  3333. -- <attributes> ::= <attributes> , binary
  3334. -- <attributes> ::= <attributes> , <rho> <expression 5>
  3335. -- <rho> ::= >= | <= | = | ==
  3336. --
  3337. -- Commae in <attributes> are optional and may be omitted anywhere. */
  3338. VARIABLE *variable_statement(MPL *mpl)
  3339. { VARIABLE *var;
  3340. int integer_used = 0, binary_used = 0;
  3341. xassert(is_keyword(mpl, "var"));
  3342. if (mpl->flag_s)
  3343. mpl_error(mpl, "variable statement must precede solve statement");
  3344. get_token(mpl /* var */);
  3345. /* symbolic name must follow the keyword 'var' */
  3346. if (mpl->token == T_NAME)
  3347. ;
  3348. else if (is_reserved(mpl))
  3349. mpl_error(mpl, "invalid use of reserved keyword %s", mpl->image);
  3350. else
  3351. mpl_error(mpl, "symbolic name missing where expected");
  3352. /* there must be no other object with the same name */
  3353. if (avl_find_node(mpl->tree, mpl->image) != NULL)
  3354. mpl_error(mpl, "%s multiply declared", mpl->image);
  3355. /* create model variable */
  3356. var = alloc(VARIABLE);
  3357. var->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  3358. strcpy(var->name, mpl->image);
  3359. var->alias = NULL;
  3360. var->dim = 0;
  3361. var->domain = NULL;
  3362. var->type = A_NUMERIC;
  3363. var->lbnd = NULL;
  3364. var->ubnd = NULL;
  3365. var->array = NULL;
  3366. get_token(mpl /* <symbolic name> */);
  3367. /* parse optional alias */
  3368. if (mpl->token == T_STRING)
  3369. { var->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  3370. strcpy(var->alias, mpl->image);
  3371. get_token(mpl /* <string literal> */);
  3372. }
  3373. /* parse optional indexing expression */
  3374. if (mpl->token == T_LBRACE)
  3375. { var->domain = indexing_expression(mpl);
  3376. var->dim = domain_arity(mpl, var->domain);
  3377. }
  3378. /* include the variable name in the symbolic names table */
  3379. { AVLNODE *node;
  3380. node = avl_insert_node(mpl->tree, var->name);
  3381. avl_set_node_type(node, A_VARIABLE);
  3382. avl_set_node_link(node, (void *)var);
  3383. }
  3384. /* parse the list of optional attributes */
  3385. for (;;)
  3386. { if (mpl->token == T_COMMA)
  3387. get_token(mpl /* , */);
  3388. else if (mpl->token == T_SEMICOLON)
  3389. break;
  3390. if (is_keyword(mpl, "integer"))
  3391. { if (integer_used)
  3392. mpl_error(mpl, "at most one integer allowed");
  3393. if (var->type != A_BINARY) var->type = A_INTEGER;
  3394. integer_used = 1;
  3395. get_token(mpl /* integer */);
  3396. }
  3397. else if (is_keyword(mpl, "binary"))
  3398. bin: { if (binary_used)
  3399. mpl_error(mpl, "at most one binary allowed");
  3400. var->type = A_BINARY;
  3401. binary_used = 1;
  3402. get_token(mpl /* binary */);
  3403. }
  3404. else if (is_keyword(mpl, "logical"))
  3405. { if (!mpl->as_binary)
  3406. { warning(mpl, "keyword logical understood as binary");
  3407. mpl->as_binary = 1;
  3408. }
  3409. goto bin;
  3410. }
  3411. else if (is_keyword(mpl, "symbolic"))
  3412. mpl_error(mpl, "variable cannot be symbolic");
  3413. else if (mpl->token == T_GE)
  3414. { /* lower bound */
  3415. if (var->lbnd != NULL)
  3416. { if (var->lbnd == var->ubnd)
  3417. mpl_error(mpl, "both fixed value and lower bound not allo"
  3418. "wed");
  3419. else
  3420. mpl_error(mpl, "at most one lower bound allowed");
  3421. }
  3422. get_token(mpl /* >= */);
  3423. /* parse an expression that specifies the lower bound */
  3424. var->lbnd = expression_5(mpl);
  3425. if (var->lbnd->type == A_SYMBOLIC)
  3426. var->lbnd = make_unary(mpl, O_CVTNUM, var->lbnd,
  3427. A_NUMERIC, 0);
  3428. if (var->lbnd->type != A_NUMERIC)
  3429. mpl_error(mpl, "expression following >= has invalid type");
  3430. xassert(var->lbnd->dim == 0);
  3431. }
  3432. else if (mpl->token == T_LE)
  3433. { /* upper bound */
  3434. if (var->ubnd != NULL)
  3435. { if (var->ubnd == var->lbnd)
  3436. mpl_error(mpl, "both fixed value and upper bound not allo"
  3437. "wed");
  3438. else
  3439. mpl_error(mpl, "at most one upper bound allowed");
  3440. }
  3441. get_token(mpl /* <= */);
  3442. /* parse an expression that specifies the upper bound */
  3443. var->ubnd = expression_5(mpl);
  3444. if (var->ubnd->type == A_SYMBOLIC)
  3445. var->ubnd = make_unary(mpl, O_CVTNUM, var->ubnd,
  3446. A_NUMERIC, 0);
  3447. if (var->ubnd->type != A_NUMERIC)
  3448. mpl_error(mpl, "expression following <= has invalid type");
  3449. xassert(var->ubnd->dim == 0);
  3450. }
  3451. else if (mpl->token == T_EQ)
  3452. { /* fixed value */
  3453. char opstr[8];
  3454. if (!(var->lbnd == NULL && var->ubnd == NULL))
  3455. { if (var->lbnd == var->ubnd)
  3456. mpl_error(mpl, "at most one fixed value allowed");
  3457. else if (var->lbnd != NULL)
  3458. mpl_error(mpl, "both lower bound and fixed value not allo"
  3459. "wed");
  3460. else
  3461. mpl_error(mpl, "both upper bound and fixed value not allo"
  3462. "wed");
  3463. }
  3464. strcpy(opstr, mpl->image);
  3465. xassert(strlen(opstr) < sizeof(opstr));
  3466. get_token(mpl /* = | == */);
  3467. /* parse an expression that specifies the fixed value */
  3468. var->lbnd = expression_5(mpl);
  3469. if (var->lbnd->type == A_SYMBOLIC)
  3470. var->lbnd = make_unary(mpl, O_CVTNUM, var->lbnd,
  3471. A_NUMERIC, 0);
  3472. if (var->lbnd->type != A_NUMERIC)
  3473. mpl_error(mpl, "expression following %s has invalid type",
  3474. opstr);
  3475. xassert(var->lbnd->dim == 0);
  3476. /* indicate that the variable is fixed, not bounded */
  3477. var->ubnd = var->lbnd;
  3478. }
  3479. else if (mpl->token == T_LT || mpl->token == T_GT ||
  3480. mpl->token == T_NE)
  3481. mpl_error(mpl, "strict bound not allowed");
  3482. else
  3483. mpl_error(mpl, "syntax error in variable statement");
  3484. }
  3485. /* close the domain scope */
  3486. if (var->domain != NULL) close_scope(mpl, var->domain);
  3487. /* the variable statement has been completely parsed */
  3488. xassert(mpl->token == T_SEMICOLON);
  3489. get_token(mpl /* ; */);
  3490. return var;
  3491. }
  3492. /*----------------------------------------------------------------------
  3493. -- constraint_statement - parse constraint statement.
  3494. --
  3495. -- This routine parses constraint statement using the syntax:
  3496. --
  3497. -- <constraint statement> ::= <subject to> <symbolic name> <alias>
  3498. -- <domain> : <constraint> ;
  3499. -- <subject to> ::= <empty>
  3500. -- <subject to> ::= subject to
  3501. -- <subject to> ::= subj to
  3502. -- <subject to> ::= s.t.
  3503. -- <alias> ::= <empty>
  3504. -- <alias> ::= <string literal>
  3505. -- <domain> ::= <empty>
  3506. -- <domain> ::= <indexing expression>
  3507. -- <constraint> ::= <formula> , >= <formula>
  3508. -- <constraint> ::= <formula> , <= <formula>
  3509. -- <constraint> ::= <formula> , = <formula>
  3510. -- <constraint> ::= <formula> , <= <formula> , <= <formula>
  3511. -- <constraint> ::= <formula> , >= <formula> , >= <formula>
  3512. -- <formula> ::= <expression 5>
  3513. --
  3514. -- Commae in <constraint> are optional and may be omitted anywhere. */
  3515. CONSTRAINT *constraint_statement(MPL *mpl)
  3516. { CONSTRAINT *con;
  3517. CODE *first, *second, *third;
  3518. int rho;
  3519. char opstr[8];
  3520. if (mpl->flag_s)
  3521. mpl_error(mpl, "constraint statement must precede solve statement")
  3522. ;
  3523. if (is_keyword(mpl, "subject"))
  3524. { get_token(mpl /* subject */);
  3525. if (!is_keyword(mpl, "to"))
  3526. mpl_error(mpl, "keyword subject to incomplete");
  3527. get_token(mpl /* to */);
  3528. }
  3529. else if (is_keyword(mpl, "subj"))
  3530. { get_token(mpl /* subj */);
  3531. if (!is_keyword(mpl, "to"))
  3532. mpl_error(mpl, "keyword subj to incomplete");
  3533. get_token(mpl /* to */);
  3534. }
  3535. else if (mpl->token == T_SPTP)
  3536. get_token(mpl /* s.t. */);
  3537. /* the current token must be symbolic name of constraint */
  3538. if (mpl->token == T_NAME)
  3539. ;
  3540. else if (is_reserved(mpl))
  3541. mpl_error(mpl, "invalid use of reserved keyword %s", mpl->image);
  3542. else
  3543. mpl_error(mpl, "symbolic name missing where expected");
  3544. /* there must be no other object with the same name */
  3545. if (avl_find_node(mpl->tree, mpl->image) != NULL)
  3546. mpl_error(mpl, "%s multiply declared", mpl->image);
  3547. /* create model constraint */
  3548. con = alloc(CONSTRAINT);
  3549. con->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  3550. strcpy(con->name, mpl->image);
  3551. con->alias = NULL;
  3552. con->dim = 0;
  3553. con->domain = NULL;
  3554. con->type = A_CONSTRAINT;
  3555. con->code = NULL;
  3556. con->lbnd = NULL;
  3557. con->ubnd = NULL;
  3558. con->array = NULL;
  3559. get_token(mpl /* <symbolic name> */);
  3560. /* parse optional alias */
  3561. if (mpl->token == T_STRING)
  3562. { con->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  3563. strcpy(con->alias, mpl->image);
  3564. get_token(mpl /* <string literal> */);
  3565. }
  3566. /* parse optional indexing expression */
  3567. if (mpl->token == T_LBRACE)
  3568. { con->domain = indexing_expression(mpl);
  3569. con->dim = domain_arity(mpl, con->domain);
  3570. }
  3571. /* include the constraint name in the symbolic names table */
  3572. { AVLNODE *node;
  3573. node = avl_insert_node(mpl->tree, con->name);
  3574. avl_set_node_type(node, A_CONSTRAINT);
  3575. avl_set_node_link(node, (void *)con);
  3576. }
  3577. /* the colon must precede the first expression */
  3578. if (mpl->token != T_COLON)
  3579. mpl_error(mpl, "colon missing where expected");
  3580. get_token(mpl /* : */);
  3581. /* parse the first expression */
  3582. first = expression_5(mpl);
  3583. if (first->type == A_SYMBOLIC)
  3584. first = make_unary(mpl, O_CVTNUM, first, A_NUMERIC, 0);
  3585. if (!(first->type == A_NUMERIC || first->type == A_FORMULA))
  3586. mpl_error(mpl, "expression following colon has invalid type");
  3587. xassert(first->dim == 0);
  3588. /* relational operator must follow the first expression */
  3589. if (mpl->token == T_COMMA) get_token(mpl /* , */);
  3590. switch (mpl->token)
  3591. { case T_LE:
  3592. case T_GE:
  3593. case T_EQ:
  3594. break;
  3595. case T_LT:
  3596. case T_GT:
  3597. case T_NE:
  3598. mpl_error(mpl, "strict inequality not allowed");
  3599. case T_SEMICOLON:
  3600. mpl_error(mpl, "constraint must be equality or inequality");
  3601. default:
  3602. goto err;
  3603. }
  3604. rho = mpl->token;
  3605. strcpy(opstr, mpl->image);
  3606. xassert(strlen(opstr) < sizeof(opstr));
  3607. get_token(mpl /* rho */);
  3608. /* parse the second expression */
  3609. second = expression_5(mpl);
  3610. if (second->type == A_SYMBOLIC)
  3611. second = make_unary(mpl, O_CVTNUM, second, A_NUMERIC, 0);
  3612. if (!(second->type == A_NUMERIC || second->type == A_FORMULA))
  3613. mpl_error(mpl, "expression following %s has invalid type", opstr);
  3614. xassert(second->dim == 0);
  3615. /* check a token that follow the second expression */
  3616. if (mpl->token == T_COMMA)
  3617. { get_token(mpl /* , */);
  3618. if (mpl->token == T_SEMICOLON) goto err;
  3619. }
  3620. if (mpl->token == T_LT || mpl->token == T_LE ||
  3621. mpl->token == T_EQ || mpl->token == T_GE ||
  3622. mpl->token == T_GT || mpl->token == T_NE)
  3623. { /* it is another relational operator, therefore the constraint
  3624. is double inequality */
  3625. if (rho == T_EQ || mpl->token != rho)
  3626. mpl_error(mpl, "double inequality must be ... <= ... <= ... or "
  3627. "... >= ... >= ...");
  3628. /* the first expression cannot be linear form */
  3629. if (first->type == A_FORMULA)
  3630. mpl_error(mpl, "leftmost expression in double inequality cannot"
  3631. " be linear form");
  3632. get_token(mpl /* rho */);
  3633. /* parse the third expression */
  3634. third = expression_5(mpl);
  3635. if (third->type == A_SYMBOLIC)
  3636. third = make_unary(mpl, O_CVTNUM, second, A_NUMERIC, 0);
  3637. if (!(third->type == A_NUMERIC || third->type == A_FORMULA))
  3638. mpl_error(mpl, "rightmost expression in double inequality const"
  3639. "raint has invalid type");
  3640. xassert(third->dim == 0);
  3641. /* the third expression also cannot be linear form */
  3642. if (third->type == A_FORMULA)
  3643. mpl_error(mpl, "rightmost expression in double inequality canno"
  3644. "t be linear form");
  3645. }
  3646. else
  3647. { /* the constraint is equality or single inequality */
  3648. third = NULL;
  3649. }
  3650. /* close the domain scope */
  3651. if (con->domain != NULL) close_scope(mpl, con->domain);
  3652. /* convert all expressions to linear form, if necessary */
  3653. if (first->type != A_FORMULA)
  3654. first = make_unary(mpl, O_CVTLFM, first, A_FORMULA, 0);
  3655. if (second->type != A_FORMULA)
  3656. second = make_unary(mpl, O_CVTLFM, second, A_FORMULA, 0);
  3657. if (third != NULL)
  3658. third = make_unary(mpl, O_CVTLFM, third, A_FORMULA, 0);
  3659. /* arrange expressions in the constraint */
  3660. if (third == NULL)
  3661. { /* the constraint is equality or single inequality */
  3662. switch (rho)
  3663. { case T_LE:
  3664. /* first <= second */
  3665. con->code = first;
  3666. con->lbnd = NULL;
  3667. con->ubnd = second;
  3668. break;
  3669. case T_GE:
  3670. /* first >= second */
  3671. con->code = first;
  3672. con->lbnd = second;
  3673. con->ubnd = NULL;
  3674. break;
  3675. case T_EQ:
  3676. /* first = second */
  3677. con->code = first;
  3678. con->lbnd = second;
  3679. con->ubnd = second;
  3680. break;
  3681. default:
  3682. xassert(rho != rho);
  3683. }
  3684. }
  3685. else
  3686. { /* the constraint is double inequality */
  3687. switch (rho)
  3688. { case T_LE:
  3689. /* first <= second <= third */
  3690. con->code = second;
  3691. con->lbnd = first;
  3692. con->ubnd = third;
  3693. break;
  3694. case T_GE:
  3695. /* first >= second >= third */
  3696. con->code = second;
  3697. con->lbnd = third;
  3698. con->ubnd = first;
  3699. break;
  3700. default:
  3701. xassert(rho != rho);
  3702. }
  3703. }
  3704. /* the constraint statement has been completely parsed */
  3705. if (mpl->token != T_SEMICOLON)
  3706. err: mpl_error(mpl, "syntax error in constraint statement");
  3707. get_token(mpl /* ; */);
  3708. return con;
  3709. }
  3710. /*----------------------------------------------------------------------
  3711. -- objective_statement - parse objective statement.
  3712. --
  3713. -- This routine parses objective statement using the syntax:
  3714. --
  3715. -- <objective statement> ::= <verb> <symbolic name> <alias> <domain> :
  3716. -- <formula> ;
  3717. -- <verb> ::= minimize
  3718. -- <verb> ::= maximize
  3719. -- <alias> ::= <empty>
  3720. -- <alias> ::= <string literal>
  3721. -- <domain> ::= <empty>
  3722. -- <domain> ::= <indexing expression>
  3723. -- <formula> ::= <expression 5> */
  3724. CONSTRAINT *objective_statement(MPL *mpl)
  3725. { CONSTRAINT *obj;
  3726. int type;
  3727. if (is_keyword(mpl, "minimize"))
  3728. type = A_MINIMIZE;
  3729. else if (is_keyword(mpl, "maximize"))
  3730. type = A_MAXIMIZE;
  3731. else
  3732. xassert(mpl != mpl);
  3733. if (mpl->flag_s)
  3734. mpl_error(mpl, "objective statement must precede solve statement");
  3735. get_token(mpl /* minimize | maximize */);
  3736. /* symbolic name must follow the verb 'minimize' or 'maximize' */
  3737. if (mpl->token == T_NAME)
  3738. ;
  3739. else if (is_reserved(mpl))
  3740. mpl_error(mpl, "invalid use of reserved keyword %s", mpl->image);
  3741. else
  3742. mpl_error(mpl, "symbolic name missing where expected");
  3743. /* there must be no other object with the same name */
  3744. if (avl_find_node(mpl->tree, mpl->image) != NULL)
  3745. mpl_error(mpl, "%s multiply declared", mpl->image);
  3746. /* create model objective */
  3747. obj = alloc(CONSTRAINT);
  3748. obj->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  3749. strcpy(obj->name, mpl->image);
  3750. obj->alias = NULL;
  3751. obj->dim = 0;
  3752. obj->domain = NULL;
  3753. obj->type = type;
  3754. obj->code = NULL;
  3755. obj->lbnd = NULL;
  3756. obj->ubnd = NULL;
  3757. obj->array = NULL;
  3758. get_token(mpl /* <symbolic name> */);
  3759. /* parse optional alias */
  3760. if (mpl->token == T_STRING)
  3761. { obj->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  3762. strcpy(obj->alias, mpl->image);
  3763. get_token(mpl /* <string literal> */);
  3764. }
  3765. /* parse optional indexing expression */
  3766. if (mpl->token == T_LBRACE)
  3767. { obj->domain = indexing_expression(mpl);
  3768. obj->dim = domain_arity(mpl, obj->domain);
  3769. }
  3770. /* include the constraint name in the symbolic names table */
  3771. { AVLNODE *node;
  3772. node = avl_insert_node(mpl->tree, obj->name);
  3773. avl_set_node_type(node, A_CONSTRAINT);
  3774. avl_set_node_link(node, (void *)obj);
  3775. }
  3776. /* the colon must precede the objective expression */
  3777. if (mpl->token != T_COLON)
  3778. mpl_error(mpl, "colon missing where expected");
  3779. get_token(mpl /* : */);
  3780. /* parse the objective expression */
  3781. obj->code = expression_5(mpl);
  3782. if (obj->code->type == A_SYMBOLIC)
  3783. obj->code = make_unary(mpl, O_CVTNUM, obj->code, A_NUMERIC, 0);
  3784. if (obj->code->type == A_NUMERIC)
  3785. obj->code = make_unary(mpl, O_CVTLFM, obj->code, A_FORMULA, 0);
  3786. if (obj->code->type != A_FORMULA)
  3787. mpl_error(mpl, "expression following colon has invalid type");
  3788. xassert(obj->code->dim == 0);
  3789. /* close the domain scope */
  3790. if (obj->domain != NULL) close_scope(mpl, obj->domain);
  3791. /* the objective statement has been completely parsed */
  3792. if (mpl->token != T_SEMICOLON)
  3793. mpl_error(mpl, "syntax error in objective statement");
  3794. get_token(mpl /* ; */);
  3795. return obj;
  3796. }
  3797. #if 1 /* 11/II-2008 */
  3798. /***********************************************************************
  3799. * table_statement - parse table statement
  3800. *
  3801. * This routine parses table statement using the syntax:
  3802. *
  3803. * <table statement> ::= <input table statement>
  3804. * <table statement> ::= <output table statement>
  3805. *
  3806. * <input table statement> ::=
  3807. * table <table name> <alias> IN <argument list> :
  3808. * <input set> [ <field list> ] , <input list> ;
  3809. * <alias> ::= <empty>
  3810. * <alias> ::= <string literal>
  3811. * <argument list> ::= <expression 5>
  3812. * <argument list> ::= <argument list> <expression 5>
  3813. * <argument list> ::= <argument list> , <expression 5>
  3814. * <input set> ::= <empty>
  3815. * <input set> ::= <set name> <-
  3816. * <field list> ::= <field name>
  3817. * <field list> ::= <field list> , <field name>
  3818. * <input list> ::= <input item>
  3819. * <input list> ::= <input list> , <input item>
  3820. * <input item> ::= <parameter name>
  3821. * <input item> ::= <parameter name> ~ <field name>
  3822. *
  3823. * <output table statement> ::=
  3824. * table <table name> <alias> <domain> OUT <argument list> :
  3825. * <output list> ;
  3826. * <domain> ::= <indexing expression>
  3827. * <output list> ::= <output item>
  3828. * <output list> ::= <output list> , <output item>
  3829. * <output item> ::= <expression 5>
  3830. * <output item> ::= <expression 5> ~ <field name> */
  3831. TABLE *table_statement(MPL *mpl)
  3832. { TABLE *tab;
  3833. TABARG *last_arg, *arg;
  3834. TABFLD *last_fld, *fld;
  3835. TABIN *last_in, *in;
  3836. TABOUT *last_out, *out;
  3837. AVLNODE *node;
  3838. int nflds;
  3839. char name[MAX_LENGTH+1];
  3840. xassert(is_keyword(mpl, "table"));
  3841. get_token(mpl /* solve */);
  3842. /* symbolic name must follow the keyword table */
  3843. if (mpl->token == T_NAME)
  3844. ;
  3845. else if (is_reserved(mpl))
  3846. mpl_error(mpl, "invalid use of reserved keyword %s", mpl->image);
  3847. else
  3848. mpl_error(mpl, "symbolic name missing where expected");
  3849. /* there must be no other object with the same name */
  3850. if (avl_find_node(mpl->tree, mpl->image) != NULL)
  3851. mpl_error(mpl, "%s multiply declared", mpl->image);
  3852. /* create data table */
  3853. tab = alloc(TABLE);
  3854. tab->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  3855. strcpy(tab->name, mpl->image);
  3856. get_token(mpl /* <symbolic name> */);
  3857. /* parse optional alias */
  3858. if (mpl->token == T_STRING)
  3859. { tab->alias = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  3860. strcpy(tab->alias, mpl->image);
  3861. get_token(mpl /* <string literal> */);
  3862. }
  3863. else
  3864. tab->alias = NULL;
  3865. /* parse optional indexing expression */
  3866. if (mpl->token == T_LBRACE)
  3867. { /* this is output table */
  3868. tab->type = A_OUTPUT;
  3869. tab->u.out.domain = indexing_expression(mpl);
  3870. if (!is_keyword(mpl, "OUT"))
  3871. mpl_error(mpl, "keyword OUT missing where expected");
  3872. get_token(mpl /* OUT */);
  3873. }
  3874. else
  3875. { /* this is input table */
  3876. tab->type = A_INPUT;
  3877. if (!is_keyword(mpl, "IN"))
  3878. mpl_error(mpl, "keyword IN missing where expected");
  3879. get_token(mpl /* IN */);
  3880. }
  3881. /* parse argument list */
  3882. tab->arg = last_arg = NULL;
  3883. for (;;)
  3884. { /* create argument list entry */
  3885. arg = alloc(TABARG);
  3886. /* parse argument expression */
  3887. if (mpl->token == T_COMMA || mpl->token == T_COLON ||
  3888. mpl->token == T_SEMICOLON)
  3889. mpl_error(mpl, "argument expression missing where expected");
  3890. arg->code = expression_5(mpl);
  3891. /* convert the result to symbolic type, if necessary */
  3892. if (arg->code->type == A_NUMERIC)
  3893. arg->code =
  3894. make_unary(mpl, O_CVTSYM, arg->code, A_SYMBOLIC, 0);
  3895. /* check that now the result is of symbolic type */
  3896. if (arg->code->type != A_SYMBOLIC)
  3897. mpl_error(mpl, "argument expression has invalid type");
  3898. /* add the entry to the end of the list */
  3899. arg->next = NULL;
  3900. if (last_arg == NULL)
  3901. tab->arg = arg;
  3902. else
  3903. last_arg->next = arg;
  3904. last_arg = arg;
  3905. /* argument expression has been parsed */
  3906. if (mpl->token == T_COMMA)
  3907. get_token(mpl /* , */);
  3908. else if (mpl->token == T_COLON || mpl->token == T_SEMICOLON)
  3909. break;
  3910. }
  3911. xassert(tab->arg != NULL);
  3912. /* argument list must end with colon */
  3913. if (mpl->token == T_COLON)
  3914. get_token(mpl /* : */);
  3915. else
  3916. mpl_error(mpl, "colon missing where expected");
  3917. /* parse specific part of the table statement */
  3918. switch (tab->type)
  3919. { case A_INPUT: goto input_table;
  3920. case A_OUTPUT: goto output_table;
  3921. default: xassert(tab != tab);
  3922. }
  3923. input_table:
  3924. /* parse optional set name */
  3925. if (mpl->token == T_NAME)
  3926. { node = avl_find_node(mpl->tree, mpl->image);
  3927. if (node == NULL)
  3928. mpl_error(mpl, "%s not defined", mpl->image);
  3929. if (avl_get_node_type(node) != A_SET)
  3930. mpl_error(mpl, "%s not a set", mpl->image);
  3931. tab->u.in.set = (SET *)avl_get_node_link(node);
  3932. if (tab->u.in.set->assign != NULL)
  3933. mpl_error(mpl, "%s needs no data", mpl->image);
  3934. if (tab->u.in.set->dim != 0)
  3935. mpl_error(mpl, "%s must be a simple set", mpl->image);
  3936. get_token(mpl /* <symbolic name> */);
  3937. if (mpl->token == T_INPUT)
  3938. get_token(mpl /* <- */);
  3939. else
  3940. mpl_error(mpl, "delimiter <- missing where expected");
  3941. }
  3942. else if (is_reserved(mpl))
  3943. mpl_error(mpl, "invalid use of reserved keyword %s", mpl->image);
  3944. else
  3945. tab->u.in.set = NULL;
  3946. /* parse field list */
  3947. tab->u.in.fld = last_fld = NULL;
  3948. nflds = 0;
  3949. if (mpl->token == T_LBRACKET)
  3950. get_token(mpl /* [ */);
  3951. else
  3952. mpl_error(mpl, "field list missing where expected");
  3953. for (;;)
  3954. { /* create field list entry */
  3955. fld = alloc(TABFLD);
  3956. /* parse field name */
  3957. if (mpl->token == T_NAME)
  3958. ;
  3959. else if (is_reserved(mpl))
  3960. mpl_error(mpl,
  3961. "invalid use of reserved keyword %s", mpl->image);
  3962. else
  3963. mpl_error(mpl, "field name missing where expected");
  3964. fld->name = dmp_get_atomv(mpl->pool, strlen(mpl->image)+1);
  3965. strcpy(fld->name, mpl->image);
  3966. get_token(mpl /* <symbolic name> */);
  3967. /* add the entry to the end of the list */
  3968. fld->next = NULL;
  3969. if (last_fld == NULL)
  3970. tab->u.in.fld = fld;
  3971. else
  3972. last_fld->next = fld;
  3973. last_fld = fld;
  3974. nflds++;
  3975. /* field name has been parsed */
  3976. if (mpl->token == T_COMMA)
  3977. get_token(mpl /* , */);
  3978. else if (mpl->token == T_RBRACKET)
  3979. break;
  3980. else
  3981. mpl_error(mpl, "syntax error in field list");
  3982. }
  3983. /* check that the set dimen is equal to the number of fields */
  3984. if (tab->u.in.set != NULL && tab->u.in.set->dimen != nflds)
  3985. mpl_error(mpl, "there must be %d field%s rather than %d",
  3986. tab->u.in.set->dimen, tab->u.in.set->dimen == 1 ? "" : "s",
  3987. nflds);
  3988. get_token(mpl /* ] */);
  3989. /* parse optional input list */
  3990. tab->u.in.list = last_in = NULL;
  3991. while (mpl->token == T_COMMA)
  3992. { get_token(mpl /* , */);
  3993. /* create input list entry */
  3994. in = alloc(TABIN);
  3995. /* parse parameter name */
  3996. if (mpl->token == T_NAME)
  3997. ;
  3998. else if (is_reserved(mpl))
  3999. mpl_error(mpl,
  4000. "invalid use of reserved keyword %s", mpl->image);
  4001. else
  4002. mpl_error(mpl, "parameter name missing where expected");
  4003. node = avl_find_node(mpl->tree, mpl->image);
  4004. if (node == NULL)
  4005. mpl_error(mpl, "%s not defined", mpl->image);
  4006. if (avl_get_node_type(node) != A_PARAMETER)
  4007. mpl_error(mpl, "%s not a parameter", mpl->image);
  4008. in->par = (PARAMETER *)avl_get_node_link(node);
  4009. if (in->par->dim != nflds)
  4010. mpl_error(mpl, "%s must have %d subscript%s rather than %d",
  4011. mpl->image, nflds, nflds == 1 ? "" : "s", in->par->dim);
  4012. if (in->par->assign != NULL)
  4013. mpl_error(mpl, "%s needs no data", mpl->image);
  4014. get_token(mpl /* <symbolic name> */);
  4015. /* parse optional field name */
  4016. if (mpl->token == T_TILDE)
  4017. { get_token(mpl /* ~ */);
  4018. /* parse field name */
  4019. if (mpl->token == T_NAME)
  4020. ;
  4021. else if (is_reserved(mpl))
  4022. mpl_error(mpl,
  4023. "invalid use of reserved keyword %s", mpl->image);
  4024. else
  4025. mpl_error(mpl, "field name missing where expected");
  4026. xassert(strlen(mpl->image) < sizeof(name));
  4027. strcpy(name, mpl->image);
  4028. get_token(mpl /* <symbolic name> */);
  4029. }
  4030. else
  4031. { /* field name is the same as the parameter name */
  4032. xassert(strlen(in->par->name) < sizeof(name));
  4033. strcpy(name, in->par->name);
  4034. }
  4035. /* assign field name */
  4036. in->name = dmp_get_atomv(mpl->pool, strlen(name)+1);
  4037. strcpy(in->name, name);
  4038. /* add the entry to the end of the list */
  4039. in->next = NULL;
  4040. if (last_in == NULL)
  4041. tab->u.in.list = in;
  4042. else
  4043. last_in->next = in;
  4044. last_in = in;
  4045. }
  4046. goto end_of_table;
  4047. output_table:
  4048. /* parse output list */
  4049. tab->u.out.list = last_out = NULL;
  4050. for (;;)
  4051. { /* create output list entry */
  4052. out = alloc(TABOUT);
  4053. /* parse expression */
  4054. if (mpl->token == T_COMMA || mpl->token == T_SEMICOLON)
  4055. mpl_error(mpl, "expression missing where expected");
  4056. if (mpl->token == T_NAME)
  4057. { xassert(strlen(mpl->image) < sizeof(name));
  4058. strcpy(name, mpl->image);
  4059. }
  4060. else
  4061. name[0] = '\0';
  4062. out->code = expression_5(mpl);
  4063. /* parse optional field name */
  4064. if (mpl->token == T_TILDE)
  4065. { get_token(mpl /* ~ */);
  4066. /* parse field name */
  4067. if (mpl->token == T_NAME)
  4068. ;
  4069. else if (is_reserved(mpl))
  4070. mpl_error(mpl,
  4071. "invalid use of reserved keyword %s", mpl->image);
  4072. else
  4073. mpl_error(mpl, "field name missing where expected");
  4074. xassert(strlen(mpl->image) < sizeof(name));
  4075. strcpy(name, mpl->image);
  4076. get_token(mpl /* <symbolic name> */);
  4077. }
  4078. /* assign field name */
  4079. if (name[0] == '\0')
  4080. mpl_error(mpl, "field name required");
  4081. out->name = dmp_get_atomv(mpl->pool, strlen(name)+1);
  4082. strcpy(out->name, name);
  4083. /* add the entry to the end of the list */
  4084. out->next = NULL;
  4085. if (last_out == NULL)
  4086. tab->u.out.list = out;
  4087. else
  4088. last_out->next = out;
  4089. last_out = out;
  4090. /* output item has been parsed */
  4091. if (mpl->token == T_COMMA)
  4092. get_token(mpl /* , */);
  4093. else if (mpl->token == T_SEMICOLON)
  4094. break;
  4095. else
  4096. mpl_error(mpl, "syntax error in output list");
  4097. }
  4098. /* close the domain scope */
  4099. close_scope(mpl,tab->u.out.domain);
  4100. end_of_table:
  4101. /* the table statement must end with semicolon */
  4102. if (mpl->token != T_SEMICOLON)
  4103. mpl_error(mpl, "syntax error in table statement");
  4104. get_token(mpl /* ; */);
  4105. return tab;
  4106. }
  4107. #endif
  4108. /*----------------------------------------------------------------------
  4109. -- solve_statement - parse solve statement.
  4110. --
  4111. -- This routine parses solve statement using the syntax:
  4112. --
  4113. -- <solve statement> ::= solve ;
  4114. --
  4115. -- The solve statement can be used at most once. */
  4116. void *solve_statement(MPL *mpl)
  4117. { xassert(is_keyword(mpl, "solve"));
  4118. if (mpl->flag_s)
  4119. mpl_error(mpl, "at most one solve statement allowed");
  4120. mpl->flag_s = 1;
  4121. get_token(mpl /* solve */);
  4122. /* semicolon must follow solve statement */
  4123. if (mpl->token != T_SEMICOLON)
  4124. mpl_error(mpl, "syntax error in solve statement");
  4125. get_token(mpl /* ; */);
  4126. return NULL;
  4127. }
  4128. /*----------------------------------------------------------------------
  4129. -- check_statement - parse check statement.
  4130. --
  4131. -- This routine parses check statement using the syntax:
  4132. --
  4133. -- <check statement> ::= check <domain> : <expression 13> ;
  4134. -- <domain> ::= <empty>
  4135. -- <domain> ::= <indexing expression>
  4136. --
  4137. -- If <domain> is omitted, colon following it may also be omitted. */
  4138. CHECK *check_statement(MPL *mpl)
  4139. { CHECK *chk;
  4140. xassert(is_keyword(mpl, "check"));
  4141. /* create check descriptor */
  4142. chk = alloc(CHECK);
  4143. chk->domain = NULL;
  4144. chk->code = NULL;
  4145. get_token(mpl /* check */);
  4146. /* parse optional indexing expression */
  4147. if (mpl->token == T_LBRACE)
  4148. { chk->domain = indexing_expression(mpl);
  4149. #if 0
  4150. if (mpl->token != T_COLON)
  4151. mpl_error(mpl, "colon missing where expected");
  4152. #endif
  4153. }
  4154. /* skip optional colon */
  4155. if (mpl->token == T_COLON) get_token(mpl /* : */);
  4156. /* parse logical expression */
  4157. chk->code = expression_13(mpl);
  4158. if (chk->code->type != A_LOGICAL)
  4159. mpl_error(mpl, "expression has invalid type");
  4160. xassert(chk->code->dim == 0);
  4161. /* close the domain scope */
  4162. if (chk->domain != NULL) close_scope(mpl, chk->domain);
  4163. /* the check statement has been completely parsed */
  4164. if (mpl->token != T_SEMICOLON)
  4165. mpl_error(mpl, "syntax error in check statement");
  4166. get_token(mpl /* ; */);
  4167. return chk;
  4168. }
  4169. #if 1 /* 15/V-2010 */
  4170. /*----------------------------------------------------------------------
  4171. -- display_statement - parse display statement.
  4172. --
  4173. -- This routine parses display statement using the syntax:
  4174. --
  4175. -- <display statement> ::= display <domain> : <display list> ;
  4176. -- <display statement> ::= display <domain> <display list> ;
  4177. -- <domain> ::= <empty>
  4178. -- <domain> ::= <indexing expression>
  4179. -- <display list> ::= <display entry>
  4180. -- <display list> ::= <display list> , <display entry>
  4181. -- <display entry> ::= <dummy index>
  4182. -- <display entry> ::= <set name>
  4183. -- <display entry> ::= <set name> [ <subscript list> ]
  4184. -- <display entry> ::= <parameter name>
  4185. -- <display entry> ::= <parameter name> [ <subscript list> ]
  4186. -- <display entry> ::= <variable name>
  4187. -- <display entry> ::= <variable name> [ <subscript list> ]
  4188. -- <display entry> ::= <constraint name>
  4189. -- <display entry> ::= <constraint name> [ <subscript list> ]
  4190. -- <display entry> ::= <expression 13> */
  4191. DISPLAY *display_statement(MPL *mpl)
  4192. { DISPLAY *dpy;
  4193. DISPLAY1 *entry, *last_entry;
  4194. xassert(is_keyword(mpl, "display"));
  4195. /* create display descriptor */
  4196. dpy = alloc(DISPLAY);
  4197. dpy->domain = NULL;
  4198. dpy->list = last_entry = NULL;
  4199. get_token(mpl /* display */);
  4200. /* parse optional indexing expression */
  4201. if (mpl->token == T_LBRACE)
  4202. dpy->domain = indexing_expression(mpl);
  4203. /* skip optional colon */
  4204. if (mpl->token == T_COLON) get_token(mpl /* : */);
  4205. /* parse display list */
  4206. for (;;)
  4207. { /* create new display entry */
  4208. entry = alloc(DISPLAY1);
  4209. entry->type = 0;
  4210. entry->next = NULL;
  4211. /* and append it to the display list */
  4212. if (dpy->list == NULL)
  4213. dpy->list = entry;
  4214. else
  4215. last_entry->next = entry;
  4216. last_entry = entry;
  4217. /* parse display entry */
  4218. if (mpl->token == T_NAME)
  4219. { AVLNODE *node;
  4220. int next_token;
  4221. get_token(mpl /* <symbolic name> */);
  4222. next_token = mpl->token;
  4223. unget_token(mpl);
  4224. if (!(next_token == T_COMMA || next_token == T_SEMICOLON))
  4225. { /* symbolic name begins expression */
  4226. goto expr;
  4227. }
  4228. /* display entry is dummy index or model object */
  4229. node = avl_find_node(mpl->tree, mpl->image);
  4230. if (node == NULL)
  4231. mpl_error(mpl, "%s not defined", mpl->image);
  4232. entry->type = avl_get_node_type(node);
  4233. switch (avl_get_node_type(node))
  4234. { case A_INDEX:
  4235. entry->u.slot =
  4236. (DOMAIN_SLOT *)avl_get_node_link(node);
  4237. break;
  4238. case A_SET:
  4239. entry->u.set = (SET *)avl_get_node_link(node);
  4240. break;
  4241. case A_PARAMETER:
  4242. entry->u.par = (PARAMETER *)avl_get_node_link(node);
  4243. break;
  4244. case A_VARIABLE:
  4245. entry->u.var = (VARIABLE *)avl_get_node_link(node);
  4246. if (!mpl->flag_s)
  4247. mpl_error(mpl, "invalid reference to variable %s above"
  4248. " solve statement", entry->u.var->name);
  4249. break;
  4250. case A_CONSTRAINT:
  4251. entry->u.con = (CONSTRAINT *)avl_get_node_link(node);
  4252. if (!mpl->flag_s)
  4253. mpl_error(mpl, "invalid reference to %s %s above solve"
  4254. " statement",
  4255. entry->u.con->type == A_CONSTRAINT ?
  4256. "constraint" : "objective", entry->u.con->name);
  4257. break;
  4258. default:
  4259. xassert(node != node);
  4260. }
  4261. get_token(mpl /* <symbolic name> */);
  4262. }
  4263. else
  4264. expr: { /* display entry is expression */
  4265. entry->type = A_EXPRESSION;
  4266. entry->u.code = expression_13(mpl);
  4267. }
  4268. /* check a token that follows the entry parsed */
  4269. if (mpl->token == T_COMMA)
  4270. get_token(mpl /* , */);
  4271. else
  4272. break;
  4273. }
  4274. /* close the domain scope */
  4275. if (dpy->domain != NULL) close_scope(mpl, dpy->domain);
  4276. /* the display statement has been completely parsed */
  4277. if (mpl->token != T_SEMICOLON)
  4278. mpl_error(mpl, "syntax error in display statement");
  4279. get_token(mpl /* ; */);
  4280. return dpy;
  4281. }
  4282. #endif
  4283. /*----------------------------------------------------------------------
  4284. -- printf_statement - parse printf statement.
  4285. --
  4286. -- This routine parses print statement using the syntax:
  4287. --
  4288. -- <printf statement> ::= <printf clause> ;
  4289. -- <printf statement> ::= <printf clause> > <file name> ;
  4290. -- <printf statement> ::= <printf clause> >> <file name> ;
  4291. -- <printf clause> ::= printf <domain> : <format> <printf list>
  4292. -- <printf clause> ::= printf <domain> <format> <printf list>
  4293. -- <domain> ::= <empty>
  4294. -- <domain> ::= <indexing expression>
  4295. -- <format> ::= <expression 5>
  4296. -- <printf list> ::= <empty>
  4297. -- <printf list> ::= <printf list> , <printf entry>
  4298. -- <printf entry> ::= <expression 9>
  4299. -- <file name> ::= <expression 5> */
  4300. PRINTF *printf_statement(MPL *mpl)
  4301. { PRINTF *prt;
  4302. PRINTF1 *entry, *last_entry;
  4303. xassert(is_keyword(mpl, "printf"));
  4304. /* create printf descriptor */
  4305. prt = alloc(PRINTF);
  4306. prt->domain = NULL;
  4307. prt->fmt = NULL;
  4308. prt->list = last_entry = NULL;
  4309. get_token(mpl /* printf */);
  4310. /* parse optional indexing expression */
  4311. if (mpl->token == T_LBRACE)
  4312. { prt->domain = indexing_expression(mpl);
  4313. #if 0
  4314. if (mpl->token != T_COLON)
  4315. mpl_error(mpl, "colon missing where expected");
  4316. #endif
  4317. }
  4318. /* skip optional colon */
  4319. if (mpl->token == T_COLON) get_token(mpl /* : */);
  4320. /* parse expression for format string */
  4321. prt->fmt = expression_5(mpl);
  4322. /* convert it to symbolic type, if necessary */
  4323. if (prt->fmt->type == A_NUMERIC)
  4324. prt->fmt = make_unary(mpl, O_CVTSYM, prt->fmt, A_SYMBOLIC, 0);
  4325. /* check that now the expression is of symbolic type */
  4326. if (prt->fmt->type != A_SYMBOLIC)
  4327. mpl_error(mpl, "format expression has invalid type");
  4328. /* parse printf list */
  4329. while (mpl->token == T_COMMA)
  4330. { get_token(mpl /* , */);
  4331. /* create new printf entry */
  4332. entry = alloc(PRINTF1);
  4333. entry->code = NULL;
  4334. entry->next = NULL;
  4335. /* and append it to the printf list */
  4336. if (prt->list == NULL)
  4337. prt->list = entry;
  4338. else
  4339. last_entry->next = entry;
  4340. last_entry = entry;
  4341. /* parse printf entry */
  4342. entry->code = expression_9(mpl);
  4343. if (!(entry->code->type == A_NUMERIC ||
  4344. entry->code->type == A_SYMBOLIC ||
  4345. entry->code->type == A_LOGICAL))
  4346. mpl_error(mpl, "only numeric, symbolic, or logical expression a"
  4347. "llowed");
  4348. }
  4349. /* close the domain scope */
  4350. if (prt->domain != NULL) close_scope(mpl, prt->domain);
  4351. #if 1 /* 14/VII-2006 */
  4352. /* parse optional redirection */
  4353. prt->fname = NULL, prt->app = 0;
  4354. if (mpl->token == T_GT || mpl->token == T_APPEND)
  4355. { prt->app = (mpl->token == T_APPEND);
  4356. get_token(mpl /* > or >> */);
  4357. /* parse expression for file name string */
  4358. prt->fname = expression_5(mpl);
  4359. /* convert it to symbolic type, if necessary */
  4360. if (prt->fname->type == A_NUMERIC)
  4361. prt->fname = make_unary(mpl, O_CVTSYM, prt->fname,
  4362. A_SYMBOLIC, 0);
  4363. /* check that now the expression is of symbolic type */
  4364. if (prt->fname->type != A_SYMBOLIC)
  4365. mpl_error(mpl, "file name expression has invalid type");
  4366. }
  4367. #endif
  4368. /* the printf statement has been completely parsed */
  4369. if (mpl->token != T_SEMICOLON)
  4370. mpl_error(mpl, "syntax error in printf statement");
  4371. get_token(mpl /* ; */);
  4372. return prt;
  4373. }
  4374. /*----------------------------------------------------------------------
  4375. -- for_statement - parse for statement.
  4376. --
  4377. -- This routine parses for statement using the syntax:
  4378. --
  4379. -- <for statement> ::= for <domain> <statement>
  4380. -- <for statement> ::= for <domain> { <statement list> }
  4381. -- <domain> ::= <indexing expression>
  4382. -- <statement list> ::= <empty>
  4383. -- <statement list> ::= <statement list> <statement>
  4384. -- <statement> ::= <check statement>
  4385. -- <statement> ::= <display statement>
  4386. -- <statement> ::= <printf statement>
  4387. -- <statement> ::= <for statement> */
  4388. FOR *for_statement(MPL *mpl)
  4389. { FOR *fur;
  4390. STATEMENT *stmt, *last_stmt;
  4391. xassert(is_keyword(mpl, "for"));
  4392. /* create for descriptor */
  4393. fur = alloc(FOR);
  4394. fur->domain = NULL;
  4395. fur->list = last_stmt = NULL;
  4396. get_token(mpl /* for */);
  4397. /* parse indexing expression */
  4398. if (mpl->token != T_LBRACE)
  4399. mpl_error(mpl, "indexing expression missing where expected");
  4400. fur->domain = indexing_expression(mpl);
  4401. /* skip optional colon */
  4402. if (mpl->token == T_COLON) get_token(mpl /* : */);
  4403. /* parse for statement body */
  4404. if (mpl->token != T_LBRACE)
  4405. { /* parse simple statement */
  4406. fur->list = simple_statement(mpl, 1);
  4407. }
  4408. else
  4409. { /* parse compound statement */
  4410. get_token(mpl /* { */);
  4411. while (mpl->token != T_RBRACE)
  4412. { /* parse statement */
  4413. stmt = simple_statement(mpl, 1);
  4414. /* and append it to the end of the statement list */
  4415. if (last_stmt == NULL)
  4416. fur->list = stmt;
  4417. else
  4418. last_stmt->next = stmt;
  4419. last_stmt = stmt;
  4420. }
  4421. get_token(mpl /* } */);
  4422. }
  4423. /* close the domain scope */
  4424. xassert(fur->domain != NULL);
  4425. close_scope(mpl, fur->domain);
  4426. /* the for statement has been completely parsed */
  4427. return fur;
  4428. }
  4429. /*----------------------------------------------------------------------
  4430. -- end_statement - parse end statement.
  4431. --
  4432. -- This routine parses end statement using the syntax:
  4433. --
  4434. -- <end statement> ::= end ; <eof> */
  4435. void end_statement(MPL *mpl)
  4436. { if (!mpl->flag_d && is_keyword(mpl, "end") ||
  4437. mpl->flag_d && is_literal(mpl, "end"))
  4438. { get_token(mpl /* end */);
  4439. if (mpl->token == T_SEMICOLON)
  4440. get_token(mpl /* ; */);
  4441. else
  4442. warning(mpl, "no semicolon following end statement; missing"
  4443. " semicolon inserted");
  4444. }
  4445. else
  4446. warning(mpl, "unexpected end of file; missing end statement in"
  4447. "serted");
  4448. if (mpl->token != T_EOF)
  4449. warning(mpl, "some text detected beyond end statement; text ig"
  4450. "nored");
  4451. return;
  4452. }
  4453. /*----------------------------------------------------------------------
  4454. -- simple_statement - parse simple statement.
  4455. --
  4456. -- This routine parses simple statement using the syntax:
  4457. --
  4458. -- <statement> ::= <set statement>
  4459. -- <statement> ::= <parameter statement>
  4460. -- <statement> ::= <variable statement>
  4461. -- <statement> ::= <constraint statement>
  4462. -- <statement> ::= <objective statement>
  4463. -- <statement> ::= <solve statement>
  4464. -- <statement> ::= <check statement>
  4465. -- <statement> ::= <display statement>
  4466. -- <statement> ::= <printf statement>
  4467. -- <statement> ::= <for statement>
  4468. --
  4469. -- If the flag spec is set, some statements cannot be used. */
  4470. STATEMENT *simple_statement(MPL *mpl, int spec)
  4471. { STATEMENT *stmt;
  4472. stmt = alloc(STATEMENT);
  4473. stmt->line = mpl->line;
  4474. stmt->next = NULL;
  4475. if (is_keyword(mpl, "set"))
  4476. { if (spec)
  4477. mpl_error(mpl, "set statement not allowed here");
  4478. stmt->type = A_SET;
  4479. stmt->u.set = set_statement(mpl);
  4480. }
  4481. else if (is_keyword(mpl, "param"))
  4482. { if (spec)
  4483. mpl_error(mpl, "parameter statement not allowed here");
  4484. stmt->type = A_PARAMETER;
  4485. stmt->u.par = parameter_statement(mpl);
  4486. }
  4487. else if (is_keyword(mpl, "var"))
  4488. { if (spec)
  4489. mpl_error(mpl, "variable statement not allowed here");
  4490. stmt->type = A_VARIABLE;
  4491. stmt->u.var = variable_statement(mpl);
  4492. }
  4493. else if (is_keyword(mpl, "subject") ||
  4494. is_keyword(mpl, "subj") ||
  4495. mpl->token == T_SPTP)
  4496. { if (spec)
  4497. mpl_error(mpl, "constraint statement not allowed here");
  4498. stmt->type = A_CONSTRAINT;
  4499. stmt->u.con = constraint_statement(mpl);
  4500. }
  4501. else if (is_keyword(mpl, "minimize") ||
  4502. is_keyword(mpl, "maximize"))
  4503. { if (spec)
  4504. mpl_error(mpl, "objective statement not allowed here");
  4505. stmt->type = A_CONSTRAINT;
  4506. stmt->u.con = objective_statement(mpl);
  4507. }
  4508. #if 1 /* 11/II-2008 */
  4509. else if (is_keyword(mpl, "table"))
  4510. { if (spec)
  4511. mpl_error(mpl, "table statement not allowed here");
  4512. stmt->type = A_TABLE;
  4513. stmt->u.tab = table_statement(mpl);
  4514. }
  4515. #endif
  4516. else if (is_keyword(mpl, "solve"))
  4517. { if (spec)
  4518. mpl_error(mpl, "solve statement not allowed here");
  4519. stmt->type = A_SOLVE;
  4520. stmt->u.slv = solve_statement(mpl);
  4521. }
  4522. else if (is_keyword(mpl, "check"))
  4523. { stmt->type = A_CHECK;
  4524. stmt->u.chk = check_statement(mpl);
  4525. }
  4526. else if (is_keyword(mpl, "display"))
  4527. { stmt->type = A_DISPLAY;
  4528. stmt->u.dpy = display_statement(mpl);
  4529. }
  4530. else if (is_keyword(mpl, "printf"))
  4531. { stmt->type = A_PRINTF;
  4532. stmt->u.prt = printf_statement(mpl);
  4533. }
  4534. else if (is_keyword(mpl, "for"))
  4535. { stmt->type = A_FOR;
  4536. stmt->u.fur = for_statement(mpl);
  4537. }
  4538. else if (mpl->token == T_NAME)
  4539. { if (spec)
  4540. mpl_error(mpl, "constraint statement not allowed here");
  4541. stmt->type = A_CONSTRAINT;
  4542. stmt->u.con = constraint_statement(mpl);
  4543. }
  4544. else if (is_reserved(mpl))
  4545. mpl_error(mpl, "invalid use of reserved keyword %s", mpl->image);
  4546. else
  4547. mpl_error(mpl, "syntax error in model section");
  4548. return stmt;
  4549. }
  4550. /*----------------------------------------------------------------------
  4551. -- model_section - parse model section.
  4552. --
  4553. -- This routine parses model section using the syntax:
  4554. --
  4555. -- <model section> ::= <empty>
  4556. -- <model section> ::= <model section> <statement>
  4557. --
  4558. -- Parsing model section is terminated by either the keyword 'data', or
  4559. -- the keyword 'end', or the end of file. */
  4560. void model_section(MPL *mpl)
  4561. { STATEMENT *stmt, *last_stmt;
  4562. xassert(mpl->model == NULL);
  4563. last_stmt = NULL;
  4564. while (!(mpl->token == T_EOF || is_keyword(mpl, "data") ||
  4565. is_keyword(mpl, "end")))
  4566. { /* parse statement */
  4567. stmt = simple_statement(mpl, 0);
  4568. /* and append it to the end of the statement list */
  4569. if (last_stmt == NULL)
  4570. mpl->model = stmt;
  4571. else
  4572. last_stmt->next = stmt;
  4573. last_stmt = stmt;
  4574. }
  4575. return;
  4576. }
  4577. /* eof */