DracScript 1.06 Released! LGPL Scripting Language

Developed or developing a new product in PureBasic? Tell the world about it.
Xombie
Addict
Addict
Posts: 898
Joined: Thu Jul 01, 2004 2:51 am
Location: Tacoma, WA
Contact:

Post by Xombie »

Nifty.

I'm unsure of what other areas need enhancements so if there's a procedure you'd like me to look at, just let me know. I enjoy a good challenge at trying to optimize things ^_^
Xombie
Addict
Addict
Posts: 898
Joined: Thu Jul 01, 2004 2:51 am
Location: Tacoma, WA
Contact:

Post by Xombie »

Nifty.

I'm unsure of what other areas need enhancements so if there's a procedure you'd like me to look at, just let me know. I enjoy a good challenge at trying to optimize things ^_^

Like this small procedure update...

Code: Select all

Procedure.s TrimFloat(value.s)
   ;
   HoldFloat.f
   ;
   HoldString.s
   ;
   *HoldChar.BYTE
   ;
   HasDecimal.l
   ;
   LastNumeric.l = 1
   ;
   HoldBegin.l
   ;
   If IsNumber(value, 46, 0, 0)
      ;
      *HoldChar = @value
      ;
      Repeat
         ;
         If *HoldChar\b = 46
            ;
            HasDecimal = LastNumeric
            ;
         ElseIf *HoldChar\b = 0
            ;
            If HasDecimal
               ;
               ProcedureReturn PeekS(@value + HoldBegin - 1, LastNumeric)
               ;
            Else
               ;
               ProcedureReturn value
               ;
            EndIf
            ;
         Else
            ;
            If *HoldChar\b <> 32
               ;
               If HoldBegin = 0 : HoldBegin = *HoldChar - @value + 1 : EndIf
               ;
               If *HoldChar\b <> 48 : LastNumeric + 1 : EndIf
               ;
            EndIf
            ;
         EndIf
         ;
         *HoldChar + 1
         ;
      ForEver
      ;
   EndIf
   ;
   ProcedureReturn value
   ;
EndProcedure
Althought I don't think you're using the procedure yet. If you do, it should be roughly twice as fast as your existing procedure. It has the added bonus of performing an inplace trim as well.
dracflamloc
Addict
Addict
Posts: 1648
Joined: Mon Sep 20, 2004 3:52 pm
Contact:

Post by dracflamloc »

Thats cool. Its used mainly in the DracSoft_Default.pb file.

I think alot of the room for improvement has to do with the passing and handling of strings across procedures.
ricardo
Addict
Addict
Posts: 2438
Joined: Fri Apr 25, 2003 7:06 pm
Location: Argentina

Post by ricardo »

Really great!!

Wishlist:

-Add the possiblity to make procedures or functions
- For/Next
ARGENTINA WORLD CHAMPION
dracflamloc
Addict
Addict
Posts: 1648
Joined: Mon Sep 20, 2004 3:52 pm
Contact:

Post by dracflamloc »

Functions within the script are on the ToDo

For->Next is pretty worthless and would just slow down the interpreter. Of course its open source so someone could add it pretty easily.

Just do this instead:

Instead of:
For i =0 to 10
...
Next

Do:
While i<10
...
i=i+1
Wend
Killswitch
Enthusiast
Enthusiast
Posts: 731
Joined: Wed Apr 21, 2004 7:12 pm

Post by Killswitch »

Well not nessicarly - you could just (internally) convert a for/next loop to a While loop (just like you showed) and that way you'll save end users some time while keeping the interpreter as fast as usual.

Of course, you'd need to convert the line just the once - otherwise you will get some slow down :).
~I see one problem with your reasoning: the fact is thats not a chicken~
dracflamloc
Addict
Addict
Posts: 1648
Joined: Mon Sep 20, 2004 3:52 pm
Contact:

Post by dracflamloc »

Yes I had considered that approach. That would have the effect of reporting incorrect lines when an error occurs in the script, though.
Killswitch
Enthusiast
Enthusiast
Posts: 731
Joined: Wed Apr 21, 2004 7:12 pm

Post by Killswitch »

Really? Could you not just replace the For/Next lines with While/Wend lines? I can't see how you'd get incorrect line number there...
~I see one problem with your reasoning: the fact is thats not a chicken~
dracflamloc
Addict
Addict
Posts: 1648
Joined: Mon Sep 20, 2004 3:52 pm
Contact:

Post by dracflamloc »

you would need to add a line to increment the variable.
Killswitch
Enthusiast
Enthusiast
Posts: 731
Joined: Wed Apr 21, 2004 7:12 pm

Post by Killswitch »

Ahh, I see what you mean now.
~I see one problem with your reasoning: the fact is thats not a chicken~
dracflamloc
Addict
Addict
Posts: 1648
Joined: Mon Sep 20, 2004 3:52 pm
Contact:

Post by dracflamloc »

Just a quick note:

For those unfamiliar witht he LGPL. If you use this code in any way you must release the modifications to the code and within your programs documentation or credits must make available a way for the source code to be obtained at no cost. Thats it in a nutshell but the full text can be found on www.gnu.org

Enjoy!
dracflamloc
Addict
Addict
Posts: 1648
Joined: Mon Sep 20, 2004 3:52 pm
Contact:

Post by dracflamloc »

Bug fixes have been uploaded. See the readme.txt
dracflamloc
Addict
Addict
Posts: 1648
Joined: Mon Sep 20, 2004 3:52 pm
Contact:

Post by dracflamloc »

Uploaded a quick fix. Execute() was clearing the symbol table. I disabled this. Now you will have to call DS_Reset(0,0,1,0,0) to clear the symbol table before calling DS_Execute(). The reason for this is to allow the variables to be global between scripts.
Shannara
Addict
Addict
Posts: 1808
Joined: Thu Oct 30, 2003 11:19 pm
Location: Emerald Cove, Unformed

Post by Shannara »

Hmm, the newest download have a bug, it's trying to reference a commented out array ... So I uncommented it while I am converting over to 4.0. I think it's around line 130.

Code: Select all

Dim DS_ScriptArray.DS_LINE(i,j)
Shannara
Addict
Addict
Posts: 1808
Joined: Thu Oct 30, 2003 11:19 pm
Location: Emerald Cove, Unformed

Post by Shannara »

4.0 code ... only a few changes :)

DracScript.pbi

Code: Select all

;DracScript Include
;Copyright 2006 DracSoft
;If you use this file in a project it would be appreciated if you 
;send me a friendly e-mail or perhaps paypal donate to: cyberneticwraith@phreaker.net
;Do not change this header!
;
;   Licensed under the LGPL (www.gnu.org) with an exception: May be statically linked and 
;   included into a program, code must maintain the above header. Be sure to release any
;   optimizations to the language ASAP!
;
;   Only this file or files it includes must have code released under LGPL,
;   so this CAN be used in commercial projects!
;
;   Some of the math evaluation algo's are modified by DracSoft! Thanks to all!


;TODO: Make  DS_RegisterDLL() procedure that calls a DS_Plugin_RegisterAll() function within the dll to load new functions
;TODO: Optimize (of course, this ToDo will be permanent =P).
;TODO: Make it so strings with the ' character in them can be used
;TODO: Add ability to declare and call procedures made in script (For now IncludeFile can achieve a similar effect)

;COMPILER CONSTANTS
#DS_TEST_MATHSPEED=0    ;set to zero to skip the eval algorithm speed test
#DS_TEST_BUILD=0        ;set to zero for use in normal projects.
#DS_INCLUDE_DEFAULT=1   ;set to zero to strip default DracScript functions from your project

Enumeration 1 ; EVAL_ALGO
  #DS_EVAL_ALGO_XOMBIE
  #DS_EVAL_ALGO_XOMBIENEW
  #DS_EVAL_ALGO_SROD
  #DS_EVAL_ALGO_TROND
EndEnumeration

#DS_EVAL_ALGO=#DS_EVAL_ALGO_XOMBIENEW


;CONSTANTS
#DS_VERSION="1.01 Beta"
#DS_RETURN_SYMBOL="RET"
#DS_CONSTANT_CHAR="#"
#DS_ERROR_STRING="#"
Enumeration ; TYPE
  #DS_TYPE_NULL
  #DS_TYPE_VALUE
  #DS_TYPE_STRING
EndEnumeration
Enumeration 1 ; RESULT
  #DS_RESULT_SUCCESS
  #DS_RESULT_SYMBOL
  #DS_RESULT_COMMANDERROR
  #DS_RESULT_PCOUNT
  #DS_RESULT_NOTEXIST
  #DS_RESULT_CONDITIONAL
  #DS_RESULT_NOENDIF
  #DS_RESULT_NOWEND
  #DS_RESULT_NOWHILE
  #DS_RESULT_MATH
  #DS_RESULT_NOSCRIPT
EndEnumeration
Enumeration 1 ; KEYWORD
  #DS_KEYWORD_IF
  #DS_KEYWORD_EXIT
  #DS_KEYWORD_GOTO
  #DS_KEYWORD_LABEL
  #DS_KEYWORD_ELSEIF
  #DS_KEYWORD_ELSE
  #DS_KEYWORD_ENDIF
  #DS_KEYWORD_WHILE
  #DS_KEYWORD_WEND
  #DS_KEYWORD_FREE
EndEnumeration


;STRUCTURES
Structure DS_COMMAND
  Address.l
  params.l
  name.s
EndStructure

Structure DS_SYMBOL
  Value.s
  name.s
  type.l  ;DS_TYPE_<etc>
EndStructure

Structure DS_ENVIRONMENT
  scriptname.s
  line.l
  ;linecount.l
  lastError.s
  maxScripts.l
  maxLines.l
EndStructure

Structure DS_CONSTANT
  name.s
  Value.s
EndStructure

Structure DS_JUMPENTRY
  src.l
  dest.l
EndStructure

Structure DS_LINE
  IsUsed.b  ;this stores if this script index has been loaded into yet
  IsLast.b  ;stores if this is the last line of the script
  line.s
  command.s
  word.s
  wordval.l
  exp.s
  params.s
  lhs.s
  rhs.s
  operator.s
  sym.s
  symexp.s
EndStructure


;GLOBALS
Global NewList DS_CommandList.DS_COMMAND()
Global NewList DS_SymbolList.DS_SYMBOL()
Global NewList DS_StackList.DS_SYMBOL()
Global NewList DS_ConstantList.DS_CONSTANT()
Global NewList DS_JumpList.DS_JUMPENTRY()
Global DS_Env.DS_ENVIRONMENT
; Shannara: Fixed below, it was commented out, but is required in code.
Global Dim DS_ScriptArray.DS_LINE(i,j) ;is declared in DS_Initialize()


;EXPRESSION EVAL PROCEDURES
Procedure.s DS_XS_Concatenate(exp.s)
  s.s=""
  While 1
    p=FindString(exp,"+",1)
    If p>0 And CountString(PeekS(@exp,p),"'") % 2 = 0
      s=s+RemoveString(Trim(PeekS(@exp,p-1)) ,"'")
      exp=Right(exp,Len(exp)-p)
    ElseIf p=0
      s=s+RemoveString(exp,"'")
      Break
    EndIf 
  Wend 
  ProcedureReturn s
EndProcedure

CompilerIf #DS_EVAL_ALGO=#DS_EVAL_ALGO_XOMBIE
  IncludeFile "./Xombie.pb"
CompilerEndIf
CompilerIf #DS_EVAL_ALGO=#DS_EVAL_ALGO_SROD
  IncludeFile "./Srod.pb"
CompilerEndIf
CompilerIf #DS_EVAL_ALGO=#DS_EVAL_ALGO_TROND
  IncludeFile "./Trond.pb"
CompilerEndIf
CompilerIf #DS_EVAL_ALGO=#DS_EVAL_ALGO_XOMBIENEW
  IncludeFile "./XombieNew.pb"
CompilerEndIf


Declare.b DS_CallCommand(name.s,params.s)


;DRACSCRIPT PROCEDURES
Procedure DS_SetLastError(err.s)
  DS_Env\lastError=err 
EndProcedure

Procedure.s DS_GetLastError()
  ProcedureReturn DS_Env\lastError
EndProcedure

Procedure.b DS_IsNumeric(str.s)
  str=Trim(str)
  If Mid(str,1,1)="-"
    a=2
  Else
    a=1
  EndIf   
  
  For i = a To Len(str)
    c.s=Mid(str,i,1)
    If (c<"0" Or c>"9") And c<>"." 
      ProcedureReturn 0
    EndIf 
  Next
  ProcedureReturn 1
EndProcedure

Procedure.s DS_TrimFloat(str.s)
  If DS_IsNumeric(str)
    If ValF(str)=0.0
      ProcedureReturn "0"
    EndIf 
    
    p=Len(str)-1
    While PeekB(@str+p)=48 ;checks for 0, if it is, then it continues to decrement the truncate counter
      p - 1
    Wend 
    
    If PeekS(@str+p+1,1)="." ; make sure it was a float and not a whole number that ends in 0 like 100
      ProcedureReturn PeekS(@str,p+1)
    EndIf 
  EndIf 
  
  ProcedureReturn str  
EndProcedure

Procedure.b DS_IsCommand(cmd.s)
  cmd=UCase(cmd)
  ForEach DS_CommandList()
    If DS_CommandList()\name = cmd
      ProcedureReturn 1
    EndIf 
  Next 
  ProcedureReturn 0
EndProcedure

Procedure.b DS_Initialize(maxScripts.l,maxLinesPerScript.l)
  If maxScripts >= 0 And maxLinesPerScript >= 0
    Dim DS_ScriptArray.DS_LINE(maxScripts-1,maxLinesPerScript-1)
    DS_Env\maxScripts=maxScripts
    DS_Env\maxLines=maxLinesPerScript
    DS_Env\scriptname=""
    DS_Env\line=0
    ProcedureReturn 1
  EndIf 
  ProcedureReturn 0
EndProcedure

Procedure.s DS_ProcessConstants(s.s)
  ;constants
  ;MessageRequester(s,"bef")
  ForEach DS_ConstantList()
    s=ReplaceString(s,#DS_CONSTANT_CHAR+DS_ConstantList()\name,DS_ConstantList()\Value)
  Next
  ;MessageRequester(s,"aft")
  ProcedureReturn s
EndProcedure

Procedure.b DS_Reset(commands.b,stack.b,symbols.b,const.b,env.b)
  If stack
    ClearList(DS_StackList())
  EndIf 
  If commands
    ClearList(DS_CommandList())
  EndIf
  If symbols 
    ClearList(DS_SymbolList())
  EndIf 
  If const
    ClearList(DS_ConstantList())
  EndIf 
  If env
    DS_Env\scriptname=""
    DS_Env\line=0
  EndIf 
  ClearList(DS_JumpList())
EndProcedure

Procedure.b DS_StackPush(sym.s, val.s, type.l)
  If type>-1
    AddElement(DS_StackList())
    DS_StackList()\name=sym 
    DS_StackList()\type=type
    DS_StackList()\Value=val
    ProcedureReturn 1
  EndIf 
  DS_SetLastError("Stack push failed. Invalid symbol type.")
  ProcedureReturn 0 
EndProcedure

Procedure.b DS_SetSymbol(sym.s, val.s, type.l)
  sym=Trim(sym)
  ;if type is -1 dont change the type just set the value
  ForEach DS_SymbolList()
    If DS_SymbolList()\name=UCase(sym)
      DS_SymbolList()\Value=val 
      If type <> -1
        DS_SymbolList()\type=type
      EndIf 
      ProcedureReturn 1
    EndIf 
  Next 
  
  ;not found symbol and if valid symbol, create it
  If type<>-1 And Trim(sym)<>"" And DS_IsNumeric(sym)=0
    AddElement(DS_SymbolList())
    DS_SymbolList()\name=UCase(sym)
    DS_SymbolList()\type=type
    DS_SymbolList()\Value=val
    ProcedureReturn 1
  EndIf 
  DS_SetLastError("Set symbol failed. Invalid symbol name or symbol type.")
  ProcedureReturn 0 
EndProcedure

Procedure.b DS_FreeSymbol(sym.s)
  ForEach DS_SymbolList()
    If DS_SymbolList()\name = sym 
      DeleteElement(DS_SymbolList())
      ProcedureReturn 1
    EndIf 
  Next 
  DS_SetLastError("Free symbol failed. Symbol "+sym+" does not exist.")
  ProcedureReturn 0
EndProcedure

Procedure.l DS_GetSymbol(sym.s)
  ForEach DS_SymbolList()
    If DS_SymbolList()\name=UCase(sym)
      ProcedureReturn @DS_SymbolList()
    EndIf 
  Next 
  DS_SetLastError("Get symbol failed. Symbol "+sym+" does not exist.")
  ProcedureReturn 0
EndProcedure

Procedure DS_Return(val.s, type.l)
  DS_SetSymbol(#DS_RETURN_SYMBOL,val,type)
EndProcedure

Procedure.b DS_RegisterCommand(procAddr.l, name.s, numParams.l)
  If procAddr<>0 And Trim(name)<>"" And Val(name)=0
    AddElement(DS_CommandList())
    DS_CommandList()\Address=procAddr
    DS_CommandList()\params=numParams
    DS_CommandList()\name=UCase(name)
    SortStructuredList(DS_CommandList(),#PB_Sort_String,OffsetOf(DS_COMMAND\name),0)
    ProcedureReturn 1
  EndIf 
  DS_SetLastError("Register command failed. Null procedure address or invalid command name.")
  ProcedureReturn 0
EndProcedure

Procedure.b DS_RegisterConstant(name.s,val.s)
  If Trim(name)<>"" And Val(name)=0
    AddElement(DS_ConstantList())
    DS_ConstantList()\name=UCase(name)
    DS_ConstantList()\Value=val
    ProcedureReturn 1 
  EndIf 
  DS_SetLastError("Register constant failed. Invalid constant name.")
  ProcedureReturn 0
EndProcedure

Procedure.b DS_FreeCommand(procAddr)
  ForEach DS_CommandList()
    If DS_CommandList()\Address=procAddr
      DeleteElement(DS_CommandList())
      ProcedureReturn 1
    EndIf 
  Next 
  DS_SetLastError("Free command failed. Command does not exist.")
  ProcedureReturn 0
EndProcedure

Procedure.b DS_FreeCommandByName(name.s)
  ForEach DS_CommandList()
    If DS_CommandList()\name=UCase(name)
      DeleteElement(DS_CommandList())
      ProcedureReturn 1
    EndIf 
  Next 
  DS_SetLastError("Free command failed. Command does not exist.")
  ProcedureReturn 0
EndProcedure

Procedure.b DS_FreeConstant(name.s)
  ForEach DS_ConstantList()
    If UCase(DS_ConstantList()\name)=UCase(name)
      DeleteElement(DS_ConstantList())
      ProcedureReturn 1
    EndIf 
  Next 
  DS_SetLastError("Free constant failed. Constant does not exist.")
  ProcedureReturn 0
EndProcedure

Procedure.s DS_GetParameter(params.s,index)
  
  For i = 1 To Len(params)
  
    Char.s=Mid(params,i,1)
    
    If Char="," And qcount % 2 = 0
      ccount + 1
      lastcomma=currentcomma
      currentcomma=i
      
      If ccount=index
        ProcedureReturn Trim(PeekS(@params+lastcomma,currentcomma-lastcomma-1))
      EndIf 
    EndIf 
    
    If Char="'"
      qcount + 1
    EndIf 
    
  Next 
  
  If i-1=Len(params) And index=ccount+1
    ProcedureReturn Trim(PeekS(@params+currentcomma,Len(params)-currentcomma))
  EndIf 
  
  ProcedureReturn ""
EndProcedure

Procedure.l DS_CountParameters(params.s)
  For i = 1 To Len(params)
    Char.s=Mid(params,i,1)
    
    If Char="," And qcount % 2 = 0
      ccount + 1
    ElseIf Char="'"
      qcount + 1
    EndIf 
  Next 
  
  If ccount=0 And Trim(params)=""
    ProcedureReturn 0
  EndIf 
  
  ProcedureReturn ccount+1
EndProcedure

Procedure.l DS_FindStringReverse(s.s,f.s,p.l)
  p=p-Len(f)+1
  While p>=0
    If PeekS(@s+p,Len(f))=f
      ProcedureReturn p+1
    EndIf 
    p-1
  Wend   
  ProcedureReturn 0
EndProcedure

Procedure.s DS_ProcessCommands(exp.s)
  spos=1
  parcount=0
  While spos>0
    spos=0
    ForEach DS_CommandList()
      temp=DS_FindStringReverse(UCase(exp),DS_CommandList()\name,Len(exp))
      rchar.s=Mid(exp,temp+Len(DS_CommandList()\name),1)
      lchar.s=Mid(exp,temp-1,1)
      If rchar="(" And Mid(exp,temp+Len(DS_CommandList()\name)+1,1)=")"
        parcount=DS_CommandList()\params
        spos=temp
        command.s=DS_CommandList()\name
      ElseIf rchar=" " Or rchar="("
        If lchar="=" Or lchar=">" Or lchar="<" Or lchar="+" Or lchar="-" Or lchar="/" Or lchar="*" Or lchar="^" Or lchar=" " Or lchar="," Or lchar="(" Or temp=1
          qcl=CountString(Left(exp,spos-1),"'")
          If qcl % 2 = 0  ;so not in the midle of a string
            If temp>spos
              parcount=DS_CommandList()\params
              spos=temp
              command.s=DS_CommandList()\name
            EndIf
          EndIf 
        EndIf
      EndIf    
    Next 
                  
    If spos>0                         
      ;get params
      If parcount>0
        Startpos=FindString(exp,"(",spos)
        pcount=0
        tmp=Startpos+1
        While 1
          If tmp<Len(exp)
            cur.s=PeekS(@exp+tmp,1)
            If cur="("
              pcount+1
            EndIf 
            If cur=")" And pcount=0
              Endpos=tmp
              Break 
            ElseIf cur=")"
              pcount-1
            EndIf
            tmp + 1                  
          Else
            DS_SetLastError("Syntax error: '(' expected after '"+command+"'.")
            ProcedureReturn #DS_ERROR_STRING+"ERROR"
          EndIf                 
        Wend 
      Else
        Startpos=FindString(exp,"(",spos)
        Endpos=Startpos
      EndIf 
      
      ;call command
      params.s=Trim(PeekS(@exp+Startpos,Endpos-Startpos))          
      res=DS_CallCommand(command,params)
      If res=#DS_RESULT_SUCCESS
        *symbol.DS_SYMBOL=DS_GetSymbol(#DS_RETURN_SYMBOL)
        Select *symbol\type
          Case #DS_TYPE_STRING
            exp=PeekS(@exp,spos-1)+"'"+*symbol\Value+"'"+PeekS(@exp+Endpos+1,Len(exp)-Endpos)
          Case #DS_TYPE_VALUE
            exp=PeekS(@exp,spos-1)+*symbol\Value+PeekS(@exp+Endpos+1,Len(exp)-Endpos)
          Case #DS_TYPE_NULL
            exp=PeekS(@exp,spos-1)+"0"+PeekS(@exp+Endpos+1,Len(exp)-Endpos)
        EndSelect
      Else
        ProcedureReturn #DS_ERROR_STRING+"ERROR:"+Str(res)
      EndIf
    EndIf       
    
  Wend   
  
  ProcedureReturn exp   
EndProcedure

Procedure.b DS_CallCommand(name.s,params.s)
  ;push the stack
  params=DS_ProcessConstants(params)
  
  pc = DS_CountParameters(params)
  For i = 1 To pc
    param.s = DS_XS_Evaluate(DS_GetParameter(params,i))
    If DS_IsNumeric(param)=0
      type=#DS_TYPE_STRING
    Else ; its a number!
      type=#DS_TYPE_VALUE 
    EndIf
     
    If PeekS(@param,Len(#DS_ERROR_STRING))=#DS_ERROR_STRING
      DS_SetLastError("Expression evaluation error in: "+StringField(params,i,","))
      ProcedureReturn #DS_RESULT_MATH
    EndIf
     
    DS_StackPush(Str(i+CountList(DS_StackList())),param,type)
  Next 
  
  ;execute the command
  ForEach DS_CommandList()
    If DS_CommandList()\name=UCase(name)
      If DS_CommandList()\params=pc
        If CallFunctionFast(DS_CommandList()\Address)=0
          ;The error text should be set by the procedure before returning
          ProcedureReturn #DS_RESULT_COMMANDERROR ;if the actual function returns an error
        EndIf 
        found=1
        Break 
      Else
        DS_SetLastError("Command error. Incorrect number of parameters. Expected: "+Str(DS_CommandList()\params))
        ProcedureReturn #DS_RESULT_PCOUNT ;if the parameter count is wrong
      EndIf 
    EndIf 
  Next 
  
  If found=0
    DS_SetLastError("Syntax error. Command "+UCase(name)+" does not exist.")
    ProcedureReturn #DS_RESULT_NOTEXIST ;if the command doesnt exist
  EndIf 
  
  ;pop the stack
  ClearList(DS_StackList()) ; just clear it for now
;   lc=CountList(DS_StackList())  
;   For i=1 To pc
;     SelectElement(DS_StackList(),lc-i)
;     DeleteElement(DS_StackList())
;   Next 
  
  ProcedureReturn #DS_RESULT_SUCCESS ;function was successful
EndProcedure

Procedure.l DS_FindLabel(script.l,label.s)
  i=0
  While DS_ScriptArray(script,i)\IsLast=0
    If UCase(Trim(DS_ScriptArray(script,i)\line))="LABEL "+UCase(Trim(label))
      ProcedureReturn i
    EndIf 
    i + 1
  Wend     
  DS_SetLastError("Syntax error: Label '"+label+"' not found.")
  ProcedureReturn -1
EndProcedure

Procedure.b DS_FreeScript(index.l)
  If index>=0 And index<DS_Env\maxScripts
    For i=0 To DS_Env\maxLines-1
      DS_ScriptArray(index,i)\IsUsed=0  ;this stores if this script index has been loaded into yet
      DS_ScriptArray(index,i)\IsLast=0  ;stores if this is the last line of the script
      DS_ScriptArray(index,i)\line=""
    Next
    ProcedureReturn 1 
  EndIf 
  ProcedureReturn 0
EndProcedure

Procedure.l DS_LoadScriptString(str.s,index.l)
  If index=-1
    ;find next free script
    For i=0 To DS_Env\maxScripts-1
      If DS_ScriptArray(i,0)\IsUsed=0
        index=i
        Break 
      EndIf 
    Next
    If index=-1
      ProcedureReturn -1
    EndIf 
  ElseIf index > DS_Env\maxScripts-1 Or index < -1
    ProcedureReturn -1
  EndIf 
  
  ;count lines, check if its above the max
  str=RemoveString(str,Chr(13))
  linecount=CountString(str,Chr(10))+1
  If linecount > DS_Env\maxLines
    ProcedureReturn -1
  EndIf 
  
  ;clear the script we're loading over
  If DS_FreeScript(index)=0
    ProcedureReturn -1
  EndIf 
    
  ;process script into the array
  For i=1 To linecount
    DS_ScriptArray(index,i-1)\line=ReplaceString(Trim(StringField(str,i,Chr(10))),Chr(9)," ")
    ForEach DS_ConstantList()
      DS_ScriptArray(index,i-1)\line=ReplaceString(DS_ScriptArray(index,i-1)\line,#DS_CONSTANT_CHAR+DS_ConstantList()\name,DS_ConstantList()\Value)
    Next
  Next 
  
  ;preprocess labels and goto's, constants
  For i=0 To linecount-1
    If UCase(Trim(StringField(Trim(DS_ScriptArray(index,i)\line),1," ")))="GOTO"
      pos=DS_FindLabel(index,Trim(StringField(Trim(DS_ScriptArray(index,i)\line),2," ")))
      If pos > -1
        DS_ScriptArray(index,i)\line="GOTO "+Str(pos)
      Else
        ProcedureReturn -1
      EndIf 
    EndIf 
    
    ;constants
;     ForEach DS_ConstantList()
;       DS_ScriptArray(index,i)\line=ReplaceString(DS_ScriptArray(index,i)\line,#DS_CONSTANT_CHAR+DS_ConstantList()\name,DS_ConstantList()\value)
;     Next
  Next 
  
  ;preprocess other parts of the data
  For i=0 To linecount-1
    DS_ScriptArray(index,i)\line=Trim(DS_ScriptArray(index,i)\line)
    DS_ScriptArray(index,i)\word=Trim(UCase(StringField(DS_ScriptArray(index,i)\line,1," ")))
    DS_ScriptArray(index,i)\exp=Trim(Right(DS_ScriptArray(index,i)\line,Len(DS_ScriptArray(index,i)\line)-Len(DS_ScriptArray(index,i)\word)))
    DS_ScriptArray(index,i)\sym=StringField(DS_ScriptArray(index,i)\line,1,"=")
    DS_ScriptArray(index,i)\symexp=Trim(Right(DS_ScriptArray(index,i)\line,Len(DS_ScriptArray(index,i)\line)-Len(DS_ScriptArray(index,i)\sym)))
    
    If Left(DS_ScriptArray(index,i)\symexp,1)="="
      DS_ScriptArray(index,i)\symexp=Right(DS_ScriptArray(index,i)\symexp,Len(DS_ScriptArray(index,i)\symexp)-1)
    EndIf 
    DS_ScriptArray(index,i)\sym=RemoveString(UCase(DS_ScriptArray(index,i)\sym), " ")
    
    DS_ScriptArray(index,i)\command=Trim(UCase(StringField(DS_ScriptArray(index,i)\line,1,"(")))
    DS_ScriptArray(index,i)\params=Trim(Right(DS_ScriptArray(index,i)\line,Len(DS_ScriptArray(index,i)\line)-Len(DS_ScriptArray(index,i)\command)))
    If Mid(DS_ScriptArray(index,i)\params,1,1)="("
      DS_ScriptArray(index,i)\params=PeekS(@DS_ScriptArray(index,i)\params+1)
    EndIf 
    If Mid(DS_ScriptArray(index,i)\params,Len(DS_ScriptArray(index,i)\params),1)=")"
      DS_ScriptArray(index,i)\params=PeekS(@DS_ScriptArray(index,i)\params,Len(DS_ScriptArray(index,i)\params)-1)
    EndIf 
    
    ;get wordval
    Select DS_ScriptArray(index,i)\word
      Case "IF"
        DS_ScriptArray(index,i)\wordval=#DS_KEYWORD_IF
      Case "ELSEIF"
        DS_ScriptArray(index,i)\wordval=#DS_KEYWORD_ELSEIF
      Case "ELSE"
        DS_ScriptArray(index,i)\wordval=#DS_KEYWORD_ELSE
      Case "ENDIF"
        DS_ScriptArray(index,i)\wordval=#DS_KEYWORD_ENDIF
      Case "EXIT"
        DS_ScriptArray(index,i)\wordval=#DS_KEYWORD_EXIT
      Case "WHILE"
        DS_ScriptArray(index,i)\wordval=#DS_KEYWORD_WHILE
      Case "WEND"
        DS_ScriptArray(index,i)\wordval=#DS_KEYWORD_WEND
      Case "FREE"
        DS_ScriptArray(index,i)\wordval=#DS_KEYWORD_FREE
      Case "GOTO"
        DS_ScriptArray(index,i)\wordval=#DS_KEYWORD_GOTO
      Case "LABEL"
        DS_ScriptArray(index,i)\wordval=#DS_KEYWORD_LABEL      
    EndSelect
    
    ;get operator and lhs,rhs
    If FindString(DS_ScriptArray(index,i)\exp,"<>",1) <> 0
      DS_ScriptArray(index,i)\lhs=RemoveString(StringField(DS_ScriptArray(index,i)\exp,1,"<>"),">")
      DS_ScriptArray(index,i)\rhs=RemoveString(StringField(DS_ScriptArray(index,i)\exp,2,"<>"),">")
      DS_ScriptArray(index,i)\operator="<>"
    ElseIf FindString(DS_ScriptArray(index,i)\exp,">=",1) <> 0
      DS_ScriptArray(index,i)\lhs=RemoveString(StringField(DS_ScriptArray(index,i)\exp,1,">="),"=")
      DS_ScriptArray(index,i)\rhs=RemoveString(StringField(DS_ScriptArray(index,i)\exp,2,">="),"=")
      DS_ScriptArray(index,i)\operator=">="
    ElseIf FindString(DS_ScriptArray(index,i)\exp,"<=",1) <> 0
      DS_ScriptArray(index,i)\lhs=RemoveString(StringField(DS_ScriptArray(index,i)\exp,1,"<="),"=")
      DS_ScriptArray(index,i)\rhs=RemoveString(StringField(DS_ScriptArray(index,i)\exp,2,"<="),"=")
      DS_ScriptArray(index,i)\operator="<="
    ElseIf FindString(DS_ScriptArray(index,i)\exp,"<",1) <> 0
      DS_ScriptArray(index,i)\lhs=StringField(DS_ScriptArray(index,i)\exp,1,"<")
      DS_ScriptArray(index,i)\rhs=StringField(DS_ScriptArray(index,i)\exp,2,"<")
      DS_ScriptArray(index,i)\operator="<"
    ElseIf FindString(DS_ScriptArray(index,i)\exp,">",1) <> 0
      DS_ScriptArray(index,i)\lhs=StringField(DS_ScriptArray(index,i)\exp,1,">")
      DS_ScriptArray(index,i)\rhs=StringField(DS_ScriptArray(index,i)\exp,2,">")
      DS_ScriptArray(index,i)\operator=">"
    ElseIf FindString(DS_ScriptArray(index,i)\exp,"=",1) <> 0
      DS_ScriptArray(index,i)\lhs=StringField(DS_ScriptArray(index,i)\exp,1,"=")
      DS_ScriptArray(index,i)\rhs=StringField(DS_ScriptArray(index,i)\exp,2,"=")
      DS_ScriptArray(index,i)\operator="="
    EndIf 
  Next
  
  DS_ScriptArray(index,0)\IsUsed=1
  DS_ScriptArray(index,linecount)\IsLast=1
  ProcedureReturn index
EndProcedure

Procedure.s DS_ReadScriptFile(file.s,removeComments.b) ;this reads an entire file and also handles includes
  fid=ReadFile(#PB_Any,file)
  If fid<>0
    ;UseFile(fid)
    While Eof(fid)=0
      tmp.s=ReadString(fid)
      If removeComments=0 Or (Left(RemoveString(Trim(tmp),Chr(9)),1)<>";" And RemoveString(Trim(tmp),Chr(9))<>"")
        If UCase(StringField(tmp,1," "))="INCLUDEFILE"
          Nextfile.s=RemoveString(Trim(Right(tmp,Len(tmp)-Len("INCLUDEFILE"))),"'")
          tmp=DS_ReadScriptFile(Nextfile,removeComments)
          ;UseFile(fid)
        EndIf 
        str.s=str.s+tmp+Chr(10)
      EndIf      
    Wend  
    CloseFile(fid)    
    ProcedureReturn str
  Else
    DS_SetLastError("Could not load the specified file: "+file)
    ProcedureReturn ""
  EndIf 
EndProcedure

Procedure.l DS_LoadScriptFile(file.s,removeComments.b,index.l)
  ProcedureReturn DS_LoadScriptString(DS_ReadScriptFile(file,removeComments),index)
EndProcedure

Procedure.s DS_ProcessSymbols(exp.s)
  ForEach DS_SymbolList()
    spos=1
    While spos>0
      spos=FindString(UCase(exp),DS_SymbolList()\name,spos)
      If spos>0
        Char.s=Mid(exp,spos+Len(DS_SymbolList()\name),1)
        char2.s=Mid(exp,spos-1,1)
        If Char="=" Or Char=">" Or Char="<" Or Char="+" Or Char="-" Or Char="/" Or Char="*" Or Char="^" Or Char=" " Or Char="," Or Char=")" Or spos+Len(DS_SymbolList()\name)-1=Len(exp)
          If char2="=" Or char2=">" Or char2="<" Or char2="+" Or char2="-" Or char2="/" Or char2="*" Or char2="^" Or char2=" " Or char2="," Or char2="(" Or spos=1
            qcl=CountString(Left(exp,spos-1),"'")
            If qcl % 2 = 0  ;so not in the midle of a string
              If DS_SymbolList()\type=#DS_TYPE_STRING
                exp=PeekS(@exp,spos-1)+"'"+DS_SymbolList()\Value+"'"+PeekS(@exp+spos+Len(DS_SymbolList()\name)-1)
              ElseIf DS_SymbolList()\type=#DS_TYPE_VALUE
                exp=PeekS(@exp,spos-1)+DS_SymbolList()\Value+PeekS(@exp+spos+Len(DS_SymbolList()\name)-1)
              ElseIf DS_SymbolList()\type=#DS_TYPE_NULL
                exp=PeekS(@exp,spos-1)+"0"+PeekS(@exp+spos+Len(DS_SymbolList()\name)-1)
              EndIf
            Else
              spos+1
            EndIf         
          Else
            spos+1          
          EndIf 
        Else
          spos+1
        EndIf 
      EndIf 
    Wend 
  Next 
  ProcedureReturn exp
EndProcedure

Procedure.b DS_EvaluateConditional(script.l,line.l)
  If DS_ScriptArray(script,line)\operator="<>"
    lhs.s=DS_ProcessConstants(DS_ProcessSymbols(DS_ScriptArray(script,line)\lhs))
    rhs.s=DS_ProcessConstants(DS_ProcessSymbols(DS_ScriptArray(script,line)\rhs))
    
    r.s=DS_XS_Evaluate(rhs)
    l.s=DS_XS_Evaluate(lhs)
        
    If DS_IsNumeric(r) And DS_IsNumeric(l)
      If ValF(l)=ValF(r)
        ProcedureReturn 0
      Else 
        ProcedureReturn 1
      EndIf 
    Else
      If l=r
        ProcedureReturn 0
      Else 
        ProcedureReturn 1
      EndIf 
    EndIf 
  EndIf 
  
  If DS_ScriptArray(script,line)\operator=">="
    lhs.s=DS_ProcessConstants(DS_ProcessSymbols(DS_ScriptArray(script,line)\lhs))
    rhs.s=DS_ProcessConstants(DS_ProcessSymbols(DS_ScriptArray(script,line)\rhs))
    
    r.s=DS_XS_Evaluate(rhs)
    l.s=DS_XS_Evaluate(lhs)
    
    If DS_IsNumeric(r) And DS_IsNumeric(l)
      If ValF(l)>=ValF(r)
        ProcedureReturn 1
      Else 
        ProcedureReturn 0
      EndIf 
    Else
      If l>=r
        ProcedureReturn 1
      Else 
        ProcedureReturn 0
      EndIf 
    EndIf 
  EndIf 
  
  If DS_ScriptArray(script,line)\operator="<="
    lhs.s=DS_ProcessConstants(DS_ProcessSymbols(DS_ScriptArray(script,line)\lhs))
    rhs.s=DS_ProcessConstants(DS_ProcessSymbols(DS_ScriptArray(script,line)\rhs))
    
    r.s=DS_XS_Evaluate(rhs)
    l.s=DS_XS_Evaluate(lhs)
    
    If DS_IsNumeric(r) And DS_IsNumeric(l)
      If ValF(l)<=ValF(r)
        ProcedureReturn 1
      Else 
        ProcedureReturn 0
      EndIf 
    Else
      If l<=r
        ProcedureReturn 1
      Else 
        ProcedureReturn 0
      EndIf 
    EndIf 
  EndIf 
  
  If DS_ScriptArray(script,line)\operator=">"
    lhs.s=DS_ProcessConstants(DS_ProcessSymbols(DS_ScriptArray(script,line)\lhs))
    rhs.s=DS_ProcessConstants(DS_ProcessSymbols(DS_ScriptArray(script,line)\rhs))
    
    r.s=DS_XS_Evaluate(rhs)
    l.s=DS_XS_Evaluate(lhs)
    
    If DS_IsNumeric(r) And DS_IsNumeric(l)
      If ValF(l)>ValF(r)
        ProcedureReturn 1
      Else 
        ProcedureReturn 0
      EndIf 
    Else
      If l>r
        ProcedureReturn 1
      Else 
        ProcedureReturn 0
      EndIf 
    EndIf 
  EndIf 
  
  If DS_ScriptArray(script,line)\operator="<"
    lhs.s=DS_ProcessConstants(DS_ProcessSymbols(DS_ScriptArray(script,line)\lhs))
    rhs.s=DS_ProcessConstants(DS_ProcessSymbols(DS_ScriptArray(script,line)\rhs))
    
    r.s=DS_XS_Evaluate(rhs)
    l.s=DS_XS_Evaluate(lhs)
    
    If DS_IsNumeric(r) And DS_IsNumeric(l)
      If ValF(l)<ValF(r)
        ProcedureReturn 1
      Else 
        ProcedureReturn 0
      EndIf 
    Else
      If l<r
        ProcedureReturn 1
      Else 
        ProcedureReturn 0
      EndIf 
    EndIf 
  EndIf 
  
  If DS_ScriptArray(script,line)\operator="="
    lhs.s=DS_ProcessConstants(DS_ProcessSymbols(DS_ScriptArray(script,line)\lhs))
    rhs.s=DS_ProcessConstants(DS_ProcessSymbols(DS_ScriptArray(script,line)\rhs))
    
    r.s=DS_XS_Evaluate(rhs)
    l.s=DS_XS_Evaluate(lhs)
    
    If DS_IsNumeric(r) And DS_IsNumeric(l)
      If ValF(l)=ValF(r)
        ProcedureReturn 1
      Else 
        ProcedureReturn 0
      EndIf 
    Else
      If l=r
        ProcedureReturn 1
      Else 
        ProcedureReturn 0
      EndIf 
    EndIf 
  EndIf 
  
  DS_SetLastError("Syntax error: Invalid operator found in expression - '"+DS_ScriptArray(script,line)\line+"'")
  ProcedureReturn -1
EndProcedure

Procedure.b DS_DoJumpTable()
  ForEach DS_JumpList()
    If DS_Env\line = DS_JumpList()\src
      DS_Env\line = DS_JumpList()\dest 
      ProcedureReturn 1
    EndIf 
  Next 
  ProcedureReturn 0
EndProcedure

Procedure.b DS_Execute(script.l)
  If script < 0 Or script >= DS_Env\maxScripts Or DS_ScriptArray(script,0)\IsUsed=0
    ProcedureReturn #DS_RESULT_NOSCRIPT
  EndIf 
  ;ClearList(DS_SymbolList())
  ClearList(DS_JumpList())
  DS_Env\line=0
    
  While DS_ScriptArray(script,DS_Env\line)\IsLast=0         ; DS_Env\line <= DS_Env\linecount
    word.s=DS_ScriptArray(script,DS_Env\line)\word
    command.s=DS_ScriptArray(script,DS_Env\line)\command
    wordval=DS_ScriptArray(script,DS_Env\line)\wordval
           
    ;check if comment ";" or blank line
    If PeekS(@word,1)<>";" And DS_ScriptArray(script,DS_Env\line)\line<>""
      
      ;check logic and keywords
      If wordval=#DS_KEYWORD_EXIT
      	ProcedureReturn #DS_RESULT_SUCCESS
	      
      ElseIf wordval=#DS_KEYWORD_GOTO Or wordval=#DS_KEYWORD_LABEL
  	    If wordval=#DS_KEYWORD_GOTO
    	    DS_Env\line=Val(PeekS(@DS_ScriptArray(script,DS_Env\line)\line+4))
  	    EndIf 
    	  
  	  ElseIf wordval=#DS_KEYWORD_IF
DS_RestartIf:
  	    cond=DS_EvaluateConditional(script,DS_Env\line)
  	    If cond=-1
    	    ProcedureReturn #DS_RESULT_CONDITIONAL
    	  ElseIf cond=0
  	      If DS_DoJumpTable()=0     	  
    	      srcline=DS_Env\line
      	    Ifcount=0
        	  DS_Env\line + 1
        	  While 1
          	  target.l=DS_ScriptArray(script,DS_Env\line)\wordval
    	        
          	  If target=#DS_KEYWORD_IF
    	          Ifcount + 1
          	  EndIf 
          	  
          	  If target=#DS_KEYWORD_ELSEIF And Ifcount=0
            	  Goto DS_RestartIf
    	        ElseIf (target=#DS_KEYWORD_ELSE Or target=#DS_KEYWORD_ENDIF) And Ifcount=0 ;no need to increment since its done at end of function
        	      AddElement(DS_JumpList())
      	        DS_JumpList()\src=srcline
        	      DS_JumpList()\dest=DS_Env\line
      	        Break 
      	      ElseIf target=#DS_KEYWORD_ENDIF
        	      Ifcount - 1
    	        EndIf 
          	  
    	        DS_Env\line + 1
    	        If DS_ScriptArray(script,DS_Env\line)\IsLast
      	        DS_SetLastError("Syntax error: Expected 'ENDIF'")
        	      ProcedureReturn #DS_RESULT_NOENDIF
          	  EndIf     	      
    	      Wend
      	  EndIf  
    	  EndIf 
  	    
    	ElseIf wordval=#DS_KEYWORD_ELSEIF Or wordval=#DS_KEYWORD_ELSE
	      If DS_DoJumpTable()=0
      	  srcline=DS_Env\line
        	Ifcount=0
        	While 1
        	  target.l=DS_ScriptArray(script,DS_Env\line)\wordval
    	      
        	  If target=#DS_KEYWORD_IF
    	        Ifcount + 1
        	  EndIf 
    	      
        	  If target=#DS_KEYWORD_ENDIF And Ifcount=0 ;no need to increment since its done at end of function
          	  AddElement(DS_JumpList())
    	        DS_JumpList()\src=srcline
      	      DS_JumpList()\dest=DS_Env\line
  	          Break
          	ElseIf target=#DS_KEYWORD_ENDIF
  	          Ifcount - 1
        	  EndIf 
    	      
        	  DS_Env\line + 1
    	      If DS_ScriptArray(script,DS_Env\line)\IsLast
    	        DS_SetLastError("Syntax error: Expected 'ENDIF'")
        	    ProcedureReturn #DS_RESULT_NOENDIF
        	  EndIf   	      
  	      Wend 
      	EndIf 
  	  
  	  ElseIf wordval=#DS_KEYWORD_ENDIF
  	    ;do nothing
    	  
  	  ElseIf wordval=#DS_KEYWORD_WHILE
  	    exp.s=DS_ScriptArray(script,DS_Env\line)\exp
    	  cond=DS_EvaluateConditional(script,DS_Env\line)
  	    If cond=0
    	    If DS_DoJumpTable()=0
      	    srcline=DS_Env\line
      	    Whilecount=0
      	    DS_Env\line + 1
        	  While 1
          	  target.l=DS_ScriptArray(script,DS_Env\line)\wordval
    	        
          	  If target=#DS_KEYWORD_WHILE
    	          Whilecount + 1
          	  EndIf 
    	        
          	  If target=#DS_KEYWORD_WEND And Whilecount=0
    	          AddElement(DS_JumpList())
      	        DS_JumpList()\src=srcline
        	      DS_JumpList()\dest=DS_Env\line
            	  Break 
            	ElseIf target=#DS_KEYWORD_WEND
  	            Whilecount - 1
    	        EndIf 
          	  
    	        DS_Env\line + 1
    	        If DS_ScriptArray(script,DS_Env\line)\IsLast
      	        DS_SetLastError("Syntax error: Expected 'WEND'")
        	      ProcedureReturn #DS_RESULT_NOWEND
          	  EndIf     	      
    	      Wend 
      	  EndIf 
  	    EndIf 
    	  
  	  ElseIf wordval=#DS_KEYWORD_WEND
  	    If DS_DoJumpTable()=0
      	  srcline=DS_Env\line
      	  Wendcount=0
      	  DS_Env\line - 1
      	  While 1
        	  target.l=DS_ScriptArray(script,DS_Env\line)\wordval
  	        
          	If target=#DS_KEYWORD_WEND
  	          Wendcount + 1
          	EndIf 
          	
        	  If target=#DS_KEYWORD_WHILE And Wendcount=0
  	          DS_Env\line - 1 ;force eval of the while since we increment below
            	AddElement(DS_JumpList())
    	        DS_JumpList()\src=srcline
      	      DS_JumpList()\dest=DS_Env\line
            	Break 
  	        ElseIf target=#DS_KEYWORD_WHILE
          	  Wendcount - 1
  	        EndIf 
          	
  	        DS_Env\line - 1
  	        If DS_Env\line < 0
    	        DS_SetLastError("Syntax error: Expected 'WHILE'")
        	    ProcedureReturn #DS_RESULT_NOWHILE
        	  EndIf   	      
  	      Wend 
      	EndIf 
	      
  	  ElseIf wordval=#DS_KEYWORD_FREE
    	  DS_FreeSymbol(DS_ScriptArray(script,DS_Env\line)\sym)
    	  
      Else 
        
        If DS_IsCommand(command)=0
          ;preprocess symbol values into the expression
          sym.s=DS_ScriptArray(script,DS_Env\line)\sym
          exp.s=DS_ProcessConstants(DS_ScriptArray(script,DS_Env\line)\symexp)
          If exp=""
            DS_SetLastError("Syntax error: Expression expected or unknown command.")
            ProcedureReturn #DS_RESULT_NOTEXIST
          EndIf 
          
          exp=DS_ProcessSymbols(exp)          
          exp=DS_ProcessCommands(exp)
          
          If PeekS(@exp,Len(#DS_ERROR_STRING))=#DS_ERROR_STRING
            ProcedureReturn #DS_RESULT_COMMANDERROR
          EndIf
          
          ;symbol assignment/operation (a=b+c, etc)
          found=0
          ForEach DS_SymbolList()
            If DS_SymbolList()\name = sym
              tmp.s=DS_XS_Evaluate(exp)
              DS_SymbolList()\Value=tmp
              If DS_IsNumeric(tmp)=0
                DS_SymbolList()\type=#DS_TYPE_STRING
              Else
                DS_SymbolList()\type=#DS_TYPE_VALUE
              EndIf 
              found=1
              Break 
            EndIf 
          Next
          
          If found=0
            tmp.s=DS_XS_Evaluate(exp)
            If DS_IsNumeric(tmp)=0
              DS_SetSymbol(sym,tmp,#DS_TYPE_STRING)
            Else
              DS_SetSymbol(sym,tmp,#DS_TYPE_VALUE)
            EndIf             
          EndIf 
                    
          If PeekS(@tmp,Len(#DS_ERROR_STRING))=#DS_ERROR_STRING
            DS_SetLastError("Expression evaluation error in: "+DS_ScriptArray(script,DS_Env\line)\symexp)
            ProcedureReturn #DS_RESULT_MATH
          EndIf 
        Else 
          ;try To execute as command
          params.s=DS_ProcessSymbols(DS_ScriptArray(script,DS_Env\line)\params)
          params.s=DS_ProcessCommands(params)
          res=DS_CallCommand(command,params)
          If res<>#DS_RESULT_SUCCESS
            ProcedureReturn res
          EndIf 
        EndIf 
        
      EndIf 
      
    EndIf
        
    ;increment program counter
    DS_Env\line + 1
  Wend 
  ProcedureReturn #DS_RESULT_SUCCESS
EndProcedure


CompilerIf #DS_INCLUDE_DEFAULT=1
  IncludeFile "./DracScript_Default.pb"
CompilerEndIf


;----------------------------------------------------------------------------------------------------


CompilerIf #DS_TEST_MATHSPEED=1
  ;Test evaluation algorithm speed
  ex.s="100+1"
  startms=ElapsedMilliseconds()
  For i=1 To 100000
    DS_XS_Evaluate(ex)
  Next 
  MessageRequester("100,000 Additions: Total (ms)",Str(ElapsedMilliseconds()-startms))
CompilerEndIf

CompilerIf #DS_TEST_BUILD=1


  ;PROCEDURES FOR TESTING
  Procedure.b DS_DEFAULT_MessageBox() ; 2 params
    SelectElement(DS_StackList(),0)
    *param1.DS_SYMBOL=@DS_StackList()
    SelectElement(DS_StackList(),1)
    *param2.DS_SYMBOL=@DS_StackList()
    
    ;test the param type (not required for this function)
    ;If *param1\type<>#DS_TYPE_VALUE Or *param2\type<>#DS_TYPE_STRING
    ;  ProcedureReturn 0
    ;EndIf 
    
    ;show the output window and wait for continue
    If IsWindow(999)=0
      OpenWindow(999,0,0,300,200,#PB_Window_TitleBar|#PB_Window_ScreenCentered,"DracScript Tester")
      CreateGadgetList(WindowID(999))
      ListViewGadget(991,0,0,300,180)
      ButtonGadget(990,0,181,149,19,"Continue")
      ButtonGadget(992,151,181,149,19,"Quit")
    EndIf 
    AddGadgetItem(991,-1,"Param1: "+*param1\Value)
    AddGadgetItem(991,-1,"Param2: "+*param2\Value)
    AddGadgetItem(991,-1,"Current line: "+Str(DS_Env\line+1))
    AddGadgetItem(991,-1,"-------------------")
    Repeat
      event=WaitWindowEvent()          
      If event=#PB_Event_Gadget And EventGadgetID()=992
        End 
      EndIf 
    Until event=#PB_Event_Gadget And EventGadgetID()=990
    
    ;return now
    DS_Return("",#DS_TYPE_NULL)
    ProcedureReturn 1  
  EndProcedure

  ;MAIN FUNC
  If DS_RegisterCommand(@DS_DEFAULT_MessageBox(),"MessageBox",2)=0
    MessageRequester("","Failed to register")
  EndIf
   
  If DS_RegisterDefault()=0
    MessageRequester("","Failed to register default command set")
  EndIf 
  
  ;Test individual commands
  If DS_SetSymbol("Yo","WEeeeoooo",#DS_TYPE_STRING)=0
    MessageRequester("","Failed to set symbol")
  EndIf 
  
  If DS_RegisterConstant("TEST_MESSAGE","'Yo bro!'")=0
    MessageRequester("","Failed to register constant")
  EndIf
  
  If DS_RegisterConstant("TEST_VALUE","2")=0
    MessageRequester("","Failed to register constant")
  EndIf
  
  ;Test script execution from file
  file.s=OpenFileRequester("Open a script file to test...","","DS Files|*.ds",0)
  If file<>""
    DS_Initialize(3,100)
    DS_Reset(0,1,1,0,1)
    
    scriptnum=DS_LoadScriptFile(file,0,-1)    
    startms=ElapsedMilliseconds()
    r=DS_Execute(scriptnum)
    If r<>#DS_RESULT_SUCCESS
      MessageRequester("Error type: "+Str(r),"Error in script. Line: "+Str(DS_Env\line+1)+Chr(13)+Chr(10)+DS_GetLastError())
      If IsWindow(999)
        Repeat
          event=WaitWindowEvent()          
          If event=#PB_Event_Gadget And EventGadgetID()=992
            End 
          EndIf 
        ForEver
      EndIf 
    Else
      MessageRequester("Total run time:",Str(ElapsedMilliseconds()-startms)+" ms.")
    EndIf 
  EndIf 
  
  End 
  
CompilerEndIf
Now, in order to add script defined constants, instead of program defined constants, would it be possible to ...

When going line by line in the script, we look for a Left(Text, 1) = "#", then we do a split on = and left side is script name, while right side is value. Thus basically a global non-modifiable variable?

But would need to be script specific, or we could have a global constant ... hmm, possiblities, oh the fun!
Post Reply