Ошибка A2006: неопределенный символ, макрос, вызываемый из, код основной линии

Я пытаюсь предоставить каркас окончательного проекта, который представляет собой калькулятор FP. Тем не менее, я столкнулся с некоторыми проблемами. Если я скомпилирую этот код, я получу Изображение сообщений об ошибках. Я не уверен, что это за сборка, но я полагаю, что она 32-битная и использую компилятор MASM.

Смысл этого в том, чтобы прочитать строку из входного файла и заставить выполнять операции. Тем не менее, я делаю только определяющий раздел, мои партнеры разберутся с реализацией операций.

Если бы я закомментировал основную функцию за вычетом «Only_Nums, Character_Error: и Invalid_Char:», программа скомпилировалась.

Можете ли вы помочь мне определить, почему он не будет компилироваться. Единственная логичная вещь, о которой я могу думать, это то, что код, на который ссылаются, не был определен первым, однако он был.

Спасибо!

Изменить: заменен ESI на 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

person Jordan    schedule 23.04.2017    source источник
comment
[BP+8+ESI] не является допустимым режимом адресации. Вы должны это [BP + 8 + SI]. Вы также должны заменить ESI на SI во всех других местах, где вы используете ESI. Код, который вы показали, является 16-битным из-за директивы .MODEL Small, поэтому вы используете 16-битную адресацию, что означает, что нет смысла использовать ESI вместо SI в качестве индекса. Ничто не может быть больше 64k.   -  person Ross Ridge    schedule 23.04.2017
comment
Сделал, но те же ошибки остались.   -  person Jordan    schedule 23.04.2017
comment
Иногда есть преимущество использования ESI в качестве индекса: он заставляет ассемблер добавлять префикс переопределения 32-битного размера, что открывает возможность использования дополнительных режимов адресации, не поддерживаемых в 16-битном режиме. Но да, совет Росса все еще хорош. Если вы не знаете, что делаете, 16-битный код должен использовать только 16-битные регистры без префиксов E.   -  person Cody Gray    schedule 23.04.2017


Ответы (1)


Отклоненные символы находятся внутри процедуры (PROC..ENDP) и поэтому являются локальными для более новой версии MASM. Они неизвестны вне процедуры.

Если вы удвоите двоеточие (::), вы объявите этот ярлык «глобальным»:

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

Лучше избегать межпроцедурных меток. Например, JB Only_Nums переходит из середины процедуры Token прямо в середину процедуры MAIN. Это называется «спагетти-код» и может привести к проблемам. Вы оставляете по крайней мере адреса возврата Token в стеке. Будущий программист, который посмотрит на MAIN, этого не узнает.

person rkhb    schedule 23.04.2017
comment
Большое спасибо, это решило мою проблему!!! Что вы имеете в виду под межпроцедурными метками? Я бы хотел улучшить этот код, как мне сделать локальную метку? - person Jordan; 23.04.2017
comment
@Jordan: я пытался объяснить это в своем редактировании ;-). Лучше... хм... избегать прыжков из процедуры. Используйте для этого только вызовы и создайте отдельные процедуры (PROC..ENDP) для целей. Избегайте макросов, если вы не совсем уверены в этом. Макросы не должны заменять процедуры. - person rkhb; 23.04.2017
comment
Я вижу, да, я думаю о том, чтобы сделать макрос, который будет принимать смещение строки сообщения об ошибке; что устранит вызов вне процедуры. Хотя я смущен, почему я должен избегать макросов и где я заменяю процедуру макросом. Макрос для чтения функций триггера и журнала должен быть там, потому что я считаю, что они передают разные переменные. - person Jordan; 25.04.2017