News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Solving expressions

Started by RuiLoureiro, December 11, 2010, 06:58:37 PM

Previous topic - Next topic

jj2007

Quote from: qWord on December 12, 2010, 09:24:21 PM
Quote from: jj2007 on December 12, 2010, 07:24:45 AMMaybe we could PM each other to exchange ideas and sources?
:thumbu, check your PMs

Thanks, impressive :U

qWord

Quote from: jj2007 on December 12, 2010, 10:24:45 PM
Thanks, impressive :U
thx  :bg
however, it is not 100% finish (but usable).

BTW: REAL10-var's also work after calling
fSlvSetGlbPrecision <REAL10>
or using the macro fSlv10
FPU in a trice: SmplMath
It's that simple!

RuiLoureiro

Hi Dave,
      I dont want to work in twos's complement but in sign-amplitude
      we need two variables (not only one): _Sign and _Value
      _Value can be any 32 bit value
      With two's complement we use only 31 bits for value and 1 bit for signal
      and we need only one variable, but i dont want this.

      Did you try Calcula12 ? Does it work as expected ?

      This is my procedure to solve any expression without ():

Quote
ResolveIt       proc

                mov     esi, offset _TblOperation
                xor     ebx, ebx

    _loop1:     mov     edi, offset _TblOperand
                mov     edx, dword ptr [esi + ebx*4]
                cmp     edx, 3          ; 1=Sub(-) 2=Add(+) 3=Mul(*) 4=Div(/) 5=Rem(\)
                jb      short _next1
                ;
                push    ebx
                    shl     ebx, 4
                    invoke  OperationAB,[edi + ebx + $SIGN1$], [edi + ebx + $OPR1$],
                                        [edi + ebx + $SIGN2$], [edi + ebx + $OPR2$], edx
                pop     ebx
                jc      _end

                mov     dword ptr [esi + ebx*4], 0

                call    SaveAntRes
                call    SaveNxtRes
                jnc     short _next1
                ;
                cmp     _NoAnt, 0
                je      _Ok                 ; END
                ;
    _next1:     add     ebx, 1
                cmp     ebx, dword ptr [esi - 4]
                jb      short _loop1

    ;---***---***---***---
     
                xor     ebx, ebx

    _loop2:     mov     edi, offset _TblOperand
                mov     edx, dword ptr [esi + ebx*4]
                cmp     edx, 0
                je      short _next2
                ;
                push    ebx
                    shl     ebx, 4
                    invoke  OperationAB,[edi + ebx + $SIGN1$], [edi + ebx + $OPR1$],
                                        [edi + ebx + $SIGN2$], [edi + ebx + $OPR2$], edx                   
                pop     ebx
                jc      _end
               
                call    SaveNxtRes
                jnc     short _next2
                ;
                ; END
                ; »»»
    _Ok:        invoke  ToRclCnv, SignW, OperandW, addr ResultZ
                clc
                ret
                ;
    _next2:     add     ebx, 1
                cmp     ebx, dword ptr [esi - 4]
                jb      short _loop2
                ; »»»»»»»»»»»»»»»»»»
                ; It cannot end here
                ; »»»»»»»»»»»»»»»»»»
                call    SetError2
                stc   
    _end:       ret
ResolveIt       endp

qWord

hi RuiLoureiro,

maybe an bug or simply an limit?:
(1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1)=ERROR

qWord
FPU in a trice: SmplMath
It's that simple!

RuiLoureiro

#19
Quote from: qWord on December 13, 2010, 05:31:47 PM
hi RuiLoureiro,

maybe an bug or simply an limit?:
(1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1)=ERROR
qWord
Hi qWord,
                   First, thank you
                   It is a limit of 20 operations if im correct
                   But i can change the table to operate with 500 or 1000... operations
                   The tables are defined to use only 20 operations

                       dd 20
                       dd 0                        <-- current number of operations
_TblOperation   dd 20 dup (?)


now works till 200 operations inside brackets


EDIT:
To solve this:          -2 + (-2* (12 - 3*5) + 23 ) + 5

the 1ª expression is:   -2+(-2*(12-3*5)+23)+5   
and we calculate:               12-3*5         (= @ )              @=-3

now, the expression is: -2+(-2*@+23)+5   
and we calculate:           -2*@+23            (= @ )              @=29

now, the expression is: -2+@+5
at last the result is:   32

When we try to find an operand or an operator we need to test to find @
When we solve an expression with () we replace it with @
This is my linear method  :green2

RuiLoureiro

Till now anything OK

the method used:
         
                    1- Read expression to _BufferX
                    2- Copy _BufferX to _BufferY and remove spaces and get
                       the buffer length Y
                       If we find @ than ERROR (this is used inside to replace...)
                       
                    3- Scan _BufferY from right to left to find an expression
                       inside brackets - try to find first ")" and than "("
                       If not, exit to 6
                    4- Copy the expression to a WorkBuffer and than call
                       the procedure SolveExpress
                    5- Save the result on _BufferAT (from top to bottom)
                       Replace the expression by @
                       Start again until we have not brackets
                    6- Call SolveExpress to solve the last expression in _BufferY

                    SolveExpress: build 2 tables: operations and operands
                                  whenever we find @, from bottom to top,
                                  get the values from _BufferAT;
                                  If it is a constant, convert it
                                  When we have the tables, call ResolveIt
                                   
                    Note that the expression is solved from left to right
                         while we scan _BufferY from right to left;
                         We move values to _BufferAT from top to bottom
                         and retrieve from bottom to top.

If _BufferY="-(5-3)+2*((5-3)+2*(3-5))"

1º expression:  -(5-3)+2*((5-3)+2*@)                _BufferAT = -2;

2º expression:  -(5-3)+2*(@+2*@)                    _BufferAT = -2;+2

3º expression:  -(5-3)+2*@                          _BufferAT = -2;

4º expression:  +@+2*@                              _BufferAT = -2; -2
                   
last solution:   -6

                    What do you think about ?
                    Is there anything wrong ? Tell me

RuiLoureiro

Hi

Quote
The first procedure to solve an expression is this:

If _BufferY is defined like

                dd 120
                dd 0            <--- number of characters
_BufferY    db 121 dup (0)

invoke  LookExpress, addr _BufferY  to solve the expression in _BufferY

Quote
;   _TblOperandAt is an array of 2 dwords to save sign
;                 and result of each operation  (each @)
;
LookExpress     proc    pRcl:DWORD

                mov     edx, offset _TblOperandAt
                mov     dword ptr [edx - 4], 0
                ;
    _start:     mov     esi, pRcl
                mov     ecx, dword ptr [esi - 4]
                ;
                cmp     ecx, 0
                jne     short _loop1
                ;
    error1:     call    SetError
                stc
                ret
               
    _loop1:     sub     ecx, 1
                movzx   eax, byte ptr [esi + ecx]
                cmp     al, ')'
                je      short _found1
                ;
                cmp     ecx, 0
                jne     short _loop1
                ;
                ; not found -> solve the last expression
                ; »»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»

                invoke      SolveExpress, esi
                ret           
;---
    _found1:    cmp     ecx, 0
                je      short error1
                ;
                mov     _OffsetLst, ecx
;---
    _loop2:     sub     ecx, 1
                movzx   eax, byte ptr [esi + ecx]
                cmp     al, '('
                je      short _found2
               
                cmp     al, ')'
                je      short _found1
               
                cmp     ecx, 0
                jne     short _loop2
                je      error1
;---
    _found2:    mov     _OffsetFst, ecx

                mov     ebx, _OffsetLst
                sub     ebx, ecx
                sub     ebx, 1
               
                cmp     ebx, 0
                je      short _rem
                ;
                cmp     ebx, 1
                ja      short _found3
                ;
                ; Constant
                ;
                mov     ebx, _OffsetFst
                add     ebx, 1
                movzx   eax, byte ptr [esi + ebx]

                cmp     al, '@'
                je      short _rem
               
                cmp     al, '0'
                jb      error1
               
                cmp     al, '9'
                ja      error1
                ;
                ; Remove ()
                ; »»»»»»»»»
      _rem:     mov     ebx, _OffsetFst
                mov     byte ptr [esi + ebx], 20h
                mov     ebx, _OffsetLst
                mov     byte ptr [esi + ebx], 20h
                invoke  RemSpaces, esi
                jmp     _start
;---------------------------------------
    _found3:    mov     edi, offset WrkBuffer

                push    esi
               
                add     esi, _OffsetFst
                add     esi, 1

                mov     dword ptr [edi - 4], ebx
                mov     byte ptr [edi + ebx], 0
               
        @@:     sub     ebx, 1               
                movzx   eax, byte ptr [esi + ebx]
                mov     byte ptr [edi + ebx], al
                jnz     short @B

                pop     esi

                ; »»»»»»»»»»»»»»»»»»»»»»»»»»»
                ;     Wrk is constant ?
                ; »»»»»»»»»»»»»»»»»»»»»»»»»»»
                invoke  VrfOperand, edi, [edi - 4]
                jnc     _rem                            ; yes
               
                cmp     eax, 1
                je      error1
                ;
                ; Operation
                ; »»»»»»»»»
                invoke  SolveExpress, edi
                jc      error1
                ; »»»»»»»»»»»»»»»»»»»»»»
                ;  Replace (...) by AT
                ; »»»»»»»»»»»»»»»»»»»»»»
                invoke  RemExpress, esi

                call    AdjustSign

                call    SaveAt

                jmp     _start
LookExpress     endp

RuiLoureiro

Try Calcula14 and see all expressions one by one

RuiLoureiro

Now, Calcula15 solve expressions like 2^5+2^4+2^3+2^2+2^1+2^0 
     or 2^3+2*(5-3)+10

RuiLoureiro

The last Calcula15 has a bug:   2^3-2^3 = 16  !!!

Now, Calcula15 solve expressions like:  2^5+2^4+2^3+2^2+2^1+2^0 
     or 2^3+2*(5-3)+10      or (((2^3)))+1   or  -(-2^3+1)-5    -2^3+2^3 ...

It is under test. Did you find another bug ?


RuiLoureiro

The last Calcula15 has a bug: a procedure VrfOperand  proc pRcl:DWORD, Len:DWORD
                              exits with  ret  4  instead of   ret 8

Calcula16   does  (1-2*3)^3   but not  (2^3)^3 (the base cannot be an exponential)
            and   (-5)^3   or (-5)^2    -5^3   (the exponent should be 0 to +31 )
           
            it does any integer expression with
            Sub (-), Add (+), Mul (*), Div (/), Remainder (\), Exp(^)
            i hope !       

New Calcula16 because  ---3^3 doesnt give error

RuiLoureiro

I am working now in Calcula16...meanwhile

I decided to show all Calcula14 project (it doesnt make exponentials)
Calcula14.zip   is = .asm.inc, .glb  & .exe
You can assemble it: Use Console Assemble & Link
Express your opinion or comments if you want

RuiLoureiro

#27
the linear method used in Calcula16:
         
                    1- Read expression to _BufferX
                   
                    2- Copy _BufferX to _BufferY and remove spaces and get
                       the buffer length Y

                       Remove some types of expressions (to have less problems after):
                       this (x+y..z)      is =   x+y...z
                       this (((x+y)))+z   is =   (x+y)+z

                       Test some types of errors (to have less problems after)
                       ... +-(x+y)        is  ERROR
                       ... -+-x+y         is  ERROR

                       Now, START

invoke LookExponent:
                    3- Scan _BufferY from right to left to find the operator ^
                       If not, exit to 5

                    4- For each operator ^, find exponent and base ( base^exponent )

                       If base is an expression, copy it to BufferB
                       and  «invoke LookExpress, addr BufferB» to get the base
                       
                       Save the result on _TableEX (from top to bottom) and replace
                       the expression "base^exponent" by #
                       Go on (goto 3)

invoke LookExpress:                       
                    5- Scan _BufferY from right to left to find an expression
                       inside brackets - try to find first ")" and than "("
                       If not, exit to 8
                       
                    6- Copy the expression to a WorkBuffer and than call
                       the procedure SolveExpress
                       
                    7- Save the result on _TableAT (from top to bottom)
                       Replace the expression by @
                       Start again until we have not brackets (goto 5)
                       
                    8- Call SolveExpress to solve the last expression in _BufferY

                    9- The result: the value is in OperandW and sign in SignW

                   10- Convert it to string _ResultZ

                   11- Show string _ResultZ
                   
                    SolveExpress: build 2 tables: operations and operands
                                  whenever we find @, from bottom to top,
                                  get the values from _TableAT;
                                  whenever we find #, from bottom to top,
                                  get the values from _TableEX;

                                  If it is a constant, convert it
                                  When we have the tables, call ResolveIt

                    ResolveIt gives the result in OperandW and SignW
                   
                    We can exit from a procedure with 3 types of results:
                                  a)    correct     (exit clc)
                                  b)    error       (exit stc EAX=0)
                                  c)    overflow    (exit stc EAX=1)
                                   
                    Note that each expression is solved by SolveExpress
                         from left to right
                         while we scan _BufferY from right to left;
                         
                         We move values to _TableAT or _TableEX from
                         top to bottom and retrieve them from bottom to top.
                         
                         _TableAt and _TableEx work like a stack: when we
                         scan we PUSH; when we want the values, we POP

    Anyone has any other idea to add.
    Do you want help us
    EDIT:
            The procedures doesnt solve expressions with exponentials or powers inside
            brackets. The result cannot be correct

oex

We are all of us insane, just to varying degrees and intelligently balanced through networking

http://www.hereford.tv

RuiLoureiro

Thanks oex,
            That link say nothing to me

Calcula16 has a problem of brackets precedence
If the expression has not brackets, the result is correct
One simple example is this: 2^4 + (2*2^3) + 2^2 = 36 (Calcula16 gives 44)
I am working on Calcula16 to solve this problem