Recent posts

#71
OxygenBasic / The deprecation of mode64bit /...
Last post by Charles Pegge - June 27, 2024, 01:38:36 PM
OxygenBasic comes with 2 compilers: co2.exe is native 32bit, and co2m64.exe is native 64bit. Both compilers can produce 32 or 64 bit binaries, but when executing code directly they are confined to their native bitness, and do not set mode64bit or mode32bit flags.

To resolve this issue the best way to test for 32/64 bit is to test the width of the sys type:

#if sizeof sys = 8
  ...
#else 'sizeof sys = 4
  ...
#endif

I found that about 20 files in the OxygenBasic package teste the mode64bit flag, so I have changed these files to use this new test instead in the latest update.


#72
OxygenBasic Examples / String Speed test
Last post by Frank Brübach - June 27, 2024, 01:11:25 PM
Hello all..

Made this little String Speed test. Hope its running perfect..

If there are any Things to optimate  or improve the Code please say

' timer example for a speed test with strings
' oxygen, 27-06-2024, by frank bruebach

uses timeutil

'---Variables declaration
dim strMaxCount  as string
strmaxCount = 1e7 '10000000  ''1e7 => 10 million

SYSTEMTIME   amyTime0
SYSTEMTIME   amyTime1

'---Start time
GetSystemTime amyTime0

'---Dimension the array
redim string MyArray(strMaxCount)

dim count as long
strMaxCount += " test string  "

'---Fill the array
for Count = lbound(strMaxCount) to ubound(strMaxCount)
  MyArray(Count) = Count*Count '^2
next

'---End time
GetSystemTime amyTime1

print len(strMaxCount) ' 22
' format() and str() same results

print "total time to fill an EXT array of strings " + strMaxCount + " elements: " + str(TimeLapseMs(amyTime0,amyTime1), "###") + " msecs"

' result 907 msec
wait



#73
General Discussion / Bad news for dark matter
Last post by Charles Pegge - June 27, 2024, 12:46:37 PM
Bad news for dark matter: This data doesn't fit at all

Sabine Hossenfelder

#74
OxygenBasic Examples / Re: Parser example and questio...
Last post by Charles Pegge - June 26, 2024, 09:42:21 PM
This is fairly new syntax to support the passing of dynamic array attributes locally.

If the tokens(redim) param is removed from the split() prototype, it will be handled directly as the global dynamic array defined at the start of the program.

Function Split(string inputs, delimiter, *tokens(redim) ) As Integer
#75
OxygenBasic Examples / Re: Parser example and questio...
Last post by Frank Brübach - June 26, 2024, 07:34:10 PM
Hello Charles thanks for fixing my example.

But *tokens(redim)  seems to be new command or function for me. I am using oxygen issue of Begin march and this example does Run only in latest build so I suppose you included this new construct in one of a newer issue. Nevertheless its a good Idea to simplify These Things  thx

 
#76
OxygenBasic Examples / Re: Parser example and questio...
Last post by Charles Pegge - June 26, 2024, 01:58:04 PM
Hi Frank,
I have marked my changes '***'

' test of my parser example of freebasic (its running fine there)
' to oxygen by frank bruebach, 24-06 + 25-06-2024
'
uses console
indexbase 0 '*** same as freebasic

' test -------------------------
'dim tokens() as string '*** comment out
Dim token As String = ""
Dim tokenCount As Integer = 0 '
ReDim string tokens(tokenCount) '
' test -------------------------

printl "ok"   


' Split() function ' may be an error inside cause of tokens() ?
Function Split(string inputs, delimiter, *tokens(redim) ) As Integer '***  *tokens(redim)
    Dim token As String = ""
    Dim tokenCount As Integer = 0
    redim string tokens(100) '*** temp amount
    int i
    For i = 1 To Len(inputs)
        If Mid(inputs, i, 1) = delimiter Then
            If token <> "" Then
                'ReDim Preserve tokens(0 To tokenCount)
                'ReDim string tokens(tokenCount) 'redim string s(n) '*** take out
                tokens(tokenCount) = token
                tokenCount += 1
                token = ""
            End If
        Else
            token += Mid(inputs, i, 1)
        End If
    Next
    If token <> "" Then
        ReDim string tokens(tokenCount) 'trims excess elements
        tokens(tokenCount) = token
    End If

    Return tokenCount
End Function

printl "ok2"

' IsNumeric() function ok
Function IsNumeric(string value ) As Integer
    Static string numericChars
    numericChars = "0123456789.-"
    If Len(value) = 0 Then Return False
    int i
    int dotCount = 0
    For i = 1 To Len(value)
        string c = Mid(value, i, 1)
        If InStr(numericChars, c) = 0 Then
            Return False
        ElseIf c = "." Then
            dotCount += 1
            If dotCount > 1 Then
                Return False
            End If
        End If
    Next
    Return True
End Function

printl "ok3"

' new build in: EvaluateExpression function
' error inside split() functions
'
Function EvaluateExpression(string inputs) As Double
    'Dim tokens() As String '*** comment out

'------------------ problem zone 1 ------------ //
    Split(inputs," ", tokens()) '*** ok now
'------------------ problem zone 1 ------------ //
    Dim total As Double = 0
    Dim currentNumber As Double = 0
    Dim operators As String = "+"
    int i
    For i = 0 To UBound(tokens)
        Dim token As String = tokens(i)

        If IsNumeric(token) Then
            currentNumber = Val(token)
            If operators = "+" Then
                total += currentNumber
            ElseIf operators = "-" Then
                total -= currentNumber
            ElseIf operators = "*" Then
                total *= currentNumber
            ElseIf operators = "/" Then
                If currentNumber <> 0 Then
                    total /= currentNumber
                Else
                    Print "Error: Division by zero"
                    Exit For
                End If
            End If
            operators = "+"
        Else
            operators = token
        End If
    Next

    Return total
End Function

printl "ok4"


' Test my code with different inputs
Dim inputs As String = "2 + 3 * 10" ' 50 result ok
Dim result As Double

'------------------------ problem zone 2 ------------- //
result = EvaluateExpression(inputs) ' error '*** uncommented, ok now
'------------------------ problem zone 2 ------------- //

' all tests are running fine here for calculations
' + - * /
' Test my code with different inputs
' Dim inputs As String = "2 + 3 * 10" ' 50 ok
' Dim inputs As String = "5 + 6 + 10" ' 21 ok
' Dim inputs As String = "8 * 5" ' 40 ok
' Dim inputs As String = "20 / 4 " ' 5 ok
' Dim inputs As String = "-20 10" ' -10 ok
' Dim inputs As String = "-10  20" ' ok
 Dim inputs As String = "30 -20" ' 10 ok


If result <> 0 Then
    Printl "The total is " + result
Else
    Printl "Error: Invalid input"
End If

printl result 'test was 0

' Wait for a key press before closing the console
Printl "Press any key to continue..."
'Sleep
wait
'While Inkey <> "" : Wend

print "ok5" '*** comment out
#77
OxygenBasic / Re: sprintf / sprintf_s in 64-...
Last post by Charles Pegge - June 26, 2024, 10:12:35 AM
Many thanks Roland, I will include it in demos\WinGui

It should be possible to edit using 'Quick Edit' or 'More'--> Modify' if these are visible to you. I have made the change for you.

PS:
a format function is available in parseutil.inc

uses parseutil
...
print format(num,"###.00") cr
#78
OxygenBasic / Re: sprintf / sprintf_s in 64-...
Last post by Roland Stowasser - June 26, 2024, 03:56:27 AM
Is it not possible any more to edit a reply? There are two lines in the code which I forgot to delete:

it should read:

...
function WndProc(sys hwnd, uMsg, wParam, lParam) as sys callback
 
    select uMsg
...
#79
OxygenBasic / Re: sprintf / sprintf_s in 64-...
Last post by Roland Stowasser - June 26, 2024, 02:45:21 AM
Hi Charles,

It took me some time to create a small demo that should show the advantages of sprintf over str(). Line 233 - 238 use sprintf. If try to use str() I will not achieve the desired result,. Therefore sprintf is a very useful formating feature and I think it is used in several programming languages, among other functions of msvcrt.dll. But perhaps you can adapt str()?

I am still hesitating to apply the quad approach. In 32-bit I do not need this, it even works without prototyping. Therefore I apply prototyping only in 64-bit. Is there a side effect that speaks against it? The best solution would actually be to carry out prototyping directly from time to time with the variadic functions in msvcrt.dll, as this is obviously very possible in Oxygenbasic. But I would of course like to use the original .inc files, so I will not change them.

Amort-Demo.o2bas:

' ************************************************
'  Adapted from: Amort.bas by Kevin Diggins(MrBCX)
'  ported to Oxygenbasic (simplified)     
' ************************************************
'  AMORT is a small loan amortization program 
' ************************************************

$ filename "Amort-Demo.exe"

'uses rtl32
'uses rtl64

uses winutil

#ifdef mode64bit
! sprintf lib "msvcrt.dll" (char *buffer, const char *format, ...) as sys
#endif

typedef sys control

% DS_MODALFRAME=128
% SS_NOTIFY = 256
% SS_LEFT = 0

% LVS_EX_GRIDLINES 1 
% LVS_EX_FULLROWSELECT  0x0020
% LVM_SETEXTENDEDLISTVIEWSTYLE 0x1036
% LVCF_TEXT=4
% LVM_SETCOLUMN = 4122
% LVM_SETCOLUMNWIDTH=4126
% LVSCW_AUTOSIZE  -1
% LVSCW_AUTOSIZE_USEHEADER = -2
% LVM_DELETEALLITEMS = 4105
% LVIF_TEXT=1
% LVM_INSERTITEM=4103
% LVCF_FMT 1
% LVCF_WIDTH 2
% LVCF_SUBITEM 8
% LVCFMT_LEFT = 0
% LVM_INSERTCOLUMN = 4123
% LVS_REPORT = 1
% LVS_SHAREIMAGELISTS = 64
% LVS_EDITLABELS = 512
% LVM_SETITEMTEXT = 4142


% HDI_FORMAT = 4
% HDF_STRING = 16384
% HDM_SETITEM = 4612
% HDF_LEFT = 0
% HDF_RIGHT = 1


type LVCOLUMN
  uint  mask
  int   fmt
  int   cx
  char* pszText
  int   cchTextMax
  int   iSubItem
  int   iImage
  int   iOrder
  int   cxMin
  int   cxDefault
  int   cxIdeal 
end type
typedef LVCOLUMN LV_COLUMN

type LVITEM 
  uint   mask
  int    iItem
  int    iSubItem
  uint   state
  uint   stateMask
  char*  pszText
  int    cchTextMax
  int    iImage       // index of the list view item's icon
  sys    lParam       // 32-bit value to associate with item
  int    iIndent
  int    iGroupId
  uint   cColumns
  uint   *puColumns
  int    *piColFmt
  int    iGroup
end type
typedef LVITEM LV_ITEM

type HDITEM 
  uint     mask 
  int      cxy
  char*    pszText
  sys      hbm
  int      cchTextMax
  int      fmt
  sys      lParam
  int      iImage
  int      iOrder
'#if (_WIN32_IE >= 0x0500)
  uint     type_    'type
  sys      pvFilter 'LPVOID
'#endif /* _WIN32_IE >= 0x0500 */
'#if (_WIN32_WINNT >= 0x0600)
  uint     state
'#endif /* _WIN32_WINNT >= 0x0600 */ 
end type
typedef HDITEM HD_ITEM


macro ListView_DeleteAllItems(hwnd) (SendMessage(hwnd, LVM_DELETEALLITEMS, 0, 0))
macro ListView_InsertItem(hwnd,pitem) (SendMessage(hwnd, LVM_INSERTITEM,0, pitem))
macro ListView_InsertColumn(hwnd,iCol,pcol) (SendMessage(hwnd, LVM_INSERTCOLUMN, iCol, pcol))
macro ListView_SetItemText(hwnd,i,iSubItem_,pszText_) 
  LV_ITEM _ms_lvi
  _ms_lvi.iSubItem = iSubItem_
  _ms_lvi.pszText = pszText_
  SendMessage((hwnd),LVM_SETITEMTEXT, i, &_ms_lvi)
end macro 

    ' create a structure of INITCOMMONCONTROLSEX
    INITCOMMONCONTROLSEXt iccex
    iccex.dwSize=sizeof(iccex)
    'Register Common Controls
    iccex.dwICC= 0xffff
    InitCommonControlsEx(&iccex)

GLOBAL Input1  AS CONTROL
GLOBAL Input2  AS CONTROL
GLOBAL Input3  AS CONTROL
GLOBAL Label1  AS CONTROL
GLOBAL Label2  AS CONTROL
GLOBAL Label3  AS CONTROL
GLOBAL Label4  AS CONTROL
GLOBAL Button1 AS CONTROL
GLOBAL LView1  AS CONTROL

SUB Set_ColumnText(ByVal hWnd AS sys, ByVal Column as int, ByVal Text$ as string)
   LOCAL lvc AS LV_COLUMN
   lvc.mask = LVCF_TEXT
   lvc.pszText = Text$
   SendMessage(hWnd, LVM_SETCOLUMN, Column, &lvc)
   SendMessage(LView1, LVM_SETCOLUMNWIDTH, Column, LVSCW_AUTOSIZE_USEHEADER)
END SUB

SUB LV_Reset(ByVal LView AS CONTROL, ByVal Columns as int, ByVal Rows as int)
   LOCAL lvItem AS LV_ITEM
   LOCAL i as int
   ListView_DeleteAllItems(LView)
   for i = 1 to Rows
     lvItem.mask = LVIF_TEXT
     lvItem.pszText = " "
     lvItem.iSubItem = 0
     ListView_InsertItem(LView1, &lvItem)
   next   
END SUB

SUB LV_Justify(ByVal LV AS sys, ByVal Column as int , ByVal JustifyType as int)
   LOCAL hHeader AS LONG
   LOCAL hdi AS HD_ITEM
   '*******************************************
   % HDF_LEFT = 0    'JustifyType
   % HDF_RIGHT = 1    'JustifyType
   % HDF_CENTER = 2    'JustifyType
   '*******************************************
   % LVM_FIRST = 4096
   % LVM_GETHEADER = LVM_FIRST + 31
   '*******************************************
   hHeader = SendMessage(LV, LVM_GETHEADER, 0, 0)
   hdi.mask = HDI_FORMAT
   hdi.pszText = " "
   hdi.fmt = HDF_STRING OR JustifyType
   SendMessage(hHeader, HDM_SETITEM, Column, &hdi)
END SUB

FUNCTION INTEREST_PAYMENT(ByVal i AS DOUBLE, ByVal Balance AS DOUBLE) AS DOUBLE
   FUNCTION =(i/12/100) * Balance
END FUNCTION
   
FUNCTION Payment(ByVal i AS DOUBLE, ByVal np AS DOUBLE, ByVal pv AS DOUBLE, ByVal fv AS DOUBLE) AS DOUBLE
   DIM q1 AS DOUBLE
   DIM ir AS DOUBLE
   ir = i / 12 / 100
   q1 = POW(1 + ir, np)
   FUNCTION =((ir *(fv + q1 * pv))/(-1 + q1))
END FUNCTION

function Set_Text(sys hWnd, string Text) as int
  return SetWindowText(hWnd,Text)
end function

function Get_Text(sys hWnd) as string
  int tmpint
  tmpint = 1 + GetWindowTextLength(hWnd)
  static string strtmp = nuls * 1024
  GetWindowText(hWnd, strtmp, tmpint) 
  return strtmp
end function


SUB FillListView() 
   '==========================
   DIM Amount AS DOUBLE
   DIM Interest AS DOUBLE
   DIM Years AS DOUBLE
   DIM Pmt AS DOUBLE
   DIM Int_Payment AS DOUBLE
   DIM Prin_Payment AS DOUBLE
   DIM lvItem AS LV_ITEM
   DIM SumPrinc AS DOUBLE
   DIM SumInt AS DOUBLE
   DIM z AS int
   char buff[32]
   '==========================
 
   Amount =   VAL(GET_TEXT(Input1))
   Interest = VAL(GET_TEXT(Input2))
   Years =    VAL(GET_TEXT(Input3))
   Pmt = Payment(Interest, Years * 12, Amount, 0)
 
   LV_Reset(LView1, 4, Years * 12)
 
   Set_ColumnText(LView1, 0, "Payment")
   Set_ColumnText(LView1, 1, "Interest")
   Set_ColumnText(LView1, 2, "Principal")
   Set_ColumnText(LView1, 3, "Balance")
 
   FOR z = 1 TO Years * 12
     Int_Payment = INTEREST_PAYMENT(Interest, Amount)
     Prin_Payment = Pmt - INTEREST_PAYMENT(Interest, Amount)
     SumPrinc = SumPrinc + Prin_Payment
     SumInt = SumInt + Int_Payment
     string z1=str(z)
     ListView_SetItemText(LView1, z - 1, 0, z1)
     sprintf(buff, "%0.2lf", Int_Payment)
     ListView_SetItemText(LView1, z - 1, 1, buff)     
     sprintf(buff, "%.2f", Prin_Payment)
     ListView_SetItemText(LView1, z - 1, 2, buff)
     Amount = Amount - Prin_Payment
     sprintf(buff, "%.2f", Amount)
     ListView_SetItemText(LView1, z - 1, 3, buff)
   NEXT
 
   ListView_SetItemText(LView1, z, 3, " ")  ' add a line at the bottom
 
   FOR z = 0 TO 3
     SendMessage(LView1, LVM_SETCOLUMNWIDTH, z, LVSCW_AUTOSIZE_USEHEADER)
   NEXT
 
   LV_Justify(LView1, 0, HDF_LEFT)
   LV_Justify(LView1, 1, HDF_RIGHT)
   LV_Justify(LView1, 2, HDF_RIGHT)
   LV_Justify(LView1, 3, HDF_RIGHT)
 
   SET_TEXT(Label3, str(SumPrinc,2))
   SET_TEXT(Label4, str(SumInt,2))
END SUB

******************************************************************************

sys hInstance=inst
MainWindow 400,460, DS_MODALFRAME OR WS_POPUP OR WS_CAPTION OR WS_SYSMENU

function WndProc(sys hwnd, uMsg, wParam, lParam) as sys callback
 
    select uMsg
    case WM_CREATE
        SetWindowText(hwnd, "Amortization Schedule in Oxygenbasic")

        Input1=CreateWindowEx(WS_EX_CLIENTEDGE,"edit","8000",WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_LEFT | ES_AUTOHSCROLL, 272,  6, 92, 28, hwnd,0,hinstance,0)
        Input2=CreateWindowEx(WS_EX_CLIENTEDGE,"edit","9.25",WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_LEFT | ES_AUTOHSCROLL, 272, 36, 92, 28, hwnd,0,hinstance,0)
        Input3=CreateWindowEx(WS_EX_CLIENTEDGE,"edit","3",WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_LEFT | ES_AUTOHSCROLL, 272, 66, 92, 28, hwnd,0,hinstance,0)
        Label1=CreateWindowEx(0,"static","Principal",WS_CHILD | SS_NOTIFY | SS_LEFT | WS_VISIBLE, 10, 104, 80, 28, hwnd,0,hinstance,0)
        Label2=CreateWindowEx(0,"static","Interest",WS_CHILD | SS_NOTIFY | SS_LEFT | WS_VISIBLE,  10, 130, 80, 28, hwnd,0,hinstance,0)
        Label3=CreateWindowEx(0,"static","",WS_CHILD | SS_NOTIFY | SS_LEFT | WS_VISIBLE, 100, 104, 80, 28, hwnd,0,hinstance,0)
        Label4=CreateWindowEx(0,"static","",WS_CHILD | SS_NOTIFY | SS_LEFT | WS_VISIBLE, 100,130, 80, 28, hwnd,0,hinstance,0)
        Button1=CreateWindowEx(WS_EX_STATICEDGE,"button","Calc",WS_CHILD | WS_VISIBLE | BS_MULTILINE | BS_PUSHBUTTON | WS_TABSTOP, 280,104, 80, 28, hwnd, 101, hinstance, 0)

        LV_COLUMN lvCol =
            { LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM, LVCFMT_LEFT, 65, "", 0, 0 }
        LView1=CreateWindowEx(WS_EX_CLIENTEDGE,"SysListView32",0,WS_CHILD | WS_TABSTOP |
                                         WS_VISIBLE | LVS_REPORT |
                                         LVS_SHAREIMAGELISTS | LVS_EDITLABELS | WS_BORDER, 10, 160, 300, 246, hwnd, 0, hinstance, 0)
        int Style=LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT
        SendMessage(LView1, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, Style)
        lvCol.iSubItem=0
        while lvCol.iSubItem<15
           ListView_InsertColumn(LView1, 0, lvCol)
           lvCol.iSubItem+=1     
        wend

        CreateWindowEx(0,"static","Loan Amount",  WS_CHILD | SS_NOTIFY | SS_LEFT | WS_VISIBLE, 10, 14, 126, 22, hwnd,0,hinstance,0)
        CreateWindowEx(0,"static","Interest Rate",WS_CHILD | SS_NOTIFY | SS_LEFT | WS_VISIBLE, 10, 44, 126, 22, hwnd,0,hinstance,0)
        CreateWindowEx(0,"static","No. of Years", WS_CHILD | SS_NOTIFY | SS_LEFT | WS_VISIBLE, 10, 72, 192, 22, hwnd,0,hinstance,0)

        Set_ColumnText(LView1, 0, "Payment")
        Set_ColumnText(LView1, 1, "Interest")
        Set_ColumnText(LView1, 2, "Principal")
        Set_ColumnText(LView1, 3, "Balance")
               
        SetFocus(Input1)
        RedrawWindow(hwnd)
        ShowWindow(hwnd)

    case WM_COMMAND
        if LOWORD(wParam) = 101 then 'Calc
           FillListView()
        end if   

    case WM_CLOSE
        DestroyWindow(hwnd)
           
    case WM_DESTROY
        PostQuitMessage(0)
           
    case else
        return DefWindowProc(hwnd, uMsg, wParam, lParam)

    end select

    return 0
end function

#80
OxygenBasic Examples / Parser example and question
Last post by Frank Brübach - June 25, 2024, 11:47:09 PM
Hello Charles..

Perhaps you can Help to Fix my freebasic Translation to oxygen. My freebasic example is running fine.

I am Not quite Sure how to handle String Tokens() and my Error or Problem zones I have marked in my o2 example. Thanks in advance, frank


' test of my parser example of freebasic (its running fine there)
' to oxygen by frank bruebach, 24-06 + 25-06-2024
'
uses console

' test -------------------------
dim tokens() as string
Dim token As String = ""
Dim tokenCount As Integer = 0 '
ReDim string tokens(tokenCount) '
' test -------------------------

printl "ok"   


' Split() function ' may be an error inside cause of tokens() ?
Function Split(string inputs, delimiter, tokens() ) As Integer
    Dim token As String = ""
    Dim tokenCount As Integer = 0
    int i
    For i = 1 To Len(inputs)
        If Mid(inputs, i, 1) = delimiter Then
            If token <> "" Then
                'ReDim Preserve tokens(0 To tokenCount)
                ReDim string tokens(tokenCount) 'redim string s(n)
                tokens(tokenCount) = token
                tokenCount += 1
                token = ""
            End If
        Else
            token += Mid(inputs, i, 1)
        End If
    Next
    If token <> "" Then
        ReDim string tokens(tokenCount)
        tokens(tokenCount) = token
    End If

    Return tokenCount
End Function

printl "ok2"

' IsNumeric() function ok
Function IsNumeric(string value ) As Integer
    Static string numericChars
    numericChars = "0123456789.-"
    If Len(value) = 0 Then Return False
    int i
    int dotCount = 0
    For i = 1 To Len(value)
        string c = Mid(value, i, 1)
        If InStr(numericChars, c) = 0 Then
            Return False
        ElseIf c = "." Then
            dotCount += 1
            If dotCount > 1 Then
                Return False
            End If
        End If
    Next

    Return True
End Function

printl "ok3"

' new build in: EvaluateExpression function
' error inside split() functions
'
Function EvaluateExpression(string inputs) As Double
    Dim tokens() As String

'------------------ problem zone 1 ------------ //
    Split(inputs," ", tokens())
'------------------ problem zone 1 ------------ //

    Dim total As Double = 0
    Dim currentNumber As Double = 0
    Dim operators As String = "+"
    int i
    For i = 0 To UBound(tokens)
        Dim token As String = tokens(i)

        If IsNumeric(token) Then
            currentNumber = Val(token)
            If operators = "+" Then
                total += currentNumber
            ElseIf operators = "-" Then
                total -= currentNumber
            ElseIf operators = "*" Then
                total *= currentNumber
            ElseIf operators = "/" Then
                If currentNumber <> 0 Then
                    total /= currentNumber
                Else
                    Print "Error: Division by zero"
                    Exit For
                End If
            End If
            operators = "+"
        Else
            operators = token
        End If
    Next

    Return total
End Function

printl "ok4"


' Test my code with different inputs
Dim inputs As String = "2 + 3 * 10" ' 50 result ok
Dim result As Double

'------------------------ problem zone 2 ------------- //
' result = EvaluateExpression(inputs) ' error
'------------------------ problem zone 2 ------------- //

' all tests are running fine here for calculations
' + - * /
' Test my code with different inputs
' Dim inputs As String = "2 + 3 * 10" ' 50 ok
' Dim inputs As String = "5 + 6 + 10" ' 21 ok
' Dim inputs As String = "8 * 5" ' 40 ok
' Dim inputs As String = "20 / 4 " ' 5 ok
' Dim inputs As String = "-20 10" ' -10 ok
' Dim inputs As String = "-10  20" ' ok
 Dim inputs As String = "30 -20" ' 10 ok 


If result <> 0 Then
    Printl "The total is " + result
Else
    Printl "Error: Invalid input"
End If

printl result 'test was 0

' Wait for a key press before closing the console
Printl "Press any key to continue..."
'Sleep
wait
'While Inkey <> "" : Wend

print "ok5"