| ||
Here, I present an example of the simplest calculator. For Assembly language, it might be difficult to find libraries with specific procedures. Naturally, you can write everything on your own, but this approach isn't suitable when you are short of time. The method suggested here is simple. The program written in C language (or any other high-level language) is a skeleton. It calls the Assembly procedure, which carries out the main operations. In addition, you can include in the C module those procedures that are easier to write in C language. These procedures will be called from the Assembly code. The example provided in this section illustrates this approach. The C module includes procedures that convert strings into real numbers , carry out requested operations over them, and then convert the result back into a string.
// CALCC.CPP #include <windows.h> #include <stdio.h> // Call the Assembly procedure extern "C" __stdcall MAIN1(); // Add extern "C"__stdcall void sum(char *, char *, char *); // Subtract extern "C"__stdcall void su(char *, char *, char *); // Multiply extern "C"__stdcall void mu(char *, char *, char *); // Divide extern "C"__stdcall void dii(char *, char *, char *) ; int WINAPI WinMain (HINSTANCE hThisInst, HINSTANCE hPrevInst, LPSTR lpszArgs, int nWinMode) { MAIN1 (); return 0; } extern "C"__stdcall void sum(char * s1, char * s2, char * s) { float f1, f2, f; f1 = atof(s1); f2 = atof(s2); f = f1 + f2; sprintf(s, "%f", f); strcat(s, " + "); return; } extern "C" __stdcall void su(char * s1, char * s2, char * s) { float f1, f2, f; f1 = atof(s1); f2 = atof(s2); f = f1 - f2; sprintf(s, "%f", f); strcat(s, " -"); return; } extern "C" __stdcall void mu(char * s1, char * s2, char * s) { float f1, f2, f; f1 = atof(s1); f2 = atof(s2); f = f1*f2; sprintf(s, "%f", f); strcat(s, " *"); return; } extern "C" __stdcall void dii(char * s1, char * s2, char * s) { float f1, f2, f; f1 = atof(s1); f2 = atof(s2); if(f2!=0) { f = f1/f2; sprintf(s, "%f", f); strcat(s, " /"); } else strcpy(s, "Division error"); return; }
// CALC.RC // Definitions of constants // Window styles #define WS_SYSMENU 0x00080000L #define WS_MINIMIZEBOX 0x00020000L #define DS_3DLOOK 0x0004L #defin ES_LEFT 0x0000L #define WS_CHILD 0x40000000L #define WS_VISIBLE 0x10000000L #define WS_BORDER 0x00800000L #define WS_TABSTOP 0x00010000L #define SS_LEFT 0x00000000L #define BS_PUSHBUTTON 0x00000000L #define BS_CENTER 0x00000300L #define DS_LOCALEDIT 0x20L #define ES_READONLY 0x0800L // Button identifiers #define IDC_BUTTON1 101 #define IDC_BUTTON2 102 #define IDC_BUTTON3 103 #define IDC_BUTTON4 104 DIAL1 DIALOG 0, 0, 170, 110 STYLE WS_OVERLAPPED WS_CAPTION WS_SYSMENU WS_MINIMIZEBOX DS_3DLOOK CAPTION "An example of a simple calculator" FONT 8, "Arial" { CONTROL "", 1, "edit", ES_LEFT WS_CHILD WS_VISIBLE WS_BORDER WS_TABSTOP, 9, 8, 128, 12 CONTROL "", 2, "edit", ES_LEFT WS_CHILD WS_VISIBLE WS_BORDER WS_TABSTOP, 9, 27, 128, 12 CONTROL "", 3, "edit", ES_LEFT WS_CHILD ES_READONLY WS_VISIBLE WS_BORDER WS_TABSTOP, 9, 76, 127, 12 CONTROL "+", IDC_BUTTON1, "button", BS_PUSHBUTTON BS_CENTER WS_CHILD WS_VISIBLE WS_TABSTOP, 11, 48, 15, 14 CONTROL "-", IDC_BUTTON2, "button", BS_PUSHBUTTON BS_CENTER WS_CHILD WS_VISIBLE WS_TABSTOP, 34, 48, 15, 14 CONTROL "*", IDC_BUTTON3, "button", BS_PUSHBUTTON BS_CENTER WS_CHILD WS_VISIBLE WS_TABSTOP, 56, 48, 15, 14 CONTROL "/", IDC_BUTTON4, "button", BS_PUSHBUTTON BS_CENTER WS_CHILD WS_VISIBLE WS_TABSTOP, 80, 48, 15, 14 } ; CALC.INC ; Constants ; This message arrives when the window is closed WM_CLOSE equ 10h WM_INITDIALOG equ 110h WM_COMMAND equ 111h WM_GETTEXT equ 0Dh WM_SETTEXT equ 0Ch ; Prototypes of external procedures EXTERN ExitProcess:NEAR EXTERN GetModuleHandleA:NEAR EXTERN DialogBoxParamA:NEAR EXTERN EndDialog:NEAR EXTERN SendDlgitemMessageA:NEAR ; Structures ; Message structure MSGSTRUCT STRUC MSHWND DWORD ? MSMESSAGE DWORD ? MSWPARAM DWORD ? MSLPARAM DWORD ? MSTIME DWORD ? MSPT DWORD ? MSGSTRUCT ENDS ; The CALC.ASM module .586P ; Flat memory model .MODEL FLAT, stdcall include calc.inc EXTERN sum:NEAR EXTERN su:NEAR EXTERN mu:NEAR EXTERN dii:NEAR PUBLIC MAIN1 ; INCLUDELIB directives for the linker includelib c:\tasm32\lib\import32.lib ;------------------------------------------- ; Data segment _DATA SEGMENT MSG MSGSTRUCT <?> HINST DD 0 ; Application descriptor PA DB "DIAL1", 0 S1 DB 50 DUP(0) S2 DB 50 DUP(0) S DB 50 DUP(0) _DATA ENDS ; Code segment _TEXT SEGMENT ; The procedure called from the C module MAIN1 PROC ; Get the application descriptor PUSH 0 CALL GetModuleHandleA MOV [HINST], EAX ;----------------------------------- PUSH 0 PUSH OFFSET WNDPROC PUSH 0 PUSH OFFSET PA PUSH [HINST] CALL DialogBoxParamA ;----------------------------------- RET MAIN1 ENDP ; Window procedure ; Position of parameters in the stack ; [EBP+014H] ; LPARAM ; [EBP+10H] ; WAPARAM ; [EBP+0CH] ; MES ; [EBP+8] ; HWND WNDPROC PROC PUSH EBP MOV EBP, ESP ;----------------------------------- CMP DWORD PTR [EBP+0CH], WM_CLOSE JNE L1 PUSH 0 PUSH DWORD PTR [EBP+08H] CALL EndDialog MOV EAX, 1 JMP FINISH L1: CMP DWORD PTR [EBP+0CH], WM_INITDIALOG JNE L2 ; Fill the edit fields if necessary JMP FINISH L2: CMP DWORD PTR [EBP+0CH], WM_COMMAND JNE FINISH CMP WORD PTR [EBP+10H], 101 JNE NO_SUM ; First addend PUSH OFFSET S1 PUSH 50 PUSH WM_GETTEXT PUSH 1 PUSH DWORD PTR [EBP+08H] CALL SendDlgItemMessageA ; Second addend PUSH OFFSET S2 PUSH 50 PUSH WM_GETTEXT PUSH 2 PUSH DWORD PTR [EBP+08H] CALL SendDlgitemMessageA ; Sum PUSH OFFSET S PUSH OFFSET S2 PUSH OFFSET S1 CALL sum ; Output the sum PUSH OFFSET S PUSH 50 PUSH WM_SETTEXT PUSH 3 PUSH DWORD PTR [EBP+08H] CALL SendDlgItemMessageA JMP FINISH NO_SUM: CMP WORD PTR [EBP+10H], 102 JNE NO_SUB ; Minuend PUSH OFFSET S1 PUSH 50 PUSH WM_GETTEXT PUSH 1 PUSH DWORD PTR [EBP+08H] CALL SendDlgItemMessageA ; Subtrahend PUSH OFFSET S2 PUSH 50 PUSH WM_GETTEXT PUSH 2 PUSH DWORD PTR [EBP+08H] CALL SendDlgitemMessageA ; Difference PUSH OFFSET S PUSH OFFSET S2 PUSH OFFSET S1 CALL su ; Compute the difference PUSH OFFSET S PUSH 50 PUSH WM_SETTEXT PUSH 3 PUSH DWORD PTR [EBP+08H] CALL SendDlgItemMessageA JMP FINISH NO_SUB: CMP WORD PTR [EBP+10H], 103 JNE NO_MULT ; First multiplier PUSH OFFSET S1 PUSH 50 PUSH WM_GETTEXT PUSH 1 PUSH DWORD PTR [EBP+08H] CALL SendDlgItemMessageA ; Second multiplier PUSH OFFSET S2 PUSH 50 PUSH WM_GETTEXT PUSH 2 PUSH DWORD PTR [EBP+08H] CALL SendDlgItemMessageA ; Product PUSH OFFSET S PUSH OFFSET S2 PUSH OFFSET S1 CALL mu ; Output the product PUSH OFFSET S PUSH 50 PUSH WM_SETTEXT PUSH 3 PUSH DWORD PTR [EBP+08H] CALL SendDlgitemMessageA JMP FINISH NO_MULT: CMP WORD PTR [EBP+10H], 104 JNE FINISH ; Dividend PUSH OFFSET S1 PUSH 50 PUSH WM_GETTEXT PUSH 1 PUSH DWORD PTR [EBP+08H] CALL SendDlgItemMessageA ; Divisor PUSH OFFSET S2 PUSH 50 PUSH WM_GETTEXT PUSH 2 PUSH DWORD PTR [EBP+08H] CALL SendDlgItemMessageA ; Division PUSH OFFSET S PUSH OFFSET S2 PUSH OFFSET S1 CALL dii ; Output the division result PUSH OFFSET S PUSH 50 PUSH WM_SETTEXT PUSH 3 PUSH DWORD PTR [EBP+08H] CALL SendDlgItemMessageA JNE FINISH FINISH: MOV EAX, 0 POP EBP RET 16 WNDPROC ENDP _TEXT ENDS END
To translate this program, issue the following commands:
tasm32 /ml calc.asm brcc32 calc.rc
Then, add the CALC.OBJ and CALC.RES files to the CALCC.CPP project (Listing 20.8).
| ||