2

I am trying to provide a skeleton frame of a final project, which is a FP calculator. However, I've run into some trouble. If I compile this code, I get Picture of Error Messages. I am unsure what assembly this is, but I believe its 32bit and am using MASM compiler.

The point of this is to read a line from the input file, and make perform operations. However, I am only doing the defining section, my partners will figure out implementing the operations.

If I were to comment out the main function, minus "Only_Nums, Character_Error:, and Invalid_Char:" the program will compile.

Can you help me in determining why it won't compile. The only logical thing I can think of is that the code being referenced wasn't defined first, however, it was.

Thanks!

Edit: Replaced ESI with SI

.MODEL Small
        .386
        .387
        .STACK
        .DATA
    FileN       DB  "FILENAME.DAT",0
    Buffer      DB  255 DUP (?)
    StrinLen    DB  0
    Num2FP      DB  0
    Base        DB  10.0
    FPNum       DT  0.0
        .CODE

    ;------------------------------code to search file and opening file------------------------------------------------------------------------------------------
    ;------------------------------code for setting up the file pointer to, initally the first line, but after the first, to the next------------------------------
    ;------------------------------I am going to use buffer as the placeholder for the string of the line------------------------------------------------------------

    ;------------------------------String Length------------------------------------------------------------------------------------------------
    String_Length   PROC FAR
            PUSHAD
    Next_Element:   MOV AL, BYTE PTR [BP + 0 + SI]
            INC SI
            CMP AL, 0Dh
            JNE Next_Element
            MOV [BP+2], SI
            POPAD
            RET
    String_Length   ENDP
    ;----------------------------------------------------------------------------------------------------------------------------------------

    ;------------------------------Macro to detect if trig and log are functions------------------------------------------------------------
    Detect_Func MACRO W, X, Y, Z
            INC SI
            MOV BL, BYTE PTR [BP + 8 + SI]
            .IF (BL != W) && (BL != Y)
                JMP Character_Error
            .ENDIF

            INC SI
            MOV BL, BYTE PTR [BP + 8 + SI]
            .IF (BL != W) && (BL != Z)
                JMP Character_Error
            .ENDIF
    ENDM        

    ;------------------------------Reading the string from the input file, directing what the program does------------------------------------------
    ;------------------------------Didn't initially write this as procedure, so it will need to be converted----------------------------------------
    Token       PROC FAR    
    ReadIn:     MOV BL, BYTE PTR [BP + 8 + SI]

            .IF (BL < '0' && BL > '9')
                JB Check_Invalid
            .ENDIF

            SUB BL, 30h
            MOVZX BX, BL
            MOV [BP+6], BX
            FILD WORD PTR [BP + 6]

            FLD DWORD PTR [BP + 2]
            FMUL DWORD PTR [BP + 4]
            FADDP ST(1), ST
            FBSTP [BP + 2]  

            INC SI
            CMP [BP], SI
            JB Only_Nums
            JMP ReadIn

    Check_Invalid:
            FLD DWORD PTR [BP + 2]

    .IF     BL == 0DH
    ;------------------------------write to file, move file pointer to next line and jump to readin-------------------------------------------------
    ;------------------------------there should be some stopping condition in the event there aren't any more lines to calculate--------------------

    .ELSEIF     BL == ' '
            INC SI
            JMP ReadIn

    .ELSEIF     BL == '+'
            CALL FP_Add
            RET

    .ELSEIF     BL == '-'
            CALL FP_Sub
            RET

    .ELSEIF     BL == '*'
            CALL FP_Mul
            RET

    .ELSEIF     BL == '/'
            CALL FP_Div
            RET

    .ELSEIF     BL == '('

    .ELSEIF     BL == ')'

    .ELSEIF     BL == '^'
            CALL FP_Power
            RET

    .ELSEIF     BL == '.'
            CALL FP_Dec

    .ELSEIF     (BL == 'E' || BL == 'e')
            CALL FP_E

    .ELSEIF     (BL == 'C' || BL == 'c')
            Detect_Func 'o', 's', 'O', 'S'
            CALL FP_Cos
            RET

    .ELSEIF     (BL == 'S' || BL == 's')
            Detect_Func 'i', 'n', 'I', 'N'
            CALL FP_Sin
            RET

    .ELSEIF     (BL == 'T' || BL == 't')
            Detect_Func 'a', 'n', 'A', 'N'
            CALL FP_Tan
            RET

    .ELSEIF     (BL == 'L' || BL == 'l')
            Detect_Func 'o', 'g', 'O', 'G'
            Detect_Func '1', '0', '1', '0'
            CALL FP_Log
            RET

    .ELSEIF     (BL == 'R' || BL == 'r')
    ;------------------------------display error if number follows...?------------------------------------------------------------------------------------------

    .ELSE
            JMP Invalid_Char

    .ENDIF

            RET
    Token       ENDP    

    FP_Add      PROC FAR
            CALL Token

            RET
    FP_Add      ENDP

    FP_Sub      PROC FAR
            CALL Token

            RET
    FP_Sub      ENDP

    FP_Mul      PROC FAR
            CALL Token

            RET
    FP_Mul      ENDP

    FP_Div      PROC FAR
            CALL Token

            RET
    FP_Div      ENDP

    FP_Power    PROC FAR
            CALL Token

            RET
    FP_Power    ENDP


    FP_Dec      PROC FAR
            CALL Token

            RET
    FP_Dec      ENDP

    FP_E        PROC FAR
            CALL Token

            RET
    FP_E        ENDP


    FP_Cos      PROC FAR
            CALL Token

            RET
    FP_Cos      ENDP

    FP_Sin      PROC FAR
            CALL Token

            RET
    FP_Sin      ENDP


    FP_Tan      PROC FAR
            CALL Token

            RET
    FP_Tan      ENDP

    FP_Log      PROC FAR
            CALL Token

            RET
    FP_Log      ENDP




    MAIN        PROC FAR
            .STARTUP

            MOV SI, 0
            PUSH OFFSET StrinLen            ;[BP+2]
            PUSH OFFSET Buffer          ;[BP]
            MOV BP, SP
            CALL String_Length
            ADD SP, 4
            POP BP


            PUSH BP                 
            PUSH OFFSET Buffer          ;[BP+8]
            PUSH OFFSET Num2FP          ;[BP+6]
            PUSH OFFSET BASE            ;[BP+4]
            PUSH OFFSET FPNum           ;[BP+2]
            PUSH OFFSET StrinLen            ;[BP]
            MOV BP, SP
            CALL Token  
            ADD SP, 10
            POP SP

    Only_Nums:      ;No operands was given error message        
    Character_Error:    ;output error message (trig and log function)
    Invalid_Char:       ;output invalid character detected (invalid characted detected in input file


    MAIN        ENDP
    END
rkhb
  • 14,159
  • 7
  • 32
  • 60
Jordan
  • 21
  • 3
  • 2
    `[BP+8+ESI]` isn't a valid addressing mode. You should it to `[BP + 8 + SI]`. You also should change every place else you use ESI to SI. The code you've shown is 16-bit because of the `.MODEL Small` directive, so you're using 16-bit addressing meaning there's no point in using ESI over SI as an index. Nothing can be bigger than 64k. – Ross Ridge Apr 23 '17 at 02:43
  • Done, but the same errors are still there. – Jordan Apr 23 '17 at 02:54
  • There is sometimes an advantage of using ESI as an index: it forces the assembler to add the 32-bit size override prefix, which opens up the possibility of using additional addressing modes not supported in 16-bit mode. But yeah, Ross's advice is still good. Unless you know what you're doing, 16-bit code should use only 16-bit registers, with no `E` prefixes. – Cody Gray - on strike Apr 23 '17 at 13:08

1 Answers1

2

The rejected symbols are located inside a procedure (PROC..ENDP) and therefore local for a newer MASM. They are unknown outside the procedure.

If you double the colon (::) you declare that label as "global":

Token       PROC FAR
            ...
            JB Only_Nums
            ...
            JMP Character_Error
            ...
            JMP Invalid_Char
            ...
            RET
Token       ENDP

MAIN        PROC FAR
            ...
Only_Nums::         ;No operands was given error message
Character_Error::   ;output error message (trig and log function)
Invalid_Char::      ;output invalid character detected (invalid characted detected in input file
            ...
MAIN        ENDP

Better is to avoid interprocedural labels. For example, JB Only_Nums jumps from the middle of the procedure Token right into the middle of the procedure MAIN. This is called "spaghetti code" and can lead to trouble. You leave at least the return addres of Token on the stack. A future programmer who looks at MAIN won't know that.

rkhb
  • 14,159
  • 7
  • 32
  • 60
  • Thank you very much, this solved my issue!!! What do you mean interprocedural labels? I'd love to make this code better, how did I make a local label? – Jordan Apr 23 '17 at 06:29
  • @Jordan: I tried to explain it in my edit ;-) . Better...hmm...avoid jumps out of the procedure. Use for that purpose only calls and create separate procedures (PROC..ENDP) for the targets. Avoid macros, if you aren't absolutely firm in it. Macros should not be a replacement for procedures. – rkhb Apr 23 '17 at 07:09
  • I see, yes, I am thinking about making a macro that will take the offset of the string of the error message; which will eliminate calling outside of the procedure. Although I am confused why I should avoid macros, and where I am replacing a procedure with a macro. The macro for reading trig and log functions should be there because they pass different variables , I believe. – Jordan Apr 25 '17 at 03:01