2 Star 15 Fork 10

HaloOS/vcos_apps

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
basic.c 84.38 KB
一键复制 编辑 原始数据 按行查看 历史
openhaloos 提交于 3个月前 . haloOS init
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149
/****************************************************************************
* apps/interpreters/minibasic/basic.c
*
* Copyright (C) 2016 Gregory Nutt. All rights reserved.
*
* This file was taken from Mini Basic, versino 1.0 developed by Malcolm
* McLean, Leeds University. Mini Basic version 1.0 was released the
* Creative Commons Attribution license which, from my reading, appears to
* be compatible with the NuttX BSD-style license:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <math.h>
#include <limits.h>
#include <ctype.h>
#include <assert.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Configuration */
#ifndef CONFIG_INTERPRETER_MINIBASIC_IOBUFSIZE
# define CONFIG_INTERPRETER_MINIBASIC_IOBUFSIZE 1024
#endif
#define IOBUFSIZE CONFIG_INTERPRETER_MINIBASIC_IOBUFSIZE
/* Tokens defined */
#define EOS 0
#define VALUE 1
#define PI 2
#define E 3
#define DIV 10
#define MULT 11
#define OPAREN 12
#define CPAREN 13
#define PLUS 14
#define MINUS 15
#define SHRIEK 16
#define COMMA 17
#define MOD 200
#define SYNTAX_ERROR 20
#define EOL 21
#define EQUALS 22
#define STRID 23
#define FLTID 24
#define DIMFLTID 25
#define DIMSTRID 26
#define QUOTE 27
#define GREATER 28
#define LESS 29
#define SEMICOLON 30
#define PRINT 100
#define LET 101
#define DIM 102
#define IF 103
#define THEN 104
#define AND 105
#define OR 106
#define GOTO 107
#define INPUT 108
#define REM 109
#define FOR 110
#define TO 111
#define NEXT 112
#define STEP 113
#define SIN 5
#define COS 6
#define TAN 7
#define LN 8
#define POW 9
#define SQRT 18
#define ABS 201
#define LEN 202
#define ASCII 203
#define ASIN 204
#define ACOS 205
#define ATAN 206
#define INT 207
#define RND 208
#define VAL 209
#define VALLEN 210
#define INSTR 211
#define CHRSTRING 300
#define STRSTRING 301
#define LEFTSTRING 302
#define RIGHTSTRING 303
#define MIDSTRING 304
#define STRINGSTRING 305
/* Relational operators defined */
#define ROP_EQ 1 /* equals */
#define ROP_NEQ 2 /* doesn't equal */
#define ROP_LT 3 /* less than */
#define ROP_LTE 4 /* less than or equals */
#define ROP_GT 5 /* greater than */
#define ROP_GTE 6 /* greater than or equals */
/* Error codes (in BASIC script) defined */
#define ERR_CLEAR 0
#define ERR_SYNTAX 1
#define ERR_OUTOFMEMORY 2
#define ERR_IDTOOLONG 3
#define ERR_NOSUCHVARIABLE 4
#define ERR_BADSUBSCRIPT 5
#define ERR_TOOMANYDIMS 6
#define ERR_TOOMANYINITS 7
#define ERR_BADTYPE 8
#define ERR_TOOMANYFORS 9
#define ERR_NONEXT 10
#define ERR_NOFOR 11
#define ERR_DIVIDEBYZERO 12
#define ERR_NEGLOG 13
#define ERR_NEGSQRT 14
#define ERR_BADSINCOS 15
#define ERR_EOF 16
#define ERR_ILLEGALOFFSET 17
#define ERR_TYPEMISMATCH 18
#define ERR_INPUTTOOLONG 19
#define ERR_BADVALUE 20
#define ERR_NOTINT 21
#define MAXFORS 32 /* Maximum number of nested fors */
/****************************************************************************
* Private Types
****************************************************************************/
struct mb_line_s
{
int no; /* Line number */
FAR const char *str; /* Points to start of line */
};
struct mb_variable_s
{
char id[32]; /* Id of variable */
double dval; /* Its value if a real */
FAR char *sval; /* Its value if a string (malloced) */
};
struct mb_dimvar_s
{
char id[32]; /* Id of dimensioned variable */
int type; /* Its type, STRID or FLTID */
int ndims; /* Number of dimensions */
int dim[5]; /* Dimensions in x y order */
FAR char **str; /* Pointer to string data */
FAR double *dval; /* Pointer to real data */
};
struct mb_lvalue_s
{
int type; /* Type of variable (STRID or FLTID or SYNTAX_ERROR) */
FAR char **sval; /* Pointer to string data */
FAR double *dval; /* Pointer to real data */
};
struct mb_forloop_s
{
char id[32]; /* Id of control variable */
int nextline; /* Line below FOR to which control passes */
double toval; /* Terminal value */
double step; /* Step size */
};
/****************************************************************************
* Private Data
****************************************************************************/
/* NOTE: The use of these globals precludes the use of Mini Basic on
* multiple threads (at least in a flat address environment). If you
* want multiple copies of Mini Basic to run, you would need to:
* (1) Create a new struct mb_state_s that contains all of the following
* as fields.
* (2) Allocate an instance of struct mb_state_s in basic() as part of the
* initialization logic. And,
* (3) Pass the instance of struct mb_state_s to every Mini Basic function.
*/
static struct mb_forloop_s g_forstack[MAXFORS]; /* Stack for for loop control */
static int nfors; /* Number of fors on stack */
static FAR struct mb_variable_s *g_variables; /* The script's variables */
static int g_nvariables; /* Number of variables */
static FAR struct mb_dimvar_s *g_dimvariables; /* Dimensioned arrays */
static int g_ndimvariables; /* Number of dimensioned arrays */
static FAR struct mb_line_s *g_lines; /* List of line starts */
static int nlines; /* Number of BASIC g_lines in program */
static FILE *g_fpin; /* Input stream */
static FILE *g_fpout; /* Output stream */
static FILE *g_fperr; /* Error stream */
static FAR const char *g_string; /* String we are parsing */
static int g_token; /* Current token (lookahead) */
static int g_errorflag; /* Set when error in input encountered */
static char g_iobuffer[IOBUFSIZE]; /* I/O buffer */
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static int setup(FAR const char *script);
static void cleanup(void);
static void reporterror(int lineno);
static int findline(int no);
static int line(void);
static void doprint(void);
static void dolet(void);
static void dodim(void);
static int doif(void);
static int dogoto(void);
static void doinput(void);
static void dorem(void);
static int dofor(void);
static int donext(void);
static void lvalue(FAR struct mb_lvalue_s *lv);
static int boolexpr(void);
static int boolfactor(void);
static int relop(void);
static double expr(void);
static double term(void);
static double factor(void);
static double instr(void);
static double variable(void);
static double dimvariable(void);
static FAR struct mb_variable_s *findvariable(FAR const char *id);
static FAR struct mb_dimvar_s *finddimvar(FAR const char *id);
static FAR struct mb_dimvar_s *dimension(FAR const char *id, int ndims, ...);
static FAR void *getdimvar(FAR struct mb_dimvar_s *dv, ...);
static FAR struct mb_variable_s *addfloat(FAR const char *id);
static FAR struct mb_variable_s *addstring(FAR const char *id);
static FAR struct mb_dimvar_s *adddimvar(FAR const char *id);
static FAR char *stringexpr(void);
static FAR char *chrstring(void);
static FAR char *strstring(void);
static FAR char *leftstring(void);
static FAR char *rightstring(void);
static FAR char *midstring(void);
static FAR char *stringstring(void);
static FAR char *stringdimvar(void);
static FAR char *stringvar(void);
static FAR char *stringliteral(void);
static int integer(double x);
static void match(int tok);
static void seterror(int errorcode);
static int getnextline(FAR const char *str);
static int gettoken(FAR const char *str);
static int tokenlen(FAR const char *str, int tokenid);
static int isstring(int tokenid);
static double getvalue(FAR const char *str, FAR int *len);
static void getid(FAR const char *str, FAR char *out, FAR int *len);
static void mystrgrablit(FAR char *dest, FAR const char *src);
static FAR char *mystrend(FAR const char *str, char quote);
static int mystrcount(FAR const char *str, char ch);
static FAR char *mystrdup(FAR const char *str);
static FAR char *mystrconcat(FAR const char *str, FAR const char *cat);
static double factorial(double x);
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: setup
*
* Description:
* Sets up all our globals, including the list of lines.
* Params: script - the script passed by the user
* Returns: 0 on success, -1 on failure
*
*
****************************************************************************/
static int setup(FAR const char *script)
{
int i;
nlines = mystrcount(script, '\n');
g_lines = malloc(nlines * sizeof(struct mb_line_s));
if (!g_lines)
{
if (g_fperr)
{
fprintf(g_fperr, "Out of memory\n");
}
return -1;
}
for (i = 0; i < nlines; i++)
{
if (isdigit(*script))
{
g_lines[i].str = script;
g_lines[i].no = strtol(script, 0, 10);
}
else
{
i--;
nlines--;
}
script = strchr(script, '\n');
script++;
}
if (!nlines)
{
if (g_fperr)
{
fprintf(g_fperr, "Can't read program\n");
}
free(g_lines);
return -1;
}
for (i = 1; i < nlines; i++)
{
if (g_lines[i].no <= g_lines[i - 1].no)
{
if (g_fperr)
{
fprintf(g_fperr, "program lines %d and %d not in order\n",
g_lines[i - 1].no, g_lines[i].no);
}
free(g_lines);
return -1;
}
}
g_nvariables = 0;
g_variables = 0;
g_dimvariables = 0;
g_ndimvariables = 0;
return 0;
}
/****************************************************************************
* Name: cleanup
*
* Description:
* Frees all the memory we have allocated
*
****************************************************************************/
static void cleanup(void)
{
int i;
int ii;
int size;
for (i = 0; i < g_nvariables; i++)
{
if (g_variables[i].sval)
{
free(g_variables[i].sval);
}
}
if (g_variables)
{
free(g_variables);
}
g_variables = 0;
g_nvariables = 0;
for (i = 0; i < g_ndimvariables; i++)
{
if (g_dimvariables[i].type == STRID)
{
if (g_dimvariables[i].str)
{
size = 1;
for (ii = 0; ii < g_dimvariables[i].ndims; ii++)
{
size *= g_dimvariables[i].dim[ii];
}
for (ii = 0; ii < size; ii++)
{
if (g_dimvariables[i].str[ii])
{
free(g_dimvariables[i].str[ii]);
}
}
free(g_dimvariables[i].str);
}
}
else if (g_dimvariables[i].dval)
{
free(g_dimvariables[i].dval);
}
}
if (g_dimvariables)
{
free(g_dimvariables);
}
g_dimvariables = 0;
g_ndimvariables = 0;
if (g_lines)
{
free(g_lines);
}
g_lines = 0;
nlines = 0;
}
/****************************************************************************
* Name: reporterror
*
* Description:
* Frror report function.
* For reporting errors in the user's script.
* Checks the global g_errorflag.
* Writes to g_fperr.
* Params: lineno - the line on which the error occurred
*
****************************************************************************/
static void reporterror(int lineno)
{
if (!g_fperr)
{
return;
}
switch (g_errorflag)
{
case ERR_CLEAR:
assert(0);
break;
case ERR_SYNTAX:
fprintf(g_fperr, "Syntax error line %d\n", lineno);
break;
case ERR_OUTOFMEMORY:
fprintf(g_fperr, "Out of memory line %d\n", lineno);
break;
case ERR_IDTOOLONG:
fprintf(g_fperr, "Identifier too long line %d\n", lineno);
break;
case ERR_NOSUCHVARIABLE:
fprintf(g_fperr, "No such variable line %d\n", lineno);
break;
case ERR_BADSUBSCRIPT:
fprintf(g_fperr, "Bad subscript line %d\n", lineno);
break;
case ERR_TOOMANYDIMS:
fprintf(g_fperr, "Too many dimensions line %d\n", lineno);
break;
case ERR_TOOMANYINITS:
fprintf(g_fperr, "Too many initialisers line %d\n", lineno);
break;
case ERR_BADTYPE:
fprintf(g_fperr, "Illegal type line %d\n", lineno);
break;
case ERR_TOOMANYFORS:
fprintf(g_fperr, "Too many nested fors line %d\n", lineno);
break;
case ERR_NONEXT:
fprintf(g_fperr, "For without matching next line %d\n", lineno);
break;
case ERR_NOFOR:
fprintf(g_fperr, "Next without matching for line %d\n", lineno);
break;
case ERR_DIVIDEBYZERO:
fprintf(g_fperr, "Divide by zero lne %d\n", lineno);
break;
case ERR_NEGLOG:
fprintf(g_fperr, "Negative logarithm line %d\n", lineno);
break;
case ERR_NEGSQRT:
fprintf(g_fperr, "Negative square root line %d\n", lineno);
break;
case ERR_BADSINCOS:
fprintf(g_fperr, "Sine or cosine out of range line %d\n", lineno);
break;
case ERR_EOF:
fprintf(g_fperr, "End of input file %d\n", lineno);
break;
case ERR_ILLEGALOFFSET:
fprintf(g_fperr, "Illegal offset line %d\n", lineno);
break;
case ERR_TYPEMISMATCH:
fprintf(g_fperr, "Type mismatch line %d\n", lineno);
break;
case ERR_INPUTTOOLONG:
fprintf(g_fperr, "Input too long line %d\n", lineno);
break;
case ERR_BADVALUE:
fprintf(g_fperr, "Bad value at line %d\n", lineno);
break;
case ERR_NOTINT:
fprintf(g_fperr, "Not an integer at line %d\n", lineno);
break;
default:
fprintf(g_fperr, "ERROR line %d\n", lineno);
break;
}
}
/****************************************************************************
* Name: findline
*
* Description:
* Binary search for a line
* Params: no - line number to find
* Returns: index of the line, or -1 on fail.
*
****************************************************************************/
static int findline(int no)
{
int high;
int low;
int mid;
low = 0;
high = nlines - 1;
while (high > low + 1)
{
mid = (high + low) / 2;
if (g_lines[mid].no == no)
{
return mid;
}
if (g_lines[mid].no > no)
{
high = mid;
}
else
{
low = mid;
}
}
if (g_lines[low].no == no)
{
mid = low;
}
else if (g_lines[high].no == no)
{
mid = high;
}
else
{
mid = -1;
}
return mid;
}
/****************************************************************************
* Name: line
*
* Description:
* Parse a line. High level parse function
*
****************************************************************************/
static int line(void)
{
int answer = 0;
FAR const char *str;
match(VALUE);
switch (g_token)
{
case PRINT:
doprint();
break;
case LET:
dolet();
break;
case DIM:
dodim();
break;
case IF:
answer = doif();
break;
case GOTO:
answer = dogoto();
break;
case INPUT:
doinput();
break;
case REM:
dorem();
return 0;
case FOR:
answer = dofor();
break;
case NEXT:
answer = donext();
break;
default:
seterror(ERR_SYNTAX);
break;
}
if (g_token != EOS)
{
/* match(VALUE); */
/* check for a newline */
str = g_string;
while (isspace(*str))
{
if (*str == '\n')
{
break;
}
str++;
}
if (*str != '\n')
{
seterror(ERR_SYNTAX);
}
}
return answer;
}
/****************************************************************************
* Name: doprint
*
* Description:
* The PRINT statement
*
****************************************************************************/
static void doprint(void)
{
FAR char *str;
double x;
match(PRINT);
while (1)
{
if (isstring(g_token))
{
str = stringexpr();
if (str)
{
fprintf(g_fpout, "%s", str);
free(str);
}
}
else
{
x = expr();
fprintf(g_fpout, "%g", x);
}
if (g_token == COMMA)
{
fprintf(g_fpout, " ");
match(COMMA);
}
else
{
break;
}
}
if (g_token == SEMICOLON)
{
match(SEMICOLON);
fflush(g_fpout);
}
else
{
fprintf(g_fpout, "\n");
}
}
/****************************************************************************
* Name: dolet
*
* Description:
* The LET statement
*
****************************************************************************/
static void dolet(void)
{
struct mb_lvalue_s lv;
FAR char *temp;
match(LET);
lvalue(&lv);
match(EQUALS);
switch (lv.type)
{
case FLTID:
*lv.dval = expr();
break;
case STRID:
temp = *lv.sval;
*lv.sval = stringexpr();
if (temp)
{
free(temp);
}
break;
default:
break;
}
}
/****************************************************************************
* Name: dodim
*
* Description:
* The DIM statement
*
****************************************************************************/
static void dodim(void)
{
int ndims = 0;
double dims[6];
char name[32];
int len;
FAR struct mb_dimvar_s *dimvar;
int i;
int size = 1;
match(DIM);
switch (g_token)
{
case DIMFLTID:
case DIMSTRID:
getid(g_string, name, &len);
match(g_token);
dims[ndims++] = expr();
while (g_token == COMMA)
{
match(COMMA);
dims[ndims++] = expr();
if (ndims > 5)
{
seterror(ERR_TOOMANYDIMS);
return;
}
}
match(CPAREN);
for (i = 0; i < ndims; i++)
{
if (dims[i] < 0 || dims[i] != (int)dims[i])
{
seterror(ERR_BADSUBSCRIPT);
return;
}
}
switch (ndims)
{
case 1:
dimvar = dimension(name, 1, (int)dims[0]);
break;
case 2:
dimvar = dimension(name, 2, (int)dims[0], (int)dims[1]);
break;
case 3:
dimvar = dimension(name, 3, (int)dims[0],
(int)dims[1], (int)dims[2]);
break;
case 4:
dimvar =
dimension(name, 4, (int)dims[0], (int)dims[1], (int)dims[2],
(int)dims[3]);
break;
case 5:
dimvar =
dimension(name, 5, (int)dims[0], (int)dims[1], (int)dims[2],
(int)dims[3], (int)dims[4]);
break;
}
break;
default:
seterror(ERR_SYNTAX);
return;
}
if (dimvar == 0)
{
/* Out of memory */
seterror(ERR_OUTOFMEMORY);
return;
}
if (g_token == EQUALS)
{
match(EQUALS);
for (i = 0; i < dimvar->ndims; i++)
{
size *= dimvar->dim[i];
}
switch (dimvar->type)
{
case FLTID:
i = 0;
dimvar->dval[i++] = expr();
while (g_token == COMMA && i < size)
{
match(COMMA);
dimvar->dval[i++] = expr();
if (g_errorflag)
{
break;
}
}
break;
case STRID:
i = 0;
if (dimvar->str[i])
{
free(dimvar->str[i]);
}
dimvar->str[i++] = stringexpr();
while (g_token == COMMA && i < size)
{
match(COMMA);
if (dimvar->str[i])
{
free(dimvar->str[i]);
}
dimvar->str[i++] = stringexpr();
if (g_errorflag)
{
break;
}
}
break;
}
if (g_token == COMMA)
{
seterror(ERR_TOOMANYINITS);
}
}
}
/****************************************************************************
* Name: doif
*
* Description:
* The IF statement.
* If jump taken, returns new line no, else returns 0
*
****************************************************************************/
static int doif(void)
{
int condition;
int jump;
match(IF);
condition = boolexpr();
match(THEN);
jump = integer(expr());
if (condition)
{
return jump;
}
else
{
return 0;
}
}
/****************************************************************************
* Name: dogoto
*
* Description:
* The GOTO satement
* Returns new line number
*
****************************************************************************/
static int dogoto(void)
{
match(GOTO);
return integer(expr());
}
/****************************************************************************
* Name: dofor
*
* Description:
* The FOR statement.
*
* Pushes the for stack.
* Returns line to jump to, or -1 to end program
*
****************************************************************************/
static int dofor(void)
{
struct mb_lvalue_s lv;
char id[32];
char nextid[32];
int len;
double initval;
double toval;
double stepval;
FAR const char *savestring;
int answer;
match(FOR);
getid(g_string, id, &len);
lvalue(&lv);
if (lv.type != FLTID)
{
seterror(ERR_BADTYPE);
return -1;
}
match(EQUALS);
initval = expr();
match(TO);
toval = expr();
if (g_token == STEP)
{
match(STEP);
stepval = expr();
}
else
{
stepval = 1.0;
}
*lv.dval = initval;
if (nfors > MAXFORS - 1)
{
seterror(ERR_TOOMANYFORS);
return -1;
}
if ((stepval < 0 && initval < toval) ||
(stepval > 0 && initval > toval))
{
savestring = g_string;
while ((g_string = strchr(g_string, '\n')) != NULL)
{
g_errorflag = 0;
g_token = gettoken(g_string);
match(VALUE);
if (g_token == NEXT)
{
match(NEXT);
if (g_token == FLTID || g_token == DIMFLTID)
{
getid(g_string, nextid, &len);
if (!strcmp(id, nextid))
{
answer = getnextline(g_string);
g_string = savestring;
g_token = gettoken(g_string);
return answer ? answer : -1;
}
}
}
}
seterror(ERR_NONEXT);
return -1;
}
else
{
strlcpy(g_forstack[nfors].id, id, sizeof(g_forstack[nfors].id));
g_forstack[nfors].nextline = getnextline(g_string);
g_forstack[nfors].step = stepval;
g_forstack[nfors].toval = toval;
nfors++;
return 0;
}
}
/****************************************************************************
* Name: donext
*
* Description:
* The NEXT statement
* Updates the counting index, and returns line to jump to
*
****************************************************************************/
static int donext(void)
{
char id[32];
int len;
struct mb_lvalue_s lv;
match(NEXT);
if (nfors)
{
getid(g_string, id, &len);
lvalue(&lv);
if (lv.type != FLTID)
{
seterror(ERR_BADTYPE);
return -1;
}
*lv.dval += g_forstack[nfors - 1].step;
if ((g_forstack[nfors - 1].step < 0 &&
*lv.dval < g_forstack[nfors - 1].toval) ||
(g_forstack[nfors - 1].step > 0 &&
*lv.dval > g_forstack[nfors - 1].toval))
{
nfors--;
return 0;
}
else
{
return g_forstack[nfors - 1].nextline;
}
}
else
{
seterror(ERR_NOFOR);
return -1;
}
}
/****************************************************************************
* Name: doinput
*
* Description:
* The INPUT statement
*
****************************************************************************/
static void doinput(void)
{
struct mb_lvalue_s lv;
FAR char *end;
match(INPUT);
lvalue(&lv);
switch (lv.type)
{
case FLTID:
{
FAR char *ptr;
int nch;
/* Copy floating point number to a g_iobuffer. Skip over leading
* spaces and terminate with a NUL when a space, tab, newline, EOF,
* or comma is detected.
*/
for (nch = 0, ptr = g_iobuffer; nch < (IOBUFSIZE - 1); nch++)
{
int ch = fgetc(g_fpin);
if (ch == EOF)
{
seterror(ERR_EOF);
return;
}
if (ch == ' ' || ch == '\t' || ch == ',' || ch == '\n')
{
ungetc(ch, g_fpin);
break;
}
}
*ptr = '\0';
/* Use strtod() to get the floating point value from the substring
* in g_iobuffer.
*/
*lv.dval = strtod(g_iobuffer, &ptr);
if (ptr == g_iobuffer)
{
seterror(ERR_SYNTAX);
return;
}
}
break;
case STRID:
{
if (*lv.sval)
{
free(*lv.sval);
*lv.sval = NULL;
}
if (fgets(g_iobuffer, IOBUFSIZE, g_fpin) == 0)
{
seterror(ERR_EOF);
return;
}
end = strchr(g_iobuffer, '\n');
if (!end)
{
seterror(ERR_INPUTTOOLONG);
return;
}
*end = 0;
*lv.sval = mystrdup(g_iobuffer);
if (!*lv.sval)
{
seterror(ERR_OUTOFMEMORY);
return;
}
}
break;
default:
break;
}
}
/****************************************************************************
* Name: dorem
*
* Description:
* The REM statement.
* Note is unique as the rest of the line is not parsed
*
****************************************************************************/
static void dorem(void)
{
match(REM);
}
/****************************************************************************
* Name: lvalue
*
* Description:
* Get an lvalue from the environment
* Params: lv - structure to fill.
* Notes: missing variables (but not out of range subscripts)
* are added to the variable list.
*
****************************************************************************/
static void lvalue(FAR struct mb_lvalue_s *lv)
{
char name[32];
int len;
FAR struct mb_variable_s *var;
FAR struct mb_dimvar_s *dimvar;
int index[5];
FAR void *valptr = 0;
int type;
lv->type = SYNTAX_ERROR;
lv->dval = NULL;
lv->sval = NULL;
switch (g_token)
{
case FLTID:
{
getid(g_string, name, &len);
match(FLTID);
var = findvariable(name);
if (!var)
{
var = addfloat(name);
}
if (!var)
{
seterror(ERR_OUTOFMEMORY);
return;
}
lv->type = FLTID;
lv->dval = &var->dval;
lv->sval = NULL;
}
break;
case STRID:
{
getid(g_string, name, &len);
match(STRID);
var = findvariable(name);
if (!var)
{
var = addstring(name);
}
if (!var)
{
seterror(ERR_OUTOFMEMORY);
return;
}
lv->type = STRID;
lv->sval = &var->sval;
lv->dval = NULL;
}
break;
case DIMFLTID:
case DIMSTRID:
{
type = (g_token == DIMFLTID) ? FLTID : STRID;
getid(g_string, name, &len);
match(g_token);
dimvar = finddimvar(name);
if (dimvar)
{
switch (dimvar->ndims)
{
case 1:
{
index[0] = integer(expr());
if (g_errorflag == 0)
{
valptr = getdimvar(dimvar, index[0]);
}
}
break;
case 2:
{
index[0] = integer(expr());
match(COMMA);
index[1] = integer(expr());
if (g_errorflag == 0)
{
valptr = getdimvar(dimvar, index[0], index[1]);
}
}
break;
case 3:
{
index[0] = integer(expr());
match(COMMA);
index[1] = integer(expr());
match(COMMA);
index[2] = integer(expr());
if (g_errorflag == 0)
{
valptr = getdimvar(dimvar, index[0],
index[1], index[2]);
}
}
break;
case 4:
{
index[0] = integer(expr());
match(COMMA);
index[1] = integer(expr());
match(COMMA);
index[2] = integer(expr());
match(COMMA);
index[3] = integer(expr());
if (g_errorflag == 0)
{
valptr = getdimvar(dimvar, index[0],
index[1], index[2], index[3]);
}
}
break;
case 5:
{
index[0] = integer(expr());
match(COMMA);
index[1] = integer(expr());
match(COMMA);
index[2] = integer(expr());
match(COMMA);
index[3] = integer(expr());
match(COMMA);
index[4] = integer(expr());
if (g_errorflag == 0)
{
valptr = getdimvar(dimvar, index[0],
index[1], index[2], index[3]);
}
}
break;
}
match(CPAREN);
}
else
{
seterror(ERR_NOSUCHVARIABLE);
return;
}
if (valptr)
{
lv->type = type;
if (type == FLTID)
{
lv->dval = valptr;
}
else if (type == STRID)
{
lv->sval = valptr;
}
else
{
assert(0);
}
}
}
break;
default:
seterror(ERR_SYNTAX);
}
}
/****************************************************************************
* Name: boolexpr
*
* Description:
* Parse a boolean expression
* Consists of expressions or strings and relational operators,
* and parentheses
*
****************************************************************************/
static int boolexpr(void)
{
int left;
int right;
left = boolfactor();
while (1)
{
switch (g_token)
{
case AND:
match(AND);
right = boolexpr();
return (left && right) ? 1 : 0;
case OR:
match(OR);
right = boolexpr();
return (left || right) ? 1 : 0;
default:
return left;
}
}
}
/****************************************************************************
* Name: boolfactor
*
* Description:
* Boolean factor, consists of expression relop expression
* or string relop string, or ( boolexpr() )
*
****************************************************************************/
static int boolfactor(void)
{
int answer;
double left;
double right;
int op;
FAR char *strleft;
FAR char *strright;
int cmp;
switch (g_token)
{
case OPAREN:
match(OPAREN);
answer = boolexpr();
match(CPAREN);
break;
default:
if (isstring(g_token))
{
strleft = stringexpr();
op = relop();
strright = stringexpr();
if (!strleft || !strright)
{
if (strleft)
{
free(strleft);
}
if (strright)
{
free(strright);
}
return 0;
}
cmp = strcmp(strleft, strright);
switch (op)
{
case ROP_EQ:
answer = cmp == 0 ? 1 : 0;
break;
case ROP_NEQ:
answer = cmp == 0 ? 0 : 1;
break;
case ROP_LT:
answer = cmp < 0 ? 1 : 0;
break;
case ROP_LTE:
answer = cmp <= 0 ? 1 : 0;
break;
case ROP_GT:
answer = cmp > 0 ? 1 : 0;
break;
case ROP_GTE:
answer = cmp >= 0 ? 1 : 0;
break;
default:
answer = 0;
}
free(strleft);
free(strright);
}
else
{
left = expr();
op = relop();
right = expr();
switch (op)
{
case ROP_EQ:
answer = (left == right) ? 1 : 0;
break;
case ROP_NEQ:
answer = (left != right) ? 1 : 0;
break;
case ROP_LT:
answer = (left < right) ? 1 : 0;
break;
case ROP_LTE:
answer = (left <= right) ? 1 : 0;
break;
case ROP_GT:
answer = (left > right) ? 1 : 0;
break;
case ROP_GTE:
answer = (left >= right) ? 1 : 0;
break;
default:
g_errorflag = 1;
return 0;
}
}
}
return answer;
}
/****************************************************************************
* Name: relop
*
* Description:
* Get a relational operator
* Returns operator parsed or SYNTAX_ERROR
*
****************************************************************************/
static int relop(void)
{
switch (g_token)
{
case EQUALS:
match(EQUALS);
return ROP_EQ;
case GREATER:
match(GREATER);
if (g_token == EQUALS)
{
match(EQUALS);
return ROP_GTE;
}
return ROP_GT;
case LESS:
match(LESS);
if (g_token == EQUALS)
{
match(EQUALS);
return ROP_LTE;
}
else if (g_token == GREATER)
{
match(GREATER);
return ROP_NEQ;
}
return ROP_LT;
default:
seterror(ERR_SYNTAX);
return SYNTAX_ERROR;
}
}
/****************************************************************************
* Name: expr
*
* Description:
* Parses an expression
*
****************************************************************************/
static double expr(void)
{
double left;
double right;
left = term();
while (1)
{
switch (g_token)
{
case PLUS:
match(PLUS);
right = term();
left += right;
break;
case MINUS:
match(MINUS);
right = term();
left -= right;
break;
default:
return left;
}
}
}
/****************************************************************************
* Name: term
*
* Description:
* Parses a term
*
****************************************************************************/
static double term(void)
{
double left;
double right;
left = factor();
while (1)
{
switch (g_token)
{
case MULT:
match(MULT);
right = factor();
left *= right;
break;
case DIV:
match(DIV);
right = factor();
if (right != 0.0)
{
left /= right;
}
else
{
seterror(ERR_DIVIDEBYZERO);
}
break;
case MOD:
match(MOD);
right = factor();
left = fmod(left, right);
break;
default:
return left;
}
}
}
/****************************************************************************
* Name: factor
*
* Description:
* Parses a factor
*
****************************************************************************/
static double factor(void)
{
double answer = 0;
FAR char *str;
FAR char *end;
int len;
switch (g_token)
{
case OPAREN:
match(OPAREN);
answer = expr();
match(CPAREN);
break;
case VALUE:
answer = getvalue(g_string, &len);
match(VALUE);
break;
case MINUS:
match(MINUS);
answer = -factor();
break;
case FLTID:
answer = variable();
break;
case DIMFLTID:
answer = dimvariable();
break;
case E:
answer = exp(1.0);
match(E);
break;
case PI:
answer = acos(0.0) * 2.0;
match(PI);
break;
case SIN:
match(SIN);
match(OPAREN);
answer = expr();
match(CPAREN);
answer = sin(answer);
break;
case COS:
match(COS);
match(OPAREN);
answer = expr();
match(CPAREN);
answer = cos(answer);
break;
case TAN:
match(TAN);
match(OPAREN);
answer = expr();
match(CPAREN);
answer = tan(answer);
break;
case LN:
match(LN);
match(OPAREN);
answer = expr();
match(CPAREN);
if (answer > 0)
{
answer = log(answer);
}
else
{
seterror(ERR_NEGLOG);
}
break;
case POW:
match(POW);
match(OPAREN);
answer = expr();
match(COMMA);
answer = pow(answer, expr());
match(CPAREN);
break;
case SQRT:
match(SQRT);
match(OPAREN);
answer = expr();
match(CPAREN);
if (answer >= 0.0)
{
answer = sqrt(answer);
}
else
{
seterror(ERR_NEGSQRT);
}
break;
case ABS:
match(ABS);
match(OPAREN);
answer = expr();
match(CPAREN);
answer = fabs(answer);
break;
case LEN:
match(LEN);
match(OPAREN);
str = stringexpr();
match(CPAREN);
if (str)
{
answer = strlen(str);
free(str);
}
else
{
answer = 0;
}
break;
case ASCII:
match(ASCII);
match(OPAREN);
str = stringexpr();
match(CPAREN);
if (str)
{
answer = *str;
free(str);
}
else
{
answer = 0;
}
break;
case ASIN:
match(ASIN);
match(OPAREN);
answer = expr();
match(CPAREN);
if (answer >= -1 && answer <= 1)
{
answer = asin(answer);
}
else
{
seterror(ERR_BADSINCOS);
}
break;
case ACOS:
match(ACOS);
match(OPAREN);
answer = expr();
match(CPAREN);
if (answer >= -1 && answer <= 1)
{
answer = acos(answer);
}
else
{
seterror(ERR_BADSINCOS);
}
break;
case ATAN:
match(ATAN);
match(OPAREN);
answer = expr();
match(CPAREN);
answer = atan(answer);
break;
case INT:
match(INT);
match(OPAREN);
answer = expr();
match(CPAREN);
answer = floor(answer);
break;
case RND:
match(RND);
match(OPAREN);
answer = expr();
match(CPAREN);
answer = integer(answer);
if (answer > 1)
{
answer = floor(rand() / (RAND_MAX + 1.0) * answer);
}
else if (answer == 1)
{
answer = rand() / (RAND_MAX + 1.0);
}
else
{
if (answer < 0)
{
srand((unsigned)-answer);
}
answer = 0;
}
break;
case VAL:
match(VAL);
match(OPAREN);
str = stringexpr();
match(CPAREN);
if (str)
{
answer = strtod(str, 0);
free(str);
}
else
{
answer = 0;
}
break;
case VALLEN:
match(VALLEN);
match(OPAREN);
str = stringexpr();
match(CPAREN);
if (str)
{
strtod(str, &end);
answer = end - str;
free(str);
}
else
{
answer = 0.0;
}
break;
case INSTR:
answer = instr();
break;
default:
if (isstring(g_token))
{
seterror(ERR_TYPEMISMATCH);
}
else
{
seterror(ERR_SYNTAX);
}
break;
}
while (g_token == SHRIEK)
{
match(SHRIEK);
answer = factorial(answer);
}
return answer;
}
/****************************************************************************
* Name: instr
*
* Description:
* Calculate the INSTR() function.
*
****************************************************************************/
static double instr(void)
{
FAR char *str;
FAR char *substr;
FAR char *end;
double answer = 0;
int offset;
match(INSTR);
match(OPAREN);
str = stringexpr();
match(COMMA);
substr = stringexpr();
match(COMMA);
offset = integer(expr());
offset--;
match(CPAREN);
if (!str || !substr)
{
if (str)
{
free(str);
}
if (substr)
{
free(substr);
}
return 0;
}
if (offset >= 0 && offset < (int)strlen(str))
{
end = strstr(str + offset, substr);
if (end)
{
answer = end - str + 1.0;
}
}
free(str);
free(substr);
return answer;
}
/****************************************************************************
* Name: variable
*
* Description:
* Get the value of a scalar variable from string
* matches FLTID
*
*
****************************************************************************/
static double variable(void)
{
FAR struct mb_variable_s *var;
char id[32];
int len;
getid(g_string, id, &len);
match(FLTID);
var = findvariable(id);
if (var)
{
return var->dval;
}
else
{
seterror(ERR_NOSUCHVARIABLE);
return 0.0;
}
}
/****************************************************************************
* Name: dimvariable
*
* Description:
* Get value of a dimensioned variable from string.
* matches DIMFLTID
*
****************************************************************************/
static double dimvariable(void)
{
FAR struct mb_dimvar_s *dimvar;
char id[32];
int len;
int index[5];
FAR double *answer = NULL;
getid(g_string, id, &len);
match(DIMFLTID);
dimvar = finddimvar(id);
if (!dimvar)
{
seterror(ERR_NOSUCHVARIABLE);
return 0.0;
}
if (dimvar)
{
switch (dimvar->ndims)
{
case 1:
index[0] = integer(expr());
answer = getdimvar(dimvar, index[0]);
break;
case 2:
index[0] = integer(expr());
match(COMMA);
index[1] = integer(expr());
answer = getdimvar(dimvar, index[0], index[1]);
break;
case 3:
index[0] = integer(expr());
match(COMMA);
index[1] = integer(expr());
match(COMMA);
index[2] = integer(expr());
answer = getdimvar(dimvar, index[0], index[1], index[2]);
break;
case 4:
index[0] = integer(expr());
match(COMMA);
index[1] = integer(expr());
match(COMMA);
index[2] = integer(expr());
match(COMMA);
index[3] = integer(expr());
answer = getdimvar(dimvar, index[0], index[1], index[2], index[3]);
break;
case 5:
index[0] = integer(expr());
match(COMMA);
index[1] = integer(expr());
match(COMMA);
index[2] = integer(expr());
match(COMMA);
index[3] = integer(expr());
match(COMMA);
index[4] = integer(expr());
answer = getdimvar(dimvar, index[0], index[1],
index[2], index[3], index[4]);
break;
}
match(CPAREN);
}
if (answer != NULL)
{
return *answer;
}
return 0.0;
}
/****************************************************************************
* Name: findvariable
*
* Description:
* Find a scalar variable invariables list
* Params: id - id to get
* Returns: pointer to that entry, 0 on fail
*
****************************************************************************/
static FAR struct mb_variable_s *findvariable(FAR const char *id)
{
int i;
for (i = 0; i < g_nvariables; i++)
{
if (!strcmp(g_variables[i].id, id))
{
return &g_variables[i];
}
}
return 0;
}
/****************************************************************************
* Name: finddimvar
*
* Description:
* Get a dimensioned array by name
* Params: id (includes opening parenthesis)
* Returns: pointer to array entry or 0 on fail
*
****************************************************************************/
static struct mb_dimvar_s *finddimvar(FAR const char *id)
{
int i;
for (i = 0; i < g_ndimvariables; i++)
{
if (!strcmp(g_dimvariables[i].id, id))
{
return &g_dimvariables[i];
}
}
return 0;
}
/****************************************************************************
* Name: dimension
*
* Description:
* Dimension an array.
* Params: id - the id of the array (include leading ()
* ndims - number of dimension (1-5)
* ... - integers giving dimension size,
*
****************************************************************************/
static FAR struct mb_dimvar_s *dimension(FAR const char *id, int ndims, ...)
{
FAR struct mb_dimvar_s *dv;
va_list vargs;
int size = 1;
int oldsize = 1;
int i;
int dimensions[5];
FAR double *dtemp;
FAR char **stemp;
assert(ndims <= 5);
if (ndims > 5)
{
return 0;
}
dv = finddimvar(id);
if (!dv)
{
dv = adddimvar(id);
}
if (!dv)
{
seterror(ERR_OUTOFMEMORY);
return 0;
}
if (dv->ndims)
{
for (i = 0; i < dv->ndims; i++)
{
oldsize *= dv->dim[i];
}
}
else
{
oldsize = 0;
}
va_start(vargs, ndims);
for (i = 0; i < ndims; i++)
{
dimensions[i] = va_arg(vargs, int);
size *= dimensions[i];
}
va_end(vargs);
switch (dv->type)
{
case FLTID:
dtemp = realloc(dv->dval, size * sizeof(double));
if (dtemp)
{
dv->dval = dtemp;
}
else
{
seterror(ERR_OUTOFMEMORY);
return 0;
}
break;
case STRID:
if (dv->str)
{
for (i = size; i < oldsize; i++)
{
if (dv->str[i])
{
free(dv->str[i]);
dv->str[i] = 0;
}
}
}
stemp = realloc(dv->str, size * sizeof(char *));
if (stemp)
{
dv->str = stemp;
for (i = oldsize; i < size; i++)
{
dv->str[i] = 0;
}
}
else
{
for (i = 0; i < oldsize; i++)
{
if (dv->str[i])
{
free(dv->str[i]);
dv->str[i] = 0;
}
}
seterror(ERR_OUTOFMEMORY);
return 0;
}
break;
default:
assert(0);
}
for (i = 0; i < 5; i++)
{
dv->dim[i] = dimensions[i];
}
dv->ndims = ndims;
return dv;
}
/****************************************************************************
* Name: getdimvar
*
* Description:
* Get the address of a dimensioned array element.
* Works for both string and real arrays.
* Params: dv - the array's entry in variable list
* ... - integers telling which array element to get
* Returns: the address of that element, 0 on fail
*
****************************************************************************/
static FAR void *getdimvar(FAR struct mb_dimvar_s *dv, ...)
{
va_list vargs;
int index[5];
int i;
FAR void *answer = 0;
va_start(vargs, dv);
for (i = 0; i < dv->ndims; i++)
{
index[i] = va_arg(vargs, int);
index[i]--;
}
va_end(vargs);
for (i = 0; i < dv->ndims; i++)
{
if (index[i] >= dv->dim[i] || index[i] < 0)
{
seterror(ERR_BADSUBSCRIPT);
return 0;
}
}
if (dv->type == FLTID)
{
switch (dv->ndims)
{
case 1:
answer = &dv->dval[index[0]];
break;
case 2:
answer = &dv->dval[index[1] * dv->dim[0] + index[0]];
break;
case 3:
answer = &dv->dval[index[2] * (dv->dim[0] * dv->dim[1])
+ index[1] * dv->dim[0] + index[0]];
break;
case 4:
answer =
&dv->dval[index[3] * (dv->dim[0] + dv->dim[1] + dv->dim[2]) +
index[2] * (dv->dim[0] * dv->dim[1]) +
index[1] * dv->dim[0] + index[0]];
break;
case 5:
answer =
&dv->dval[index[4] *
(dv->dim[0] + dv->dim[1] + dv->dim[2] +
dv->dim[3]) + index[3] * (dv->dim[0] + dv->dim[1] +
dv->dim[2]) +
index[2] * (dv->dim[0] + dv->dim[1]) +
index[1] * dv->dim[0] + index[0]];
break;
}
}
else if (dv->type == STRID)
{
switch (dv->ndims)
{
case 1:
answer = &dv->str[index[0]];
break;
case 2:
answer = &dv->str[index[1] * dv->dim[0] + index[0]];
break;
case 3:
answer = &dv->str[index[2] * (dv->dim[0] * dv->dim[1])
+ index[1] * dv->dim[0] + index[0]];
break;
case 4:
answer =
&dv->str[index[3] * (dv->dim[0] + dv->dim[1] + dv->dim[2]) +
index[2] * (dv->dim[0] * dv->dim[1]) +
index[1] * dv->dim[0] + index[0]];
break;
case 5:
answer =
&dv->str[index[4] *
(dv->dim[0] + dv->dim[1] + dv->dim[2] + dv->dim[3]) +
index[3] * (dv->dim[0] + dv->dim[1] + dv->dim[2]) +
index[2] * (dv->dim[0] + dv->dim[1]) +
index[1] * dv->dim[0] + index[0]];
break;
}
}
return answer;
}
/****************************************************************************
* Name: addfloat
*
* Description:
* Add a real variable to our variable list
* Params: id - id of variable to add.
* Returns: pointer to new entry in table
*
****************************************************************************/
static FAR struct mb_variable_s *addfloat(FAR const char *id)
{
FAR struct mb_variable_s *vars;
vars =
realloc(g_variables, (g_nvariables + 1) * sizeof(struct mb_variable_s));
if (vars)
{
g_variables = vars;
strlcpy(g_variables[g_nvariables].id, id,
sizeof(g_variables[g_nvariables].id));
g_variables[g_nvariables].dval = 0.0;
g_variables[g_nvariables].sval = NULL;
g_nvariables++;
return &g_variables[g_nvariables - 1];
}
else
{
seterror(ERR_OUTOFMEMORY);
}
return 0;
}
/****************************************************************************
* Name: addstring
*
* Description:
* Add a string variable to table.
* Params: id - id of variable to get (including trailing $)
* Returns: pointer to new entry in table, 0 on fail.
*
****************************************************************************/
static FAR struct mb_variable_s *addstring(FAR const char *id)
{
FAR struct mb_variable_s *vars;
vars =
realloc(g_variables, (g_nvariables + 1) * sizeof(struct mb_variable_s));
if (vars)
{
g_variables = vars;
strlcpy(g_variables[g_nvariables].id, id,
sizeof(g_variables[g_nvariables].id));
g_variables[g_nvariables].sval = NULL;
g_variables[g_nvariables].dval = 0.0;
g_nvariables++;
return &g_variables[g_nvariables - 1];
}
else
{
seterror(ERR_OUTOFMEMORY);
}
return 0;
}
/****************************************************************************
* Name: adddimvar
*
* Description:
* Add a new array to our symbol table.
* Params: id - id of array (include leading ()
* Returns: pointer to new entry, 0 on fail.
*
****************************************************************************/
static FAR struct mb_dimvar_s *adddimvar(FAR const char *id)
{
FAR struct mb_dimvar_s *vars;
vars = realloc(g_dimvariables,
(g_ndimvariables + 1) * sizeof(struct mb_dimvar_s));
if (vars)
{
g_dimvariables = vars;
strlcpy(g_dimvariables[g_ndimvariables].id, id,
sizeof(g_dimvariables[g_ndimvariables].id));
g_dimvariables[g_ndimvariables].dval = NULL;
g_dimvariables[g_ndimvariables].str = NULL;
g_dimvariables[g_ndimvariables].ndims = 0;
g_dimvariables[g_ndimvariables].type = strchr(id, '$') ? STRID : FLTID;
g_ndimvariables++;
return &g_dimvariables[g_ndimvariables - 1];
}
else
{
seterror(ERR_OUTOFMEMORY);
}
return 0;
}
/****************************************************************************
* Name: stringexpr
*
* Description:
* High level string parsing function.
* Returns: a malloced pointer, or 0 on error condition.
* caller must free!
*
****************************************************************************/
static FAR char *stringexpr(void)
{
FAR char *left;
FAR char *right;
FAR char *temp;
switch (g_token)
{
case DIMSTRID:
left = mystrdup(stringdimvar());
break;
case STRID:
left = mystrdup(stringvar());
break;
case QUOTE:
left = stringliteral();
break;
case CHRSTRING:
left = chrstring();
break;
case STRSTRING:
left = strstring();
break;
case LEFTSTRING:
left = leftstring();
break;
case RIGHTSTRING:
left = rightstring();
break;
case MIDSTRING:
left = midstring();
break;
case STRINGSTRING:
left = stringstring();
break;
default:
if (!isstring(g_token))
{
seterror(ERR_TYPEMISMATCH);
}
else
{
seterror(ERR_SYNTAX);
}
return mystrdup("");
}
if (!left)
{
seterror(ERR_OUTOFMEMORY);
return 0;
}
switch (g_token)
{
case PLUS:
match(PLUS);
right = stringexpr();
if (right)
{
temp = mystrconcat(left, right);
free(right);
if (temp)
{
free(left);
left = temp;
}
else
{
seterror(ERR_OUTOFMEMORY);
}
}
else
{
seterror(ERR_OUTOFMEMORY);
}
break;
default:
return left;
}
return left;
}
/****************************************************************************
* Name: chrstring
*
* Description:
* Parse the CHR$ token
*
****************************************************************************/
static FAR char *chrstring(void)
{
double x;
FAR char *answer;
match(CHRSTRING);
match(OPAREN);
x = integer(expr());
match(CPAREN);
g_iobuffer[0] = (char)x;
g_iobuffer[1] = 0;
answer = mystrdup(g_iobuffer);
if (!answer)
{
seterror(ERR_OUTOFMEMORY);
}
return answer;
}
/****************************************************************************
* Name: strstring
*
* Description:
* Parse the STR$ token
*
****************************************************************************/
static FAR char *strstring(void)
{
double x;
FAR char *answer;
match(STRSTRING);
match(OPAREN);
x = expr();
match(CPAREN);
snprintf(g_iobuffer, sizeof(g_iobuffer), "%g", x);
answer = mystrdup(g_iobuffer);
if (!answer)
{
seterror(ERR_OUTOFMEMORY);
}
return answer;
}
/****************************************************************************
* Name: leftstring
*
* Description:
* Parse the LEFT$ token
*
****************************************************************************/
static FAR char *leftstring(void)
{
FAR char *str;
int x;
FAR char *answer;
match(LEFTSTRING);
match(OPAREN);
str = stringexpr();
if (!str)
{
return 0;
}
match(COMMA);
x = integer(expr());
match(CPAREN);
if (x > (int)strlen(str))
{
return str;
}
if (x < 0)
{
seterror(ERR_ILLEGALOFFSET);
return str;
}
str[x] = 0;
answer = mystrdup(str);
free(str);
if (!answer)
{
seterror(ERR_OUTOFMEMORY);
}
return answer;
}
/****************************************************************************
* Name: rightstring
*
* Description:
* Parse the RIGHT$ token
*
****************************************************************************/
static FAR char *rightstring(void)
{
int x;
FAR char *str;
FAR char *answer;
match(RIGHTSTRING);
match(OPAREN);
str = stringexpr();
if (!str)
{
return 0;
}
match(COMMA);
x = integer(expr());
match(CPAREN);
if (x > (int)strlen(str))
{
return str;
}
if (x < 0)
{
seterror(ERR_ILLEGALOFFSET);
return str;
}
answer = mystrdup(&str[strlen(str) - x]);
free(str);
if (!answer)
{
seterror(ERR_OUTOFMEMORY);
}
return answer;
}
/****************************************************************************
* Name: midstring
*
* Description:
* Parse the MID$ token
*
****************************************************************************/
static FAR char *midstring(void)
{
FAR char *str;
int x;
int len;
FAR char *answer;
FAR char *temp;
match(MIDSTRING);
match(OPAREN);
str = stringexpr();
match(COMMA);
x = integer(expr());
match(COMMA);
len = integer(expr());
match(CPAREN);
if (!str)
{
return 0;
}
if (len == -1)
{
len = strlen(str) - x + 1;
}
if (x > (int)strlen(str) || len < 1)
{
free(str);
answer = mystrdup("");
if (!answer)
{
seterror(ERR_OUTOFMEMORY);
}
return answer;
}
if (x < 1.0)
{
seterror(ERR_ILLEGALOFFSET);
return str;
}
temp = &str[x - 1];
answer = malloc(len + 1);
if (!answer)
{
seterror(ERR_OUTOFMEMORY);
return str;
}
strlcpy(answer, temp, len + 1);
free(str);
return answer;
}
/****************************************************************************
* Name: stringstring
*
* Description:
* Parse the string$ token
*
****************************************************************************/
static FAR char *stringstring(void)
{
int x;
FAR char *str;
FAR char *answer;
int len;
int N;
int i;
match(STRINGSTRING);
match(OPAREN);
x = integer(expr());
match(COMMA);
str = stringexpr();
match(CPAREN);
if (!str)
{
return 0;
}
N = x;
if (N < 1)
{
free(str);
answer = mystrdup("");
if (!answer)
{
seterror(ERR_OUTOFMEMORY);
}
return answer;
}
len = strlen(str);
answer = malloc(N * len + 1);
if (!answer)
{
free(str);
seterror(ERR_OUTOFMEMORY);
return 0;
}
for (i = 0; i < N; i++)
{
strlcpy(answer + len * i, str, (N - i) * len + 1);
}
free(str);
return answer;
}
/****************************************************************************
* Name: stringdimvar
*
* Description:
* Read a dimensioned string variable from input.
* Returns: pointer to string (not malloced)
*
****************************************************************************/
static FAR char *stringdimvar(void)
{
char id[32];
int len;
FAR struct mb_dimvar_s *dimvar;
FAR char **answer = NULL;
int index[5];
getid(g_string, id, &len);
match(DIMSTRID);
dimvar = finddimvar(id);
if (dimvar)
{
switch (dimvar->ndims)
{
case 1:
index[0] = integer(expr());
answer = getdimvar(dimvar, index[0]);
break;
case 2:
index[0] = integer(expr());
match(COMMA);
index[1] = integer(expr());
answer = getdimvar(dimvar, index[0], index[1]);
break;
case 3:
index[0] = integer(expr());
match(COMMA);
index[1] = integer(expr());
match(COMMA);
index[2] = integer(expr());
answer = getdimvar(dimvar, index[0], index[1], index[2]);
break;
case 4:
index[0] = integer(expr());
match(COMMA);
index[1] = integer(expr());
match(COMMA);
index[2] = integer(expr());
match(COMMA);
index[3] = integer(expr());
answer = getdimvar(dimvar, index[0], index[1], index[2], index[3]);
break;
case 5:
index[0] = integer(expr());
match(COMMA);
index[1] = integer(expr());
match(COMMA);
index[2] = integer(expr());
match(COMMA);
index[3] = integer(expr());
match(COMMA);
index[4] = integer(expr());
answer =
getdimvar(dimvar, index[0], index[1],
index[2], index[3], index[4]);
break;
}
match(CPAREN);
}
else
{
seterror(ERR_NOSUCHVARIABLE);
}
if (!g_errorflag)
{
if (answer != NULL && *answer != NULL)
{
return *answer;
}
}
return "";
}
/****************************************************************************
* Name: stringvar
*
* Description:
* Parse a string variable.
* Returns: pointer to string (not malloced)
*
****************************************************************************/
static FAR char *stringvar(void)
{
char id[32];
int len;
FAR struct mb_variable_s *var;
getid(g_string, id, &len);
match(STRID);
var = findvariable(id);
if (var)
{
if (var->sval)
{
return var->sval;
}
return "";
}
seterror(ERR_NOSUCHVARIABLE);
return "";
}
/****************************************************************************
* Name: stringliteral
*
* Description:
* Parse a string literal
* Returns: malloced string literal
* Notes: newlines aren't allowed in literals, but blind
* concatenation across newlines is.
*
****************************************************************************/
static FAR char *stringliteral(void)
{
int len = 1;
FAR char *answer = 0;
FAR char *temp;
FAR char *substr;
FAR char *end;
while (g_token == QUOTE)
{
while (isspace(*g_string))
{
g_string++;
}
end = mystrend(g_string, '"');
if (end)
{
len = end - g_string;
substr = malloc(len);
if (!substr)
{
seterror(ERR_OUTOFMEMORY);
return answer;
}
mystrgrablit(substr, g_string);
if (answer)
{
temp = mystrconcat(answer, substr);
free(substr);
free(answer);
answer = temp;
if (!answer)
{
seterror(ERR_OUTOFMEMORY);
return answer;
}
}
else
{
answer = substr;
}
g_string = end;
}
else
{
seterror(ERR_SYNTAX);
return answer;
}
match(QUOTE);
}
return answer;
}
/****************************************************************************
* Name: integer
*
* Description:
* Cast a double to an integer, triggering errors if out of range
*
****************************************************************************/
static int integer(double x)
{
if (x < INT_MIN || x > INT_MAX)
{
seterror(ERR_BADVALUE);
}
if (x != floor(x))
{
seterror(ERR_NOTINT);
}
return (int)x;
}
/****************************************************************************
* Name: match
*
* Description:
* Check that we have a token of the passed type (if not set g_errorflag)
* Move parser on to next token. Sets token and string.
*
****************************************************************************/
static void match(int tok)
{
if (g_token != tok)
{
seterror(ERR_SYNTAX);
return;
}
while (isspace(*g_string))
{
g_string++;
}
g_string += tokenlen(g_string, g_token);
g_token = gettoken(g_string);
if (g_token == SYNTAX_ERROR)
{
seterror(ERR_SYNTAX);
}
}
/****************************************************************************
* Name: seterror
*
* Description:
* Set the errorflag.
* Params: errorcode - the error.
* Notes: ignores error cascades
*
****************************************************************************/
static void seterror(int errorcode)
{
if (g_errorflag == 0 || errorcode == 0)
{
g_errorflag = errorcode;
}
}
/****************************************************************************
* Name: getnextline
*
* Description:
* Get the next line number
* Params: str - pointer to parse string
* Returns: line no of next line, 0 if end
* Notes: goes to newline, then finds
* first line starting with a digit.
*
****************************************************************************/
static int getnextline(FAR const char *str)
{
while (*str)
{
while (*str && *str != '\n')
{
str++;
}
if (*str == 0)
{
return 0;
}
str++;
if (isdigit(*str))
{
return atoi(str);
}
}
return 0;
}
/****************************************************************************
* Name: gettoken
*
* Description:
* Get a token from the string
* Params: str - string to read token from
* Notes: ignores white space between tokens
*
****************************************************************************/
static int gettoken(FAR const char *str)
{
while (isspace(*str))
{
str++;
}
if (isdigit(*str))
{
return VALUE;
}
switch (*str)
{
case 0:
return EOS;
case '\n':
return EOL;
case '/':
return DIV;
case '*':
return MULT;
case '(':
return OPAREN;
case ')':
return CPAREN;
case '+':
return PLUS;
case '-':
return MINUS;
case '!':
return SHRIEK;
case ',':
return COMMA;
case ';':
return SEMICOLON;
case '"':
return QUOTE;
case '=':
return EQUALS;
case '<':
return LESS;
case '>':
return GREATER;
default:
if (!strncmp(str, "e", 1) && !isalnum(str[1]))
{
return E;
}
if (isupper(*str))
{
if (!strncmp(str, "SIN", 3) && !isalnum(str[3]))
{
return SIN;
}
if (!strncmp(str, "COS", 3) && !isalnum(str[3]))
{
return COS;
}
if (!strncmp(str, "TAN", 3) && !isalnum(str[3]))
{
return TAN;
}
if (!strncmp(str, "LN", 2) && !isalnum(str[2]))
{
return LN;
}
if (!strncmp(str, "POW", 3) && !isalnum(str[3]))
{
return POW;
}
if (!strncmp(str, "PI", 2) && !isalnum(str[2]))
{
return PI;
}
if (!strncmp(str, "SQRT", 4) && !isalnum(str[4]))
{
return SQRT;
}
if (!strncmp(str, "PRINT", 5) && !isalnum(str[5]))
{
return PRINT;
}
if (!strncmp(str, "LET", 3) && !isalnum(str[3]))
{
return LET;
}
if (!strncmp(str, "DIM", 3) && !isalnum(str[3]))
{
return DIM;
}
if (!strncmp(str, "IF", 2) && !isalnum(str[2]))
{
return IF;
}
if (!strncmp(str, "THEN", 4) && !isalnum(str[4]))
{
return THEN;
}
if (!strncmp(str, "AND", 3) && !isalnum(str[3]))
{
return AND;
}
if (!strncmp(str, "OR", 2) && !isalnum(str[2]))
{
return OR;
}
if (!strncmp(str, "GOTO", 4) && !isalnum(str[4]))
{
return GOTO;
}
if (!strncmp(str, "INPUT", 5) && !isalnum(str[5]))
{
return INPUT;
}
if (!strncmp(str, "REM", 3) && !isalnum(str[3]))
{
return REM;
}
if (!strncmp(str, "FOR", 3) && !isalnum(str[3]))
{
return FOR;
}
if (!strncmp(str, "TO", 2) && !isalnum(str[2]))
{
return TO;
}
if (!strncmp(str, "NEXT", 4) && !isalnum(str[4]))
{
return NEXT;
}
if (!strncmp(str, "STEP", 4) && !isalnum(str[4]))
{
return STEP;
}
if (!strncmp(str, "MOD", 3) && !isalnum(str[3]))
{
return MOD;
}
if (!strncmp(str, "ABS", 3) && !isalnum(str[3]))
{
return ABS;
}
if (!strncmp(str, "LEN", 3) && !isalnum(str[3]))
{
return LEN;
}
if (!strncmp(str, "ASCII", 5) && !isalnum(str[5]))
{
return ASCII;
}
if (!strncmp(str, "ASIN", 4) && !isalnum(str[4]))
{
return ASIN;
}
if (!strncmp(str, "ACOS", 4) && !isalnum(str[4]))
{
return ACOS;
}
if (!strncmp(str, "ATAN", 4) && !isalnum(str[4]))
{
return ATAN;
}
if (!strncmp(str, "INT", 3) && !isalnum(str[3]))
{
return INT;
}
if (!strncmp(str, "RND", 3) && !isalnum(str[3]))
{
return RND;
}
if (!strncmp(str, "VAL", 3) && !isalnum(str[3]))
{
return VAL;
}
if (!strncmp(str, "VALLEN", 6) && !isalnum(str[6]))
{
return VALLEN;
}
if (!strncmp(str, "INSTR", 5) && !isalnum(str[5]))
{
return INSTR;
}
if (!strncmp(str, "CHR$", 4))
{
return CHRSTRING;
}
if (!strncmp(str, "STR$", 4))
{
return STRSTRING;
}
if (!strncmp(str, "LEFT$", 5))
{
return LEFTSTRING;
}
if (!strncmp(str, "RIGHT$", 6))
{
return RIGHTSTRING;
}
if (!strncmp(str, "MID$", 4))
{
return MIDSTRING;
}
if (!strncmp(str, "STRING$", 7))
{
return STRINGSTRING;
}
}
/* end isupper() */
if (isalpha(*str))
{
while (isalnum(*str))
{
str++;
}
switch (*str)
{
case '$':
return str[1] == '(' ? DIMSTRID : STRID;
case '(':
return DIMFLTID;
default:
return FLTID;
}
}
return SYNTAX_ERROR;
}
}
/****************************************************************************
* Name: tokenlen
*
* Description:
* Get the length of a token.
* Params: str - pointer to the string containing the token
* token - the type of the token read
* Returns: length of the token, or 0 for EOL to prevent
* it being read past.
*
****************************************************************************/
static int tokenlen(FAR const char *str, int tokenid)
{
int len = 0;
switch (tokenid)
{
case EOS:
return 0;
case EOL:
return 1;
case VALUE:
getvalue(str, &len);
return len;
case DIMSTRID:
case DIMFLTID:
case STRID:
getid(str, g_iobuffer, &len);
return len;
case FLTID:
getid(str, g_iobuffer, &len);
return len;
case PI:
return 2;
case E:
return 1;
case SIN:
return 3;
case COS:
return 3;
case TAN:
return 3;
case LN:
return 2;
case POW:
return 3;
case SQRT:
return 4;
case DIV:
return 1;
case MULT:
return 1;
case OPAREN:
return 1;
case CPAREN:
return 1;
case PLUS:
return 1;
case MINUS:
return 1;
case SHRIEK:
return 1;
case COMMA:
return 1;
case QUOTE:
return 1;
case EQUALS:
return 1;
case LESS:
return 1;
case GREATER:
return 1;
case SEMICOLON:
return 1;
case SYNTAX_ERROR:
return 0;
case PRINT:
return 5;
case LET:
return 3;
case DIM:
return 3;
case IF:
return 2;
case THEN:
return 4;
case AND:
return 3;
case OR:
return 2;
case GOTO:
return 4;
case INPUT:
return 5;
case REM:
return 3;
case FOR:
return 3;
case TO:
return 2;
case NEXT:
return 4;
case STEP:
return 4;
case MOD:
return 3;
case ABS:
return 3;
case LEN:
return 3;
case ASCII:
return 5;
case ASIN:
return 4;
case ACOS:
return 4;
case ATAN:
return 4;
case INT:
return 3;
case RND:
return 3;
case VAL:
return 3;
case VALLEN:
return 6;
case INSTR:
return 5;
case CHRSTRING:
return 4;
case STRSTRING:
return 4;
case LEFTSTRING:
return 5;
case RIGHTSTRING:
return 6;
case MIDSTRING:
return 4;
case STRINGSTRING:
return 7;
default:
assert(0);
return 0;
}
}
/****************************************************************************
* Name: isstring
*
* Description:
* Test if a token represents a string expression
* Params: token - token to test
* Returns: 1 if a string, else 0
*
****************************************************************************/
static int isstring(int tokenid)
{
if (tokenid == STRID || tokenid == QUOTE || tokenid == DIMSTRID
|| tokenid == CHRSTRING || tokenid == STRSTRING
|| tokenid == LEFTSTRING || tokenid == RIGHTSTRING
|| tokenid == MIDSTRING || tokenid == STRINGSTRING)
{
return 1;
}
return 0;
}
/****************************************************************************
* Name: getvalue
*
* Description:
* Get a numerical value from the parse string
* Params: str - the string to search
* len - return pinter for no chars read
* Returns: the value of the string.
*
****************************************************************************/
static double getvalue(FAR const char *str, FAR int *len)
{
double answer;
FAR char *end;
answer = strtod(str, &end);
assert(end != str);
*len = end - str;
return answer;
}
/****************************************************************************
* Name: getid
*
* Description:
* Get an id from the parse string:
* Params: str - string to search
* out - id output [32 chars max ]
* len - return pointer for id length
* Notes: triggers an error if id > 31 chars
* the id includes the $ and ( qualifiers.
*
****************************************************************************/
static void getid(FAR const char *str, FAR char *out, FAR int *len)
{
int nread = 0;
while (isspace(*str))
{
str++;
}
assert(isalpha(*str));
while (isalnum(*str))
{
if (nread < 31)
{
out[nread++] = *str++;
}
else
{
seterror(ERR_IDTOOLONG);
break;
}
}
if (*str == '$')
{
if (nread < 31)
{
out[nread++] = *str++;
}
else
{
seterror(ERR_IDTOOLONG);
}
}
if (*str == '(')
{
if (nread < 31)
{
out[nread++] = *str++;
}
else
{
seterror(ERR_IDTOOLONG);
}
}
out[nread] = 0;
*len = nread;
}
/****************************************************************************
* Name: mystrgrablit
*
* Description:
* Grab a literal from the parse string.
* Params: dest - destination string
* src - source string
* Notes: strings are in quotes, double quotes the escape
*
****************************************************************************/
static void mystrgrablit(FAR char *dest, FAR const char *src)
{
assert(*src == '"');
src++;
while (*src)
{
if (*src == '"')
{
if (src[1] == '"')
{
*dest++ = *src;
src++;
src++;
}
else
{
break;
}
}
else
{
*dest++ = *src++;
}
}
*dest++ = 0;
}
/****************************************************************************
* Name: mystrend
*
* Description:
* Find where a source string literal ends
* Params: src - string to check (must point to quote)
* quote - character to use for quotation
* Returns: pointer to quote which ends string
* Notes: quotes escape quotes
*
****************************************************************************/
static FAR char *mystrend(FAR const char *str, char quote)
{
assert(*str == quote);
str++;
while (*str)
{
while (*str != quote)
{
if (*str == '\n' || *str == 0)
{
return 0;
}
str++;
}
if (str[1] == quote)
{
str += 2;
}
else
{
break;
}
}
return (char *)(*str ? str : 0);
}
/****************************************************************************
* Name: mystrcount
*
* Description:
* Count the instances of ch in str
* Params: str - string to check
* ch - character to count
* Returns: no time chs occurs in str.
*
****************************************************************************/
static int mystrcount(FAR const char *str, char ch)
{
int answer = 0;
while (*str)
{
if (*str++ == ch)
{
answer++;
}
}
return answer;
}
/****************************************************************************
* Name: mystrdup
*
* Description:
* Duplicate a string:
* Params: str - string to duplicate
* Returns: malloced duplicate.
*
****************************************************************************/
static FAR char *mystrdup(FAR const char *str)
{
return strdup(str);
}
/****************************************************************************
* Name: mystrconcat
*
* Description:
* Concatenate two strings
* Params: str - firsts string
* cat - second string
* Returns: malloced string.
*
****************************************************************************/
static FAR char *mystrconcat(FAR const char *str, FAR const char *cat)
{
int len;
FAR char *answer;
len = strlen(str) + strlen(cat) + 1;
answer = malloc(len);
if (answer)
{
strlcpy(answer, str, len);
strlcat(answer, cat, len);
}
return answer;
}
/****************************************************************************
* Name: factorial
*
* Description:
* Compute x!
*
****************************************************************************/
static double factorial(double x)
{
double answer = 1.0;
double t;
if (x > 1000.0)
{
x = 1000.0;
}
for (t = 1; t <= x; t += 1.0)
{
answer *= t;
}
return answer;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: basic
*
* Description:
* Interpret a BASIC script
*
* Input Parameters:
* script - the script to run
* in - input stream
* out - output stream
* err - error stream
*
* Returned Value:
* Returns: 0 on success, 1 on error condition.
*
****************************************************************************/
int basic(FAR const char *script, FILE * in, FILE * out, FILE * err)
{
int curline = 0;
int nextline;
int answer = 0;
g_fpin = in;
g_fpout = out;
g_fperr = err;
if (setup(script) == -1)
{
return 1;
}
while (curline != -1)
{
g_string = g_lines[curline].str;
g_token = gettoken(g_string);
g_errorflag = 0;
nextline = line();
if (g_errorflag)
{
reporterror(g_lines[curline].no);
answer = 1;
break;
}
if (nextline == -1)
{
break;
}
if (nextline == 0)
{
curline++;
if (curline == nlines)
break;
}
else
{
curline = findline(nextline);
if (curline == -1)
{
if (g_fperr)
{
fprintf(g_fperr, "line %d not found\n", nextline);
}
answer = 1;
break;
}
}
}
cleanup();
return answer;
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/haloos/vcos_apps.git
git@gitee.com:haloos/vcos_apps.git
haloos
vcos_apps
vcos_apps
master

搜索帮助