460 likes | 710 Views
系統程式. Chapter 4 : Macro Processors. Expanded Assembly Programs. Core Assemblers. Object Programs. Linkers. Libraries. Loaders. Executables. Assembling Programs for Execution. Assembly Programs. Macro Processors. # define ABSDIFF(X,Y) ((X) > (Y) ? (X)-(Y):(Y)-(X))
E N D
系統程式 Chapter 4: Macro Processors
Expanded Assembly Programs Core Assemblers Object Programs Linkers Libraries Loaders Executables Assembling Programs for Execution Assembly Programs Macro Processors
#define ABSDIFF(X,Y) ((X) > (Y) ? (X)-(Y):(Y)-(X)) #define WRONG(X,Y) X > Y ? X - Y : Y - X int main() { int i, j, k; k = ABSDIFF(i,j); k = ABSDIFF(i-j, j-x); k = WRONG(i-j, j-x); return 0; } int main() { int i, j, k; k = (( i ) > ( j ) ? ( i )-( j ):( j )-( i )) ; k = ((i-j) > (j-x) ? (i-j)-(j-x):( j-x )-(i-j)) ; k = i-j > j-x ? i-j - j-x : j-x - i-j ; return 0; } An Example in C gcc –E –P abc.c
Macro Definition and Expansion • Macro definition (Fig. 4.1) • parameters • prototype • body • Macro expansion ( Fig. 4.2) • invocation (macro call) • arguments • Relative addressing and labels in macro prototypes
Figure 4.1 macro definition macro invocation
parameters prototype body A Simple SIC/XE Macro Definition
Figures 2.6 and 4.2 Figure 2.6
Macro Processors • A simple two-pass macro processors • How • Record macro definitions in the first pass. • Process macro invocations in the second pass.
One-Pass Macro Processors • Macro definitions must precede macro invocations. • Data structures • DEFTAB • no comment lines • parameters converted to positional notation (?n) • NAMTAB • ARGTAB
Nested Macro Definitions • Examples (Fig. 4.3) • Why? • Problems • Notice that we are NOT talking about macro invocations in macro definitions (Sec. 4.3.1)
LEVEL = 2 LEVEL = 2 LEVEL = 1 Nested Macro Definitions MACROS MACRO RDBUFF MACRO &INDEV,&BUFADR,&RECLTH …… MEND WRBUFF MACRO &OUTDEV,&BUFADR,&RECLTH …… MEND …… …… MEND What if this macro is invoked twice? Recursive macro expansion…(Sec. 4.3.1)
Figure 4.5 LEVEL=0 LEVEL=2 LEVEL=1 LEVEL=1 MACROS MACRO INSIDE MACRO &A LDA &A MEND MEND
Features • Concatenating macro parameters • What (page 186) • Marking the start and end of the parameters • Examples (Figure 4.6) • Unique labels • Use special methods to indicate local variables • $[0-9A-Z]{2}original-label in SIC • LOCAL command in MASM
Concatenating Macro Parameters SUM MACRO &ID LDA X&ID1 ADD X&ID2 ADD X&ID3 STA X&IDS MEND SUM MACRO &ID,&ID1 LDA X&ID1 ADD X&ID2 ADD X&ID3 STA X&IDS ……… LDT &ID1 MEND SUM X,Y
Labels in Macro Definitions SAM START 0 HERE MACRO &PARAM1 AGAIN LDA #&PARAM1 MEND HIHI LDX #0 HERE 4 HERE 5 END HIHI WHAT IF WE DO NEED TO USE LABELS? SAM START 0 HIHI LDX #0 AGAIN LDA #4 AGAIN LDA #5 END HIHI This is why we did not use labels in Figure 4.1.
Features (2) • Conditional Macro Expansion • Examples (Fig. 4.8) • Macro processor directive (SET) • Macro-time variables (set symbols) • &xyz • initialized to 0 • How • simple IF-ELSE-ENDIF (trace Fig. 4.8) • simple WHILE-ENDW (trace Fig. 4.9)
Features (3) • Keyword Macro Expansion • positional parameters vs. keyword parameters • Examples (pages 197-199) • Why? • Default values • Overriding default values
Design Options • Recursive macro expansion • Examples • Problems • Solving the problems
Design Options (2) • General-purpose macro processors • Advantages vs. disadvantages • Differences in programming languages • comments • statement blocks: begin-end vs. {} • tokens: assignment in C(=) and Pascal (:=) • difficulty in using consistent syntax for macro invocation
Implementation Examples • MASM Macro Processor An integrated macro processor with the assembler • Concatenation operator & • Unique Label ??n
ABSDIF MACRO OP1,OP2,SIZE LOCAL EXIT IFNB <SIZE> IFDIF <SIZE>,<E> ;ERROR .ERR EXITM ENDIF ENDIF MOV SIZE&AX,OP1 SUB SIZE&AX,OP2 JNS EXIT NEG SIZE&AX EXIT: ENDM • ABSDIF J,K • MOV AX,J • SUB AX,K • JNS ??0000 • NEG AX • ??0000: • ABSDIF M,N,E • MOV EAX,M • SUB EAX,N • JNS ??0001 • NEG EAX • ??0001:
ANSI C Preprocessor • #define NULL 0 • #define EOF (-1) • #define EQ == • while ( I EQ 0 ) • -> while ( I == 0 ) • A macro contain a token that happens to match its name.
Avoid multi-include • #ifndef COMDEF_H #define COMDEF_H //context of the header#endif
“Macro is more efficient” • Avoid the cost of function call
#define ABSDIFF(X,Y) ((X) > (Y) ? (X)-(Y):(Y)-(X)) #define WRONG(X,Y) X > Y ? X - Y : Y - X int main() { int i, j, k; k = ABSDIFF(i,j); k = ABSDIFF(i-j, j-x); k = WRONG(i-j, j-x); return 0; } int main() { int i, j, k; k = (( i ) > ( j ) ? ( i )-( j ):( j )-( i )) ; k = ((i-j) > (j-x) ? (i-j)-(j-x):( j-x )-(i-j)) ; k = i-j > j-x ? i-j - j-x : j-x - i-j ; return 0; } An Example in C gcc –E –P abc.c
“Stringizing” operator # #define DISPLAY(EXPR) printf(“EXPR = %d\n”, EXPR); DISPLAY(I*J+1) printf(“EXPR = %d\n”, I*J+1); #define DISPLAY(EXPR) printf(#EXPR “= %d\n”, EXPR); DISPLAY(I*J+1) printf(“I*J+1” “= %d\n”, I*J+1);
#define DISPLAY(EXPR) printf(#EXPR “= %d\n”, EXPR); DISPLAY(ABSDIFF(3,8)) printf(“ABSDIFF(3,8)” “= %d\n”, ABSDIFF(3,8)); printf(“ABSDIFF(3,8)” “= %d\n”, ( (3) >(8) ? (3) – (8) : (8) – (3) ) ); debug message #define ERR(fmt, ...) fprintf(stderr, "ERR: " fmt "\n\n", ##__VA_ARGS__)
Conditional compilation #ifndef BUFFER_SIZE #define BUFFER_SIZE 1024 #endif #ifdefine DEBUG 1 . #if DEBUG == 1 printf(…) /* debugging output */ #endif #define DEBUG 0 #ifdef DEBUG printf(…) #endif
Use const to replace #define #define ASPECT_RATION 1.653 Const double ASPECT_RATION 1.653; Class GamePlayer { private: static const int NUM_TURNS = 5; int score[NUM_TURNS]; } const int GamePlayer::NUM_TURNS; Effective C++ Meyers
Use inline to replace #define #define max(a, b) ( (a) > (b) ? (a) : (b) ) Int a=5, b=0; max(++a, b); max(a--, b+10); Int a=5, b=0; (++a) > (b) ? (++a) : (b) ; (a--) > (b+10) ? (a--) : (b+10);
Use inline to replace #define #define max(a, b) ( (a) > (b) ? (a) : (b) ) inline const int max(int a, int b) { return a > b ? a : b; } template <class T> inline const T& max(const T& a, const T& b) { return a > b ? a : b; }
template<int N> struct fib { static const int result = fib<N-1>::result + fib<N-2>::result; }; template<> struct fib<2> { static const int result = 1; }; template<> struct fib<1> { static const int result = 1; }; /* function */ cout<<fib<5>::result<<endl;
Unit test /* target code */ int myadd(const int a, const int b) { return a + b; }
Unit test – test case void test_case1(void) { int result = myadd(1, 2); CHECK(result == 3); } void test_case2(void) { int result = myadd(1, -2); CHECK(result == -1); }
Unit test – ut.h int __check_count = 0; int __failure_count = 0; typedef struct { char *desc; void (*func)(void); int failure; int check; } test_suite_t; #define CHECK(expr) \ { ++__check_count; if(! (expr)) { ++__failure_count; \ printf("*check* FAIL!!: %s:%d: %s\n", __func__, __LINE__, # expr); \ }} void test_case1(void) { int result = myadd(1, 2); CHECK(result == 3); }
Unit test – ut.h - run_test_suite() void run_test_suite(test_suite_t *psuite) { int num = 0; int total_failure = 0; int total_check = 0; test_suite_t *iter = psuite; for(;iter->func;++iter) { fprintf(stderr, "\n*Test: %s\n\n", iter->desc); __check_count = 0; __failure_count = 0; iter->func(); iter->failure = __failure_count; iter->check = __check_count; total_failure += __failure_count; total_check += __check_count; }
Unit test – ut.h - run_test_suite() /* report */ fprintf(stderr, "\nTest Report\n\n"); fprintf(stderr, "%4s | %-40s | %s\n", "case", "description", "fail / check"); fprintf(stderr, "-----+------------------------------------------+----------------\n"); for(iter = psuite, num = 1;iter->func;++iter, ++num) { fprintf(stderr, "%4d | %-40s | %4d / %d%s\n", num, iter->desc, iter->failure, iter->check, iter->failure?" FAIL!!":""); } fprintf(stderr, " +==========================================+================\n"); fprintf(stderr, " | final result | %4d / %d\n\n", total_failure, total_check); }
Unit test int main() { test_suite_t suite[] = { {"basic test", test_case1}, {"basic test 2", test_case2}, {NULL, NULL} }; run_test_suite(suite); return 0; }