home *** CD-ROM | disk | FTP | other *** search
- OPT MODULE,LARGE,PREPROCESS
-
- MODULE 'amigalib/lists',
- 'dos/dos',
- 'exec/lists','exec/memory','exec/nodes','exec/ports','exec/semaphores','exec/tasks',
- 'graphics/rastport',->'cybergraphics','picasso96api',
- '*varlist'
-
- MODULE 'tools/debug' -> kputfmt('',[])
-
- #define pixel(raw,w,x,y) raw[x+(y*w)]
- -> Can't we export a #define?
-
- /* Some stuff for picFX... I was forced to put it here, as I couldn't reference the main executable when needing them */
-
- EXPORT OBJECT subtaskmsg
- stm_Message:mn
- stm_Command:INT
- stm_Parameter:LONG
- stm_Result:LONG
- ENDOBJECT
-
- EXPORT OBJECT subtask
- st_Task:PTR TO tc /* sub task pointer */
- st_Port:PTR TO mp /* allocated by sub task */
- st_Reply:PTR TO mp /* allocated by main task */
- st_Data:LONG /* more initial data to pass to the sub task */
- st_Message:subtaskmsg /* Message buffer */
- ENDOBJECT
-
-
- EXPORT OBJECT planeFunc_data
- projectid -> Project ID, used when referencing a project from "outside"
- modified:CHAR -> if the project had been modified after last save
-
- /***attributes storage***/
- bfunc:PTR TO expression
- bstr:PTR TO CHAR
- failure /*$RGB*/
- gfunc:PTR TO expression
- gstr:PTR TO CHAR
- height
- imagefile:PTR TO CHAR -> eg 'picture."2:t"'
- imagefilename:PTR TO CHAR-> eg 'picture.06'
- left,newleft ->scroll when newleft is non-zero
- loading
- loadm
- lock -> -1 when there's a writelock, 0 when it is free, number of readlocks otherwise
- name:PTR TO CHAR
- paused -> this is used by the 'state' attribute, with the 'lock' var
- ratio -> scale ratio to which display the picture, multiplied by one million.
- rfunc:PTR TO expression
- rstr:PTR TO CHAR
- outputr,outputg,outputb
- quiet
- top,newtop -> scroll when newtop is non-zero
- type
- width
- xmin,xmax,ymin,ymax -> area to draw to
- /***some pointers...***/
- hscroll,vscroll -> scrollers of the window
- app -> true if we can send an update message.
- self -> pointer to ourselves
- win -> pointer to our window object
- /***some useful data***/
- savepixel -> true if the previous pixel must be saved
- rupd -> copy of the render-update preference variable.
- sema:ss -> data item protection
- subtask:PTR TO subtask -> our sub task
-
- drawhandle -> draw handle
- imagedata:PTR TO LONG,vec-> pixel information for the picture. vec is TRUE if we did allocate it with AllocVec()
- picture -> picture
-
- drawn -> the last line that has been drawn to the window
- calculated -> the last line that has been calculated by the subtask
- ds:datestamp -> planeFunc stores the datestamp when a calculation is started
- ENDOBJECT
-
- EXPORT ENUM OUT_Integer=0, -> 32bits integer
- OUT_Float32, -> 32Bits float
- OUT_Float64, -> 64Bits float
- OUT_OldR,OUT_OldG,OUT_OldB, -> Components of the pixel (previous calculation!)
- OUT_CopyR,OUT_CopyG -> Copies the new expression (e.g. black'n'white)
-
- /* Function class. This class handles the functions like sin, +, r(), and so on, the old function class has been renamed to expression.
- You can easily add functions, just put the evaluation code somewhere (better is to keep the order !) and then put it in initfuncs, in
- the same way as the other.*/
-
- OBJECT function
- ln:ln
- argcount:LONG
- readpid -> if TRUE: cte::projectid ->-> data
- evalI,evalF:LONG -> address of the evaluating procedures
- ENDOBJECT
- /* For compatibility with previous versions, a function having a constant will
- be read as f(cte,arg1,arg2), and not f(arg1,arg2,cte), as you might think*/
-
- EXPORT DEF fconstant,fvariable, -> The addresses of these two function nodes (!FUNCTION OBJECTS!)
- firstb,lastb:PTR TO ln -> first & last x_y . (!LN OBJECTS!)
-
- DEF funclist:PTR TO lh,
- gtd,-> gtd is the address of the getdata(dat,num) PROC
- dat,-> dat is the address of the ProjectlistObject's data
- vlo -> vlo is the current VariableListObject
-
- DEF c,p,s -> c,p = number of used A5, respectively by calc and precalc; s is used A1.
-
- DEF count,mc,bs, -> precompilation stuff mc stands for max-count, bs for buffer-size
- code:PTR TO INT,crs:PTR TO INT, -> code is the beginning, crs is the point we are at.
- precalc:PTR TO INT,prs:PTR TO INT,
- buffer -> *temporary* storage of the current buffer (*copy* of self.buffer, the address)
-
- PROC create(name,argcount,evalI,evalF) OF function
- self.ln.name:=String(StrLen(name))
- StrCopy(self.ln.name,name)
- self.argcount:=argcount
- self.evalI:=evalI
- self.evalF:=evalF
- ENDPROC
-
- PROC end() OF function
- DisposeLink(self.ln.name)
- ENDPROC
-
- EXPORT PROC initfuncs(gtda,data,varlst) -> getData(), projectList_data, VarListObject
- DEF thatfunc:PTR TO function
-
- IF gtd = gtda THEN RETURN -> We had already been called
-
- gtd:=gtda
- dat:=data
- vlo:=varlst
-
- NEW funclist
- newList(funclist)
-
- NEW thatfunc.create('Constant',0,{e_constant},{e_constant})
- AddTail(funclist,thatfunc.ln)
- fconstant:=thatfunc
- NEW thatfunc.create('Variable',0,{e_variable},{e_variable})
- AddTail(funclist,thatfunc.ln)
- fvariable:=thatfunc
-
- /*Following functions are sorted by order of priority*/
-
- NEW thatfunc.create('%',2,{e_mod},{f_mod})
- AddTail(funclist,thatfunc.ln)
- firstb:=thatfunc.ln -> This is the first x_y style operator
-
- NEW thatfunc.create('+',2,{e_add},{f_add})
- AddTail(funclist,thatfunc.ln)
-
- NEW thatfunc.create('-',2,{e_sub},{f_sub})
- AddTail(funclist,thatfunc.ln)
-
- NEW thatfunc.create('*',2,{e_mul},{f_mul})
- AddTail(funclist,thatfunc.ln)
-
- NEW thatfunc.create('/',2,{e_div},{f_div})
- AddTail(funclist,thatfunc.ln)
-
- NEW thatfunc.create('^',2,{e_pow},{f_pow})
- AddTail(funclist,thatfunc.ln)
- lastb:=thatfunc.ln -> this is the last x_y style operator
-
- NEW thatfunc.create('abs',1,{e_abs},{f_abs})
- AddTail(funclist,thatfunc.ln)
-
- NEW thatfunc.create('neg',1,{e_neg},{f_neg}) -> '-a' is possible but slower than 'neg(a)', because interpreted as '0-a'
- AddTail(funclist,thatfunc.ln)
-
- NEW thatfunc.create('cos',1,{e_constant},{f_cos}) -> return zero for int32 :-)
- AddTail(funclist,thatfunc.ln)
-
- NEW thatfunc.create('sin',1,{e_constant},{f_sin})
- AddTail(funclist,thatfunc.ln)
-
- NEW thatfunc.create('tan',1,{e_constant},{f_tan})
- AddTail(funclist,thatfunc.ln)
-
- NEW thatfunc.create('acos',1,{e_constant},{f_acos})
- AddTail(funclist,thatfunc.ln)
-
- NEW thatfunc.create('asin',1,{e_constant},{f_asin})
- AddTail(funclist,thatfunc.ln)
-
- NEW thatfunc.create('atan',1,{e_constant},{f_atan})
- AddTail(funclist,thatfunc.ln)
-
- NEW thatfunc.create('angle',2,{e_constant},{f_angle})
- AddTail(funclist,thatfunc.ln)
-
- NEW thatfunc.create('min',2,{e_min},{f_min})
- AddTail(funclist,thatfunc.ln)
-
- NEW thatfunc.create('max',2,{e_max},{f_max})
- AddTail(funclist,thatfunc.ln)
-
- NEW thatfunc.create('sqrt',1,{e_sqrt},{f_sqrt})
- AddTail(funclist,thatfunc.ln)
-
- NEW thatfunc.create('ln',1,{e_ln},{f_ln})
- AddTail(funclist,thatfunc.ln)
-
- NEW thatfunc.create('log',2,{e_log},{f_log})
- AddTail(funclist,thatfunc.ln)
-
- NEW thatfunc.create('cosh',1,{e_constant},{f_cosh}) -> maybe later, approximated int value?
- AddTail(funclist,thatfunc.ln)
-
- NEW thatfunc.create('sinh',1,{e_constant},{f_sinh})
- AddTail(funclist,thatfunc.ln)
-
- NEW thatfunc.create('tanh',1,{e_constant},{f_tanh})
- AddTail(funclist,thatfunc.ln)
-
- NEW thatfunc.create('acosh',1,{e_constant},{e_constant})->,{f_acosh})
- AddTail(funclist,thatfunc.ln)
-
- NEW thatfunc.create('asinh',1,{e_constant},{e_constant})->,{f_asinh})
- AddTail(funclist,thatfunc.ln)
-
- NEW thatfunc.create('atanh',1,{e_constant},{e_constant})->,{f_atanh})
- AddTail(funclist,thatfunc.ln)
-
- NEW thatfunc.create('r',3,{e_red},{f_red})
- thatfunc.readpid:=TRUE
- AddTail(funclist,thatfunc.ln)
- NEW thatfunc.create('g',3,{e_green},{f_green})
- thatfunc.readpid:=TRUE
- AddTail(funclist,thatfunc.ln)
- NEW thatfunc.create('b',3,{e_blue},{f_blue})
- thatfunc.readpid:=TRUE
- AddTail(funclist,thatfunc.ln)
- ENDPROC
-
- EXPORT PROC cleanfuncs()
- DEF thisnode:PTR TO ln,nextone
-
- thisnode:=funclist.head
- WHILE (nextone:=thisnode.succ) AND Not(CtrlC()) -> Destroy all functions...
- DisposeLink(thisnode.name)
- END thisnode;thisnode:=nextone
- ENDWHILE
- END funclist
- ENDPROC
-
- /* I am required to have the three arguments, so I cannot get rid of the unreferenced messages.*/
-
- PROC e_constant(x,y,c) IS c
-
- ENUM VAR_x,VAR_y
- PROC e_variable(x,y,c)
- IF c=VAR_x THEN RETURN x
- ENDPROC y
- /*PROC f_variable(x,y,c) -> Test: Let's use the above one instead and have picFX convert the vars...
- IF c=VAR_x THEN RETURN x!
- ENDPROC y!
- */
- EXPORT PROC e_mod(x,y,c=0) -> This is also used in picFX as a kind of replacement to Mod()
- IF y = 0; RETURN 0
- ELSEIF x >= 0; RETURN Mod(x,y)
- ENDIF
- ENDPROC Mod(x,y)+y
- PROC f_mod(x,y,c)
- IF y = 0. THEN RETURN 0.
- ENDPROC !x-(!Ffloor(!x/y)*y)
-
- PROC e_add(x,y,c) IS x+y
- PROC f_add(x,y,c) IS !x+y
-
- PROC e_sub(x,y,c) IS x-y
- PROC f_sub(x,y,c) IS !x-y
-
- PROC e_mul(x,y,c) IS Mul(x,y)
- PROC f_mul(x,y,c) IS !x*y
-
- PROC e_div(x,y,c)
- IF y = 0 THEN RETURN 123456 ELSE RETURN Div(x,y)
- ENDPROC
-
- PROC f_div(x,y,c)
- IF y = 0. THEN RETURN 123456. ELSE RETURN !x/y
- ENDPROC
-
- PROC e_pow(x,y,c) -> maybe would be quicker to convert to float, power, and back to int again?
- DEF result
- IF y = 0 THEN RETURN 1
- result:=x
- WHILE y > 1
- result:=Mul(result,x)
- y--
- ENDWHILE
- ENDPROC result
- PROC f_pow(x,y,c) IS Fpow(y,x)
-
- PROC e_abs(x,y,c) IS Abs(x)
- PROC f_abs(x,y,c) IS Fabs(x)
-
- PROC e_neg(x,y,c) IS -x
- PROC f_neg(x,y,c) IS !-x
-
- PROC f_sin(x,y,c) IS Fsin(x)
- PROC f_cos(x,y,c) IS Fcos(x)
- PROC f_tan(x,y,c) IS Ftan(x) -> I don't know if we can pass pi/2 to this function. But as it is approximated, it shouldn't cause problems...
- PROC f_asin(x,y,c) IS Fasin(x)
- PROC f_acos(x,y,c) IS Facos(x)
- PROC f_atan(x,y,c) IS Fatan(x)
-
- PROC f_angle(x,y,c)
- IF y=0.
- IF x<0. THEN RETURN 3.14159265 ELSE RETURN 0.
- ELSEIF !y<0
- RETURN !Fatan(!x/y)+1.5707963
- ENDIF
- ENDPROC !Fatan(!x/y)-1.5707963
-
- PROC e_min(x,y,c) IS Min(x,y)
- PROC f_min(x,y,c)
- IF !x>y THEN RETURN y ELSE RETURN x
- ENDPROC
-
- PROC e_max(x,y,c) IS Max(x,y)
- PROC f_max(x,y,c)
- IF !x<y THEN RETURN y ELSE RETURN x
- ENDPROC
-
- PROC e_sqrt(x,y,c) IS !Fsqrt(x!)!
- PROC f_sqrt(x,y,c) IS Fsqrt(x)
-
- PROC e_ln(x,y,c)
- IF x <= 0 THEN RETURN 123456 ELSE RETURN !Flog(x!)!
- ENDPROC
- PROC f_ln(x,y,c)
- IF x<=0 THEN RETURN 123456. ELSE RETURN Flog(x)
- ENDPROC
-
- PROC e_log(x,y,c) -> All these tests are annoying, but I do not know how to avoid them...
- IF (x<=0) OR (y<=0) OR (y=1) THEN RETURN 123456 ELSE RETURN !Flog(x!)/Flog(y!)!
- ENDPROC
- PROC f_log(x,y,c)
- IF (x<=0.) OR (y<=0.) OR (y=1. ) THEN RETURN 123456. ELSE RETURN !Flog(x)/Flog(y)
- ENDPROC
-
- PROC f_sinh(x,y,c) IS !Fcosh(x)*Ftanh(x) -> Fsinh(x) -> I am doing something wrong somewhere, anyway putting fsinh causes a crash...
- PROC f_cosh(x,y,c) IS Fcosh(x)
- PROC f_tanh(x,y,c) IS Ftanh(x)
-
- /*PROC f_asinh(x,y,c) IS Fasinh(x) -> These three aren't implemented in E...
- PROC f_acosh(x,y,c) IS Facosh(x)
- PROC f_atanh(x,y,c) IS Fatanh(x)*/
-
- PROC e_red(x,y,c:PTR TO planeFunc_data) IS Shr(pixel(c.imagedata,c.width,e_mod(x,c.width),e_mod(y,c.height)),16)
- PROC f_red(x,y,c:PTR TO planeFunc_data) IS (Shr(pixel(c.imagedata,c.width,e_mod(!x!,c.width),e_mod(!y!,c.height)),16))!
-
- PROC e_green(x,y,c:PTR TO planeFunc_data) IS Shr(pixel(c.imagedata,c.width,e_mod(x,c.width),e_mod(y,c.height)),8) AND $FF
- PROC f_green(x,y,c:PTR TO planeFunc_data) IS (Shr(pixel(c.imagedata,c.width,e_mod(!x!,c.width),e_mod(!y!,c.height)),8) AND $FF)!
-
- PROC e_blue(x,y,c:PTR TO planeFunc_data) IS pixel(c.imagedata,c.width,e_mod(x,c.width),e_mod(y,c.height)) AND $FF
- PROC f_blue(x,y,c:PTR TO planeFunc_data) IS (pixel(c.imagedata,c.width,e_mod(!x!,c.width),e_mod(!y!,c.height)) AND $FF)!
-
- /* Expression class. This is equivalent to the old function one. Decoding is now put in the constructor (=> a little bit less code ;)
- If there's a problem while decoding, the function will get f(x,y)=0*/
-
- EXPORT SET NEEDX,SHORT -> short is x,y,e,pi,numeric-constant, i.e. what does not need computation.
- EXPORT ENUM FAILURE=$100,ERR_NoParse,ERR_NoFunc,ERR_NoChar
- EXPORT SET WARN_NoSupport,WARN_EPi
-
- EXPORT OBJECT expression
- func:PTR TO function
- arg1:PTR TO expression
- arg2:PTR TO expression
- cte:LONG -> third arg. For reason of backward compatibility, it is the arg #1 in the expression string, when present.
-
- precision
- evaluate -> evaluate THIS proc.
-
- /*precalculation stuff*/
- /*following: allocated with AllocVec()!!!!*/
- precalc:PTR TO LONG -> pre-calculates. Values put in buffer (only in main expr)
- calculate:PTR TO LONG -> calculates function value (only in main expr)
- buffer:PTR TO LONG -> pre-calculated value (only in main expr)
-
- message -> how last decoding went: WARN_#? or ERR_#? or NIL
-
- need:LONG -> what vars are required to eval. it
- -> value:LONG -> precalculated value
- ENDOBJECT
-
- /*EXPORT OBJECT outinfo
- error:LONG
- quote:PTR TO CHAR
- ENDOBJECT*/
-
- PROC setfunc(address:PTR TO function) OF expression
- self.func:=address
- IF self.precision = OUT_Integer
- self.evaluate:=self.func.evalI
- ELSEIF self.precision = OUT_Float32
- self.evaluate:=self.func.evalF
- ELSE -> Actually this happens when using a non-direct output mode (copy, old,..?)
- -> WriteF('Unknown output mode\n')
- self.evaluate:=self.func.evalF -> (Just in case of problem, but it shouldn't be useful)
- ENDIF
- ENDPROC
-
- /* A Little But Serious change done here: start is the first char to decode, but end is the last plus one. (It made code a little simpler)*/
-
- /*first: TRUE means that the function will be compiled;
- FALSE means that it might throw an exception;
- 1 means that it will not be compiled neither throw an exception*/
- PROC create(precision,input:PTR TO CHAR,start=0,end=-1,first=TRUE) OF expression HANDLE
- DEF currfunc:PTR TO ln,name:PTR TO CHAR,var,
- open,close,nxt:PTR TO LONG,fnc,out=NIL ->:PTR TO outinfo
-
- self.precision:=precision
-
- IF end=-1
- end:=StrLen(input)
- mc:=0;bs:=0
- ENDIF
-
- IF start=end -> Empty expressions => constant zero
- self.setfunc(fconstant)
- self.cte:=0
- JUMP toEnd
- ENDIF
-
- IF input[start] = "(" -> If the whole expression is surrounded by brackets, decode inside.
- IF findseparator(input,start,')') = (end-1)
- self.create(precision,input,start+1,end-1,first)
- JUMP toEnd
- ENDIF
- ENDIF
-
- /* Let's seek x_y operators */
-
- currfunc:=firstb
- REPEAT
- nxt:=findseparator(input,start-1,currfunc.name)
- IF (nxt<>-1) AND (nxt<end)
- self.setfunc(currfunc-4) ->!!! There's a four-bytes gap between function and ln (because function is not simply an object: it's a class :-)
- NEW self.arg1.create(precision,input,start,nxt,FALSE)
- out:=out OR self.arg1.message -> Gather eventual warning..
- count++;mc:=Max(mc,count)
- NEW self.arg2.create(precision,input,nxt+1,end,FALSE)
- out:=out OR self.arg2.message
- self.need:=self.arg1.need OR self.arg2.need AND Not(SHORT)
- count--
- JUMP toEnd
- ENDIF
-
- currfunc:=currfunc.succ
- UNTIL (currfunc = lastb.succ) OR CtrlC()
- /* Now look for f() functions */
-
- open:=InStr(input,'(',start)
- IF (open=-1) OR (open >= end) -> No () in expression, let's treat it as a whole
- var:=getvariable(input+start,end-start,vlo) -> this is inside varlist.m
- IF var <> -1
- self.setfunc(fconstant)
- IF self.precision=OUT_Integer
- self.cte:=!var! -> If we are integer, then convert the flt32 into int32...
- ELSE
- self.cte:=var
- ENDIF
- self.need:=SHORT
- ELSEIF StrCmp(input+start,'x',1)
- self.setfunc(fvariable)
- self.cte:=VAR_x
- IF end<>(start+1) THEN Throw(ERR_NoParse,input)
- self.need:=NEEDX OR SHORT
- ELSEIF StrCmp(input+start,'y',1)
- self.setfunc(fvariable)
- self.cte:=VAR_y
- IF end<>(start+1) THEN Throw(ERR_NoParse,input)
- self.need:=SHORT
- ELSEIF StrCmp(input+start,'e',1)
- self.setfunc(fconstant)
- IF self.precision=OUT_Integer
- self.cte:=3
- out:=out OR WARN_EPi
- ELSE
- self.cte:=2.71828183
- ENDIF
- IF end<>(start+1) THEN Throw(ERR_NoParse,input)
- self.need:=SHORT
- ELSEIF StrCmp(input+start,'pi',2)
- self.setfunc(fconstant)
- IF self.precision = OUT_Integer
- self.cte:=3
- out:=out OR WARN_EPi
- ELSE
- self.cte:=3.14159265
- ENDIF
- IF end<>(start+2) THEN Throw(ERR_NoParse,input)
- self.need:=SHORT
- ELSE
- self.setfunc(fconstant)
- IF self.precision=OUT_Integer
- open,close:=Val(input+start)
- ELSE
- open,close:=RealVal(input+start)
- ENDIF
- self.cte:=open -> putting multiple return values in objects (x.y) is not accepted...
- IF close <> (end-start) THEN Throw(ERR_NoParse,input)
- self.need:=SHORT
- ENDIF
- ELSE
- IF open=start THEN -> THEN in cases like '(a)(b)', or '(a))'
- Throw(ERR_NoParse,input)
-
- name:=String(open-start)
- MidStr(name,input,start)
- fnc:=FindName(lastb.pred,name) -> .pred because abs must also be found
- IF fnc=NIL THEN Throw(ERR_NoFunc,name)
- self.setfunc(fnc-4)
- IF self.func.argcount>1
- close:=findseparator(input,open,',')
- IF (close=-1) OR (close>=end) THEN Throw(ERR_NoChar,',')
- IF self.func.argcount>2 -> In this case, read cte,arg1,arg2
-
- self.cte:=Val(input+open+1) -> Second return value: # of read chars. For error handling.
- IF self.func.readpid -> This is a project id
- self.cte:=gtd(dat,self.cte)
- ELSEIF self.precision=OUT_Float32 -> Not used for now, but may come once :-)
- self.cte:=RealVal(input+open)
- ENDIF
-
- open:=close
- close:=findseparator(input,open,',')
- IF (close=-1) OR (close>=end) THEN Throw(ERR_NoChar,',')
- NEW self.arg1.create(precision,input,open+1,close,FALSE)
- self.need:=self.arg1.need AND Not(SHORT)
- count++;mc:=Max(mc,count)
-
-
- open:=close
- close:=findseparator(input,open,')')
- IF (close=-1) OR (close>=end) THEN Throw(ERR_NoChar,')')
- NEW self.arg2.create(precision,input,open+1,close,FALSE)
- self.need:=self.need OR self.arg2.need AND Not(SHORT)
-
- count-- -> storage not needed anymore.
-
- ELSE -> two args
- NEW self.arg1.create(precision,input,open+1,close,FALSE)
- self.need:=self.arg1.need AND Not(SHORT)
- count++;mc:=Max(mc,count)
- open:=close
- close:=findseparator(input,open,')')
- IF (close=-1) OR (close>=end) THEN Throw(ERR_NoChar,')')
- NEW self.arg2.create(precision,input,open+1,close,FALSE)
- self.need:=self.need OR self.arg2.need AND Not(SHORT)
- count-- -> storage not needed anymore.
- ENDIF
- out:=out OR self.arg2.message
-
- ELSE -> Single arg
- close:=findseparator(input,open,')')
- IF (close=-1) OR (close>=end) THEN Throw(ERR_NoChar,')')
- NEW self.arg1.create(precision,input,open+1,close,FALSE)
- self.need:=self.arg1.need AND Not(SHORT)
- ENDIF
- out:=out OR self.arg1.message
- IF self.evaluate={e_constant} THEN -> I assume that if a function with args is constant, then there's a problem...
- out:=out OR WARN_NoSupport
- ENDIF
- toEnd:
- EXCEPT DO
- IF exception
- IF first=FALSE THEN Throw(exception,exceptioninfo)
- /*NEW out
- out.error:= exception;out.quote:=exceptioninfo*/
- out:=/*out OR */exception -> Once there will be some more error information sent...
- self.end()
- self.create(self.precision,'')
- ENDIF
- IF self.need AND NEEDX
- IF self.arg1 ->THEN
- IF (self.arg1.need AND NEEDX) = $0 THEN
- bs++
- ENDIF
- IF self.arg2 ->THEN
- IF (self.arg2.need AND NEEDX) = $0 THEN
- bs++
- ENDIF
- ELSEIF first -> x *never* used in whole expression: use one buffer slot.
- bs:=1
- ENDIF
-
-
- IF first=TRUE THEN
- self.compile((end-start)*10+32,mc,bs) -> Be sure that there's enough room in string :-)
- self.message:=out
- ENDPROC
-
- /* find first separator (sep: ')', ',', or '+', .....) following index, in input */
- PROC findseparator(input:PTR TO CHAR,index,sep)
- DEF open,nxt
- open:=InStr(input,'(',index+1)
- IF open=-1 THEN open:=StrLen(input)
- nxt:=InStr(input,sep,index+1)
- IF nxt < open THEN RETURN nxt
-
- /* nxt > open */
- nxt:=findseparator(input,open,')') -> Where does that "open" close?
- IF nxt=-1 THEN Throw(ERR_NoChar,')') -> If it doesn't => error
- ENDPROC findseparator(input,nxt,sep) -> If it does, let's return the following sep
-
- /*
- * str:=evalstr(str) will read a string of the form
- * '[<len>:]<expr>' and return an estring containing the value of expr.
- * zeros are added on the left if necessary, to have a length of at least len.
- * variables are allowed, of course
- *
- * evalstr('2*2') -> '4' (default len is 1)
- * evalstr('2:2*2') -> '04' (padding 0 if necessary)
- * evalstr('2:7*15') -> '105' (overtaking len if necessary)
- * evalstr('4:6-8') -> '-002' (the "-", if any, comes at the very beginning)
- *
- * (You are responsible for freeing the returned string)
- *
- */
-
- EXPORT PROC evalstr(input) HANDLE
- DEF len,neg,i,expr:PTR TO expression,st,out
-
- i:=InStr(input,':')
- IF i <> -1
- len:=Val(input)
- ELSE
- len:=1
- ENDIF
- NEW expr.create(OUT_Float32,input,i+1,-1,1)
- /*we start after the :... first is set to false so that the expression won't be compiled*/
- i:=expr.evaluate(0.,0.) -> evaluate into i using x=y=0
- i:=!i! -> Convert to int32
- END expr
- st:=String(11) -> 11, as max is -2^31, which is -2147483648
- StringF(st,'\d',Abs(i)) -> Now st contains i on the left
- neg:=(i<0)
- IF StrLen(st)-neg < len -> then we must add len-(StrLen(st)-neg) padding zeroes
- out:=String(len)
- IF neg THEN StrCopy(out,'-')
- StrAdd(out,'00000000000000000000') -> I am too lazy to use loops or such stuff. Just don't use
- -> this proc with len larger than 21...
- SetStr(out,len-StrLen(st)) -> the - is already there, so no "-neg"...
- StrAdd(out,st)
- ELSE -> then we can just return st, maybe with a heading "-"
- out:=String(StrLen(st)-neg)
- IF neg THEN StrCopy(out,'-')
- StrAdd(out,st)
- ENDIF
- EXCEPT
- IF out THEN DisposeLink(out)
- out:=String(10)
- StrCopy(out,'--Error--')
- ENDPROC out
-
-
- /* Reg usage: A5 is for temporary values, valid during one single expr evaluation;
- A1 points to the pre-calculated values*/
-
- PROC compile(len,maxcount,buffsize) OF expression
- DEF nxt:PTR TO LONG,dest:PTR TO LONG
- c:=0;p:=0;s:=-1
- NEW code[len];crs:=code
- NEW precalc[len];prs:=precalc
- buffer:=AllocVec(buffsize*4+4,MEMF_PUBLIC) -> 4 is SIZEOF LONG
- self.buffer:=buffer
-
- crs[]:=$4E55;crs++; crs[]:=(-maxcount-2)*4 AND $FFFF;crs++ -> LINK A5,#$<..maxcount..>
-
- prs[]:=$4E55;prs++; prs[]:=(-maxcount-2)*4 AND $FFFF;prs++ -> LINK A5,#$<maxcount>
-
- self.subcompile()
- IF (self.need AND NEEDX)=$0 -> If *nothing* in the expression depends on x, let's save+recall here.
- s++
-
- crs[]:=$227C;crs++; crs[]:=Shr(buffer,16);crs++; crs[]:=buffer;crs++ ->MOVE.L buffer,A1
- prs[]:=$227C;prs++; prs[]:=Shr(buffer,16);prs++; prs[]:=buffer;prs++ ->MOVE.L buffer,A1
-
- prs[]:=$2340;prs++;prs[]:=s*4;prs++ -> MOVE.L D0,<s*4>(A1)
- crs[]:=$2029;crs++;crs[]:=s*4;crs++ -> MOVE.L <s*4>(A1),D0
- ENDIF
-
- crs[]:=$4E5D;crs++ -> UNLK A5
- crs[]:=$4E75;crs++ -> RTS
-
- prs[]:=$4E5D;prs++ -> UNLK A5
- prs[]:=$4E75;prs++ -> RTS
-
- self.calculate:=AllocVec(crs-code+16,NIL)
- nxt:=code;dest:=self.calculate
- WHILE nxt <= (crs)
- dest[]:=nxt[]
- nxt++;dest++
- ENDWHILE
- END code[len]
-
- self.precalc:=AllocVec(prs-precalc+16,NIL)
- nxt:=precalc;dest:=self.precalc
- WHILE nxt <= (prs)
- dest[]:=nxt[]
- nxt++;dest++
- ENDWHILE
- END precalc[len]
- ENDPROC
-
- PROC long(k:PTR TO expression)
- IF k
- RETURN (k.need AND SHORT) = $0
- ELSE
- RETURN FALSE
- ENDIF
- ENDPROC
-
- PROC subcompile() OF expression
- DEF saved=FALSE, -> TRUE if arg1 was saved in A5.
- buff=-1 -> buffer-slot (in case "f(y)_f(x)") where f(y) is stored
- IF long(self) = FALSE -> That's only if the global (whole) expression is short.
- IF self.func=fvariable -> For now, use pre-calculation as usual, I mean, 'y' expression will be pre-calculated even if it is quite useless...
- IF self.cte=VAR_x
- crs[]:=$202D;crs++ -> MOVE.L $C(A5),D0
- crs[]:=$C;crs++
- ELSEIF self.cte=VAR_y
- prs[]:=$202D;prs++ -> MOVE.L $8(A5),D0
- prs[]:=$8;prs++
- ENDIF
- ELSEIF self.func=fconstant
- prs[]:=$203C ;prs++ -> MOVE.L #self.cte,D0
- prs[]:=Shr(self.cte,16);prs++;prs[]:=self.cte ;prs++ -> constant argument
- ENDIF
- RETURN
- ENDIF
-
- /* First of all calculate subexpressions that need to be calculated */
- IF long(self.arg1)
- self.arg1.subcompile()
- IF long(self.arg2) -> If we have two args that need computation, then we'll have to save one to do the other one...
- IF self.arg1.need AND NEEDX -> Neither arg1, nor us can pre-calculate.
- c++
- crs[]:=$2B40;crs++-> MOVE.L D0,$-<c*4>(A5)
- crs[]:=-c*4 ;crs++-> store that arg
- saved:=TRUE
- ELSEIF (self.need AND NEEDX) = $0
- p++
- prs[]:=$2B40;prs++-> MOVE.L D0,$-<p*4>(A5)
- prs[]:=-p*4 ;prs++-> store that arg
- saved:=TRUE
- ENDIF
- ENDIF
- IF self.need AND Not(self.arg1.need) AND NEEDX -> save pre-calculated arg1 to A1
- s++
- buff:=s
- prs[]:=$227C;prs++;prs[]:=Shr(buffer,16);prs++; prs[]:=buffer;prs++ ->MOVE.L buffer,A1
- prs[]:=$2340;prs++;prs[]:=s*4;prs++ -> MOVE.L D0,<s*4>(A1)
- ENDIF
- ENDIF
- IF long(self.arg2)
- self.arg2.subcompile()
- IF self.need AND Not(self.arg2.need) AND NEEDX -> arg2 doesn't needx but we do => save pre-calculated arg2 to A1
- s++
- prs[]:=$227C;prs++;prs[]:=Shr(buffer,16);prs++; prs[]:=buffer;prs++ ->MOVE.L buffer,A1
- prs[]:=$2340;prs++;prs[]:=s*4;prs++ -> MOVE.L D0,<s*4>(A1)
- ENDIF
- ENDIF
-
- /* Now put arguments in stack and execute function. */
- IF long(self.arg1)=FALSE -> I assume that self.arg1 exists
- IF self.arg1.func=fvariable
- IF self.arg1.cte=VAR_x
- crs[]:=$2F2D;crs++ -> MOVE.L $C(A5),-(A7)
- crs[]:=$C;crs++
- ELSEIF self.arg1.cte=VAR_y
- write($2F2D,self.need) -> MOVE.L $8(A5),-(A7)
- write($8,self.need) -> "write", as we wouldn't need pre-calculation if there's only a single y.
- ENDIF
- ELSEIF self.arg1.func=fconstant
- write($2F3C,self.need) -> MOVE.L #self.cte,-(A7)
- write(Shr(self.arg1.cte,16),self.need);write(self.arg1.cte,self.need)
- ENDIF
- ELSEIF saved
- IF self.need AND NEEDX
- crs[]:=$2F2D ;crs++ -> MOVE.L $-<c*4>(A5),-(A7)
- crs[]:=-c*4 ;crs++-> push copied argument (a)
- c--
- ELSE
- prs[]:=$2F2D ;prs++ -> MOVE.L $-<p*4>(A5),-(A7)
- prs[]:=-p*4 ;prs++-> push copied argument (a)
- p--
- ENDIF
- ELSEIF buff>-1 -> Copy pre-calculated value.
- crs[]:=$227C;crs++;crs[]:=Shr(buffer,16);crs++; crs[]:=buffer;crs++ ->MOVE.L buffer,A1
- crs[]:=$2F29;crs++ -> MOVE.L <buff*4>(A1),-(A7)
- crs[]:=buff*4;crs++
- ELSE -> Long arg1(x), Short arg2
- IF self.need AND NEEDX
- crs[]:=$2F00 ;crs++ -> MOVE.L D0,-(A7)
- ELSE
- prs[]:=$2F00 ;prs++ -> MOVE.L D0,-(A7)
- ENDIF
- ENDIF
-
- IF self.arg2
- IF long(self.arg2)
- IF self.need AND NEEDX
- IF self.arg2.need AND NEEDX
- crs[]:=$2F00 ;crs++ -> MOVE.L D0,-(A7)
- ELSE
- crs[]:=$227C;crs++;crs[]:=Shr(buffer,16);crs++; crs[]:=buffer;crs++ ->MOVE.L buffer,A1
- crs[]:=$2F29;crs++ -> MOVE.L <s*4>(A1),-(A7)
- crs[]:=s*4;crs++
- ENDIF
- ELSE
- prs[]:=$2F00 ;prs++ -> MOVE.L D0,-(A7)
- ENDIF
- ELSE
- IF self.arg2.func=fvariable
- IF self.arg2.cte=VAR_x
- crs[]:=$2F2D;crs++ -> MOVE.L $C(A5),-(A7)
- crs[]:=$C;crs++
- ELSEIF self.arg2.cte=VAR_y
- write($2F2D,self.need) -> MOVE.L $8(A5),-(A7)
- write($8,self.need) -> "write", as we wouldn't need pre-calculation if there's only a single y.
- ENDIF
- ELSEIF self.arg2.func=fconstant
- write($2F3C,self.need) -> MOVE.L #self.arg2.cte,-(A7)
- write(Shr(self.arg2.cte,16),self.need);write(self.arg2.cte,self.need) -> constant argument
- ENDIF
- ENDIF
- ELSE -> No arg2: push zero
- write($2F3C,self.need) -> MOVE.L #0,-(A7)
- write(0,self.need);write(0,self.need)
- ENDIF
- IF self.need AND NEEDX
- crs[]:=$2F3C ;crs++ -> MOVE.L #self.cte,-(A7)
- crs[]:=Shr(self.cte,16);crs++;crs[]:=self.cte ;crs++
- crs[]:=$4EB9 ;crs++ -> JSR self.evaluate
- crs[]:=Shr(self.evaluate,16);crs++;crs[]:=self.evaluate ;crs++
- ELSE
- prs[]:=$2F3C ;prs++ -> MOVE.L #self.cte,-(A7)
- prs[]:=Shr(self.cte,16);prs++;prs[]:=self.cte ;prs++
- prs[]:=$4EB9 ;prs++ -> JSR self.evaluate
- prs[]:=Shr(self.evaluate,16);prs++;prs[]:=self.evaluate ;prs++
- ENDIF
- ENDPROC
-
- PROC write(value,need) -> Little loss of time here at pre-compilation-time, but it is nicer so.
- IF need AND NEEDX
- crs[]:=value;crs++
- ELSE
- prs[]:=value;prs++
- ENDIF
- ENDPROC
-
- PROC reference() OF expression
- IF self.func.readpid = TRUE THEN -> I guess that all function that need a data require having its project frozen...
- RETURN self.cte,self.arg1,self.arg2
- ENDPROC self.func.argcount+1,self.arg1,self.arg2
-
- PROC evaluate(x,y) OF expression
- DEF a,b,p
- IF self.func=fvariable
- p:=self.evaluate
- RETURN p(x,y,self.cte)
- ENDIF
- IF self.func.argcount>0
- a:=self.arg1.evaluate(x,y)
- IF self.func.argcount>1 ->THEN
- b:=self.arg2.evaluate(x,y)
- ENDIF
- ENDIF
- p:=self.evaluate
- ENDPROC p(a,b,self.cte)
-
- PROC end() OF expression
- IF self.func -> Maybe the decoding was aborted before we could know the function...
- IF self.func.argcount>0
- END self.arg1
- IF self.func.argcount>1 THEN END self.arg2
- ENDIF
- ENDIF
- IF self.calculate THEN
- FreeVec(self.calculate)
- IF self.precalc THEN
- FreeVec(self.precalc)
- IF self.buffer THEN
- FreeVec(self.buffer)
- ENDPROC
-
- /*last(): Exactely like InStr(), but from right to left..*/
- PROC last(str,findme,before=-1)
- DEF found=0,next
- IF before=-1 THEN before:=StrLen(findme)
-
- WHILE ((next:=InStr(str,findme,found)) < before) AND (next <> -1)
- found:=next
- IF CtrlC()
- WriteF('Infinite loop?\nnext=\d;found=\d... [returning -1]\n')
- RETURN -1
- ENDIF
- ENDWHILE
- IF found=0 THEN found:=-1
- ENDPROC found
-