2017-04-23 452 views
2

我想提供一个最终项目的框架,这是一个FP计算器。但是,我遇到了一些麻烦。如果我编译这个代码,我得到Picture of Error Messages。我不确定这是什么汇编,但我相信它的32位和我正在使用MASM编译器。“Error A2006:Undefined Symbol,Macro Called From,Main Line Code”

这样做的要点是从输入文件中读取一行,并进行执行操作。但是,我只是在做定义部分,我的合作伙伴会考虑实施这些操作。

如果我要将主函数减去“Only_Nums,Character_Error:和Invalid_Char:”,程序将编译。

你能帮我确定为什么它不会编译。我能想到的唯一合乎逻辑的事情是,被引用的代码并没有被首先定义,但是,它是。

谢谢!

编辑:用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 
+2

'[BP + 8 + ESI]'不是有效的寻址模式。你应该给'[BP + 8 + SI]'。你也应该改变你使用ESI到SI的其他地方。由于“.MODEL Small”指令,您显示的代码为16位,因此您使用的是16位寻址,这意味着在SI上使用ESI作为索引没有意义。没有什么可以比64k更大。 –

+0

完成,但同样的错误仍然存​​在。 – Jordan

+0

使用ESI作为索引有时会带来一个好处:它会强制汇编器添加32位大小覆盖前缀,这就开辟了使用16位模式不支持的其他寻址模式的可能性。但是,罗斯的建议仍然很好。除非你知道自己在做什么,否则16位代码只能使用16位寄存器,而不能使用“E”前缀。 –

回答

2

被拒绝的符号位于内部一个过程(PROC..ENDP),因此本地为一个较新的MASM代替ESI。他们在程序之外是未知的。

如果您双击冒号(::)你声明的标签为“全球性”:

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的未来程序员不会知道这一点。

+0

非常感谢,这解决了我的问题! 你是什么意思interprocedural标签? 我很想让这段代码更好,我如何制作本地标签? – Jordan

+0

@Jordan:我试图在我的编辑中解释它;-)。更好......嗯......避免跳出程序。用于此目的只能调用并为目标创建单独的过程(PROC..ENDP)。避免使用宏,如果你不是绝对坚定的话。宏不应该成为程序的替代品。 – rkhb

+0

我看到了,是的,我正在考虑制作一个宏,它将接收错误消息字符串的偏移量;这将消除程序之外的呼叫。尽管我很困惑,为什么我应该避免使用宏,以及在哪里用宏替换过程。我相信,读取trig和log函数的宏应该在那里,因为它们通过了不同的变量。 – Jordan

相关问题