Changeset 2790 in kBuild for trunk/src/kmk/kmk_cc_exec.c
- Timestamp:
- Sep 14, 2015 12:41:11 AM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/kmk/kmk_cc_exec.c
r2789 r2790 151 151 * @{ */ 152 152 /** Normal character, nothing special. */ 153 #define KMK_CC_EVAL_CH_NORMAL UINT 8_C(0)153 #define KMK_CC_EVAL_CH_NORMAL UINT16_C(0) 154 154 /** Blank character. */ 155 #define KMK_CC_EVAL_CH_BLANK UINT 8_C(1)155 #define KMK_CC_EVAL_CH_BLANK UINT16_C(1) 156 156 #define KMK_CC_EVAL_IS_BLANK(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_BLANK) 157 157 /** Space character. */ 158 #define KMK_CC_EVAL_CH_SPACE UINT 8_C(2)158 #define KMK_CC_EVAL_CH_SPACE UINT16_C(2) 159 159 #define KMK_CC_EVAL_IS_SPACE(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_SPACE) 160 160 /** Space character or potential EOL escape backslash. */ 161 #define KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH UINT 8_C(4)161 #define KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH UINT16_C(4) 162 162 #define KMK_CC_EVAL_IS_SPACE_OR_BACKSLASH(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH) 163 /** Anything we need to take notice of when parsing something could be a 164 * variable name or a recipe. 165 * All space characters, backslash (EOL escape), variable expansion dollar, 166 * variable assignment operator chars, recipe colon and recipe percent. */ 167 #define KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE UINT16_C(8) 168 #define KMK_CC_EVAL_IS_SPACE_OR_VAR_OR_RECIPE(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE) 163 169 /** Possible EOL character. */ 164 #define KMK_CC_EVAL_CH_EOL_CANDIDATE UINT 8_C(8)170 #define KMK_CC_EVAL_CH_EOL_CANDIDATE UINT16_C(16) 165 171 #define KMK_CC_EVAL_IS_EOL_CANDIDATE(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_EOL_CANDIDATE) 166 172 /** First character in a keyword. */ 167 #define KMK_CC_EVAL_CH_1ST_IN_KEYWORD UINT 8_C(16)173 #define KMK_CC_EVAL_CH_1ST_IN_KEYWORD UINT16_C(32) 168 174 #define KMK_CC_EVAL_IS_1ST_IN_KEYWORD(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_1ST_IN_KEYWORD) 169 175 /** Second character in a keyword. */ 170 #define KMK_CC_EVAL_CH_2ND_IN_KEYWORD UINT 8_C(32)176 #define KMK_CC_EVAL_CH_2ND_IN_KEYWORD UINT16_C(64) 171 177 #define KMK_CC_EVAL_IS_2ND_IN_KEYWORD(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_2ND_IN_KEYWORD) 172 178 /** First character in a variable qualifier keyword or 'define'. */ 173 #define KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD UINT 8_C(64)179 #define KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD UINT16_C(128) 174 180 #define KMK_CC_EVAL_IS_1ST_IN_VARIABLE_KEYWORD(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD) 175 /** Assignment punctuation character. */ 176 #define KMK_CC_EVAL_CH_ASSIGNMENT UINT8_C(128) 177 #define KMK_CC_EVAL_IS_ASSIGNMENT(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_ASSIGNMENT) 181 /** Used when parsing variable names, looking for the end of a nested 182 * variable reference. Matches parentheses and backslash (escaped eol). */ 183 #define KMK_CC_EVAL_CH_PAREN_OR_SLASH UINT16_C(256) 184 #define KMK_CC_EVAL_IS_PAREN_OR_SLASH(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_PAREN_OR_SLASH) 178 185 /** @} */ 179 186 … … 708 715 KMKCCEVALIFCORE IfCore; 709 716 /** The subprogram that will give us the variable name. */ 710 KMKCCEXPSUBPROG NameSub Prog;717 KMKCCEXPSUBPROG NameSubprog; 711 718 } KMKCCEVALIFDEFDYNAMIC; 712 719 typedef KMKCCEVALIFDEFDYNAMIC *PKMKCCEVALIFDEFDYNAMIC; … … 945 952 #endif 946 953 947 /** Bitmap taking'unsigned char' index.954 /** Generic character classification, taking an 'unsigned char' index. 948 955 * ASSUMES unsigned char is 8-bits. */ 949 static uint8_t g_abEvalCcChars[256]; 956 static uint16_t g_abEvalCcChars[256]; 957 950 958 951 959 /** … … 984 992 * Internal Functions * 985 993 *********************************************************************************************************************************/ 986 static int kmk_cc_exp_compile_subprog(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr, PKMKCCEXPSUBPROG pSub Prog);987 static char *kmk_exec_expand_subprog_to_tmp(PKMKCCEXPSUBPROG pSub Prog, uint32_t *pcch);994 static int kmk_cc_exp_compile_subprog(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr, PKMKCCEXPSUBPROG pSubprog); 995 static char *kmk_exec_expand_subprog_to_tmp(PKMKCCEXPSUBPROG pSubprog, uint32_t *pcch); 988 996 989 997 … … 1005 1013 1006 1014 /* space chars and zero terminator. */ 1007 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ' ', KMK_CC_EVAL_CH_SPACE | KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH); 1008 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\t', KMK_CC_EVAL_CH_SPACE | KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH); 1009 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\n', KMK_CC_EVAL_CH_SPACE | KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH | KMK_CC_EVAL_CH_EOL_CANDIDATE); 1010 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\v', KMK_CC_EVAL_CH_SPACE | KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH); 1011 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\f', KMK_CC_EVAL_CH_SPACE | KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH); 1012 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\r', KMK_CC_EVAL_CH_SPACE | KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH | KMK_CC_EVAL_CH_EOL_CANDIDATE); 1013 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\\', KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH); 1015 #define MY_SPACE_BITS KMK_CC_EVAL_CH_SPACE | KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH | KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE 1016 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ' ', MY_SPACE_BITS); 1017 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\t', MY_SPACE_BITS); 1018 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\n', MY_SPACE_BITS | KMK_CC_EVAL_CH_EOL_CANDIDATE); 1019 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\v', MY_SPACE_BITS); 1020 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\f', MY_SPACE_BITS); 1021 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\r', MY_SPACE_BITS | KMK_CC_EVAL_CH_EOL_CANDIDATE); 1022 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\\', KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH | KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE); 1023 #undef MY_SPACE_BITS 1014 1024 1015 1025 /* keywords */ … … 1030 1040 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'u', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* undefine */ 1031 1041 1032 /* Assignment punctuation. */ 1033 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '=', KMK_CC_EVAL_CH_ASSIGNMENT); 1034 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ':', KMK_CC_EVAL_CH_ASSIGNMENT); 1035 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '<', KMK_CC_EVAL_CH_ASSIGNMENT); 1036 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '?', KMK_CC_EVAL_CH_ASSIGNMENT); 1037 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '+', KMK_CC_EVAL_CH_ASSIGNMENT); 1042 /* Assignment punctuation and recipe stuff. */ 1043 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '=', KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE); 1044 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ':', KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE); 1045 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '<', KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE); 1046 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '?', KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE); 1047 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '+', KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE); 1048 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '%', KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE); /* uncertain... */ 1049 1050 /* For locating the end of variable expansion. */ 1051 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '(', KMK_CC_EVAL_CH_PAREN_OR_SLASH); 1052 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ')', KMK_CC_EVAL_CH_PAREN_OR_SLASH); 1053 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '{', KMK_CC_EVAL_CH_PAREN_OR_SLASH); 1054 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '}', KMK_CC_EVAL_CH_PAREN_OR_SLASH); 1055 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\\', KMK_CC_EVAL_CH_PAREN_OR_SLASH); 1038 1056 } 1039 1057 … … 1497 1515 } 1498 1516 return kmk_cc_block_alloc_eval_grow(ppBlockTail, cb); 1517 } 1518 1519 1520 /** 1521 * Allocate a string buffer for a makefile evaluation program. 1522 * 1523 * @returns Pointer to a makefile evaluation instruction core. 1524 * @param ppBlockTail Pointer to the allocator tail pointer. 1525 * @param cb The number of bytes to allocate. 1526 */ 1527 static char *kmk_cc_block_alloc_eval_string(PKMKCCBLOCK *ppBlockTail, uint32_t cb) 1528 { 1529 PKMKCCBLOCK pBlockTail = *ppBlockTail; 1530 uint32_t cbLeft = pBlockTail->cbBlock - pBlockTail->offNext; 1531 1532 KMK_CC_ASSERT(cbLeft >= sizeof(KMKCCEVALJUMP)); 1533 1534 cb = (cb + sizeof(void *) - 1) & ~(sizeof(void *) - 1); 1535 if (cbLeft >= cb + sizeof(KMKCCEVALJUMP)) 1536 { 1537 char *pszRet = (char *)pBlockTail + pBlockTail->offNext; 1538 pBlockTail->offNext += cb; 1539 return pszRet; 1540 } 1541 return (char *)kmk_cc_block_alloc_eval_grow(ppBlockTail, cb); 1499 1542 } 1500 1543 … … 2203 2246 * @param cchStr The length of the string to compile. Expected to 2204 2247 * be at least on char long. 2205 * @param pSub Prog The subprogram structure to initialize.2206 */ 2207 static int kmk_cc_exp_compile_subprog(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr, PKMKCCEXPSUBPROG pSub Prog)2248 * @param pSubprog The subprogram structure to initialize. 2249 */ 2250 static int kmk_cc_exp_compile_subprog(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr, PKMKCCEXPSUBPROG pSubprog) 2208 2251 { 2209 2252 KMK_CC_ASSERT(cchStr > 0); 2210 pSub Prog->pFirstInstr = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail);2211 kmk_cc_exp_stats_init(&pSub Prog->Stats);2253 pSubprog->pFirstInstr = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail); 2254 kmk_cc_exp_stats_init(&pSubprog->Stats); 2212 2255 return kmk_cc_exp_compile_common(ppBlockTail, pchStr, cchStr); 2213 2256 } … … 2635 2678 * 2636 2679 * @returns Pointer to the output buffer (hand to free when done). 2637 * @param pSub Prog The subprogram to execute.2680 * @param pSubprog The subprogram to execute. 2638 2681 * @param pcchResult Where to return the size of the result. Optional. 2639 2682 */ 2640 static char *kmk_exec_expand_subprog_to_tmp(PKMKCCEXPSUBPROG pSub Prog, uint32_t *pcchResult)2683 static char *kmk_exec_expand_subprog_to_tmp(PKMKCCEXPSUBPROG pSubprog, uint32_t *pcchResult) 2641 2684 { 2642 2685 char *pchOldVarBuf; … … 2651 2694 */ 2652 2695 pchDst = install_variable_buffer_with_hint(&pchOldVarBuf, &cbOldVarBuf, 2653 pSub Prog->Stats.cchAvg ? pSubProg->Stats.cchAvg + 32 : 256);2654 2655 pchDst = kmk_exec_expand_instruction_stream_to_var_buf(pSub Prog->pFirstInstr, pchDst);2696 pSubprog->Stats.cchAvg ? pSubprog->Stats.cchAvg + 32 : 256); 2697 2698 pchDst = kmk_exec_expand_instruction_stream_to_var_buf(pSubprog->pFirstInstr, pchDst); 2656 2699 2657 2700 /* Ensure that it's terminated. */ … … 2663 2706 if (pcchResult) 2664 2707 *pcchResult = cchResult; 2665 kmk_cc_exp_stats_update(&pSub Prog->Stats, cchResult);2708 kmk_cc_exp_stats_update(&pSubprog->Stats, cchResult); 2666 2709 2667 2710 variable_buffer = pchOldVarBuf; … … 2874 2917 /** 2875 2918 * Escaped end-of-line sequence in the current line. 2876 *2877 * This is initially noting down the start of the escape sequence and the EOL2878 * marker. But after kmk_cc_eval_prep_command_line or2879 * kmk_cc_eval_prep_normal_line it will change into copy instructions. The2880 * offEsc is the end position of the current line, while offEol is the start of2881 * the next line. If the next line doesn't contain anything to copy, offEsc2882 * will contain the same value as offEol on the previous.2883 2919 */ 2884 2920 typedef struct KMKCCEVALESCEOL 2885 2921 { 2886 /** Offset at which the EOL escape sequence starts for a non-command line. 2887 * After prepping the line, this will be moved back to indicate the end of 2888 * the copy sequence for that line. */ 2922 /** Offset at which the EOL escape sequence starts for a non-command line. */ 2889 2923 size_t offEsc; 2890 /** Offset of the newline sequence. 2891 * After prepping the line, this will indicate where to start copying on the 2892 * following line. This may be the same as the offEsc in the next entry. */ 2924 /** Offset of the newline sequence. */ 2893 2925 size_t offEol; 2894 2926 } KMKCCEVALESCEOL; 2895 2927 typedef KMKCCEVALESCEOL *PKMKCCEVALESCEOL; 2928 2929 2930 /** 2931 * String copy segment. 2932 */ 2933 typedef struct KMKCCEVALSTRCPYSEG 2934 { 2935 /** The start. */ 2936 const char *pchSrc; 2937 /** The number of chars to copy and whether to prepend space. 2938 * Negative values indicates that we should prepend a space. */ 2939 ssize_t cchSrcAndPrependSpace; 2940 } KMKCCEVALSTRCPYSEG; 2941 typedef KMKCCEVALSTRCPYSEG *PKMKCCEVALSTRCPYSEG; 2942 typedef KMKCCEVALSTRCPYSEG const *PCKMKCCEVALSTRCPYSEG; 2896 2943 2897 2944 … … 2920 2967 /** Length of the current line, sans the final EOL and comments. */ 2921 2968 size_t cchLine; 2969 /** Length of the current line, sans the final EOL but with comments. */ 2970 size_t cchLineWithComments; 2922 2971 2923 2972 /** The first char in an EOL sequence. … … 2932 2981 /** The minimum length of an esacped EOL sequence (cchEolSeq + 1). */ 2933 2982 size_t cchEscEolSeq; 2983 2984 /** String copy segments. */ 2985 PKMKCCEVALSTRCPYSEG paStrCopySegs; 2986 /** The number of segments that has been prepared. */ 2987 unsigned cStrCopySegs; 2988 /** The number of segments we've allocated. */ 2989 unsigned cStrCopySegsAllocated; 2934 2990 /** @} */ 2935 2991 … … 3068 3124 } 3069 3125 3126 3127 /** 3128 * Compiles a string expansion subprogram. 3129 * 3130 * @param pCompiler The compiler state. 3131 * @param pszExpr The expression to compile. 3132 * @param cchExpr The length of the expression. 3133 * @param pSubprog The subprogram to compile. 3134 */ 3135 static void kmk_cc_eval_compile_string_exp_subprog(PKMKCCEVALCOMPILER pCompiler, const char *pszExpr, size_t cchExpr, 3136 PKMKCCEXPSUBPROG pSubprog) 3137 { 3138 int rc = kmk_cc_exp_compile_subprog(pCompiler->ppBlockTail, pszExpr, cchExpr, pSubprog); 3139 if (rc == 0) 3140 return; 3141 kmk_cc_eval_fatal(pCompiler, NULL, "String expansion compile error"); 3142 } 3070 3143 3071 3144 … … 3500 3573 3501 3574 /** 3575 * Skips to the end of a variable name. 3576 * 3577 * This may advance pCompiler->iEscEol. 3578 * 3579 * @returns Pointer to the first char after the variable name. 3580 * @param pCompiler The compiler state. 3581 * @param pchWord The current position. Must be at the start of the 3582 * variable name. 3583 * @param cchLeft The number of chars left to parse in the current line. 3584 * @param pcchLeft The to store the updated count of characters left to 3585 * parse. 3586 * @param pfPlain Where to store the plain variable name indicator. 3587 * Returns 0 if plain, and 1 if there are variable 3588 * references in it. 3589 */ 3590 static const char *kmk_cc_eval_skip_var_name(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, 3591 size_t *pcchLeft, int *pfPlain) 3592 { 3593 const char * const pszContent = pCompiler->pszContent; 3594 size_t off = pchWord - pszContent; 3595 size_t const offLineEnd = off + cchLeft; 3596 int fPlain = 1; 3597 unsigned iEscEol = pCompiler->iEscEol; 3598 3599 /* Check our expectations. */ 3600 KMK_CC_ASSERT(cchLeft); 3601 KMK_CC_ASSERT(!KMK_CC_EVAL_IS_SPACE(*pchWord)); 3602 KMK_CC_ASSERT(iEscEol <= pCompiler->cEscEols); 3603 KMK_CC_ASSERT( iEscEol >= pCompiler->cEscEols 3604 || off < pCompiler->paEscEols[iEscEol].offEol); 3605 KMK_CC_ASSERT(off >= (iEscEol == 0 ? pCompiler->offLine : pCompiler->paEscEols[iEscEol - 1].offEol + pCompiler->cchEolSeq)); 3606 3607 /* 3608 * The outer loop parses plain text. Variable expansion ($) is handled 3609 * by an inner loop. 3610 */ 3611 while (off < offLineEnd) 3612 { 3613 char ch = pszContent[off]; 3614 if (!KMK_CC_EVAL_IS_SPACE_OR_VAR_OR_RECIPE(ch)) 3615 off++; 3616 else 3617 { 3618 if (KMK_CC_EVAL_IS_SPACE(ch)) 3619 break; 3620 3621 if (ch == '$') 3622 { 3623 off++; 3624 if (off < offLineEnd) 3625 { 3626 char const chOpen = pszContent[off]; 3627 if (chOpen == '(' || chOpen == '{') 3628 { 3629 /* 3630 * Got a $(VAR) or ${VAR} to deal with here. This may 3631 * include nested variable references and span multiple 3632 * lines (at least for function calls). 3633 * 3634 * We scan forward till we've found the corresponding 3635 * closing parenthesis, considering any open parentheses 3636 * of the same kind as worth counting, even if there are 3637 * no dollar preceeding them, just like GNU make does. 3638 */ 3639 size_t const offStart = off - 1; 3640 char const chClose = chOpen == '(' ? ')' : '}'; 3641 unsigned cOpen = 1; 3642 for (;;) 3643 { 3644 if (off < offLineEnd) 3645 { 3646 ch = pszContent[off]; 3647 if (!(KMK_CC_EVAL_IS_PAREN_OR_SLASH(ch))) 3648 off++; 3649 else 3650 { 3651 off++; 3652 if (ch == chClose) 3653 { 3654 if (--cOpen == 0) 3655 break; 3656 } 3657 else if (ch == chOpen) 3658 cOpen++; 3659 else if ( ch == '\\' 3660 && iEscEol < pCompiler->cEscEols 3661 && off == pCompiler->paEscEols[iEscEol].offEsc) 3662 { 3663 off = pCompiler->paEscEols[iEscEol].offEsc + pCompiler->cchEolSeq; 3664 iEscEol++; 3665 pCompiler->iEscEol = iEscEol; 3666 } 3667 } 3668 } 3669 else if (cOpen == 1) 3670 kmk_cc_eval_fatal(pCompiler, &pszContent[offStart], 3671 "Variable reference is missing '%c'", chClose); 3672 else 3673 kmk_cc_eval_fatal(pCompiler, &pszContent[offStart], 3674 "%u variable references are missing '%c'", cOpen, chClose); 3675 } 3676 } 3677 /* Single char variable name. */ 3678 else if (!KMK_CC_EVAL_IS_SPACE(chOpen)) 3679 { /* likely */ } 3680 else 3681 kmk_cc_eval_fatal(pCompiler, &pszContent[off], "Expected variable name after '$', not end of line"); 3682 } 3683 else 3684 kmk_cc_eval_fatal(pCompiler, &pszContent[off], "Expected variable name after '$', not end of line"); 3685 fPlain = 0; 3686 } 3687 /* Deal with potential escaped EOL. */ 3688 else if ( ch != '\\' 3689 || iEscEol >= pCompiler->cEscEols 3690 || off != pCompiler->paEscEols[iEscEol].offEsc ) 3691 off++; 3692 else 3693 break; 3694 } 3695 } 3696 3697 *pcchLeft = offLineEnd - off; 3698 *pfPlain = fPlain; 3699 return &pszContent[off]; 3700 } 3701 3702 3703 /** 3502 3704 * Prepares for copying a command line. 3503 3705 * … … 3622 3824 3623 3825 /** 3624 * Prepares for copying a normal line. 3625 * 3626 * This will modify the members of paEscEols to store copy instructions for the 3627 * following kmk_cc_eval_copy_prepped_normal_line() call. 3628 * 3629 * @returns The number of chars that will be copied by 3630 * kmk_cc_eval_copy_prepped_normal_line(). 3826 * Gather string from segments and optional space insertion trick. 3827 * 3828 * @param pszDst The destination buffer. 3829 * @param paSegs The source segments. 3830 * @param cSegs The number of segments. 3831 * @param cchDstPrepped The size of pszDst, excluding the terminator. 3832 */ 3833 static void kmk_cc_eval_strcpyv(char *pszDst, PCKMKCCEVALSTRCPYSEG paSegs, unsigned cSegs, size_t cchDstPrepped) 3834 { 3835 const char *pszDstStart = pszDst; 3836 unsigned iSeg = 0; 3837 while (iSeg < cSegs) 3838 { 3839 size_t cchToCopy; 3840 if (paSegs[iSeg].cchSrcAndPrependSpace >= 0) 3841 cchToCopy = paSegs[iSeg].cchSrcAndPrependSpace; 3842 else 3843 { 3844 cchToCopy = -paSegs[iSeg].cchSrcAndPrependSpace; 3845 *pszDst++ = ' '; 3846 } 3847 3848 memcpy(pszDst, paSegs[iSeg].pchSrc, cchToCopy); 3849 pszDst += cchToCopy; 3850 3851 iSeg++; 3852 } 3853 *pszDst = '\0'; 3854 KMK_CC_ASSERT(pszDst == &pszDstStart[cchDstPrepped]); K_NOREF(pszDstStart); K_NOREF(cchDstPrepped); 3855 } 3856 3857 /** 3858 * Helper for ensuring that we've got sufficient number of string copy segments. 3859 */ 3860 #define KMK_CC_EVAL_ENSURE_STRCOPY_SEGS(a_pCompiler, a_cRequiredSegs) \ 3861 do { \ 3862 if ((a_cRequiredSegs) < (a_pCompiler)->cStrCopySegsAllocated) \ 3863 { /* likely */ } \ 3864 else \ 3865 { \ 3866 unsigned cSegs = ((a_cRequiredSegs) + 3 /*15*/) & ~(unsigned)3/*15*/; \ 3867 KMK_CC_ASSERT((a_cRequiredSegs) < 0x8000); \ 3868 (a_pCompiler)->paStrCopySegs = (PKMKCCEVALSTRCPYSEG)xmalloc(cSegs * sizeof((a_pCompiler)->paStrCopySegs)[0]); \ 3869 } \ 3870 } while (0) 3871 3872 3873 /** 3874 * Prepares for copying a normal line, extended version. 3875 * 3876 * This does not assume that we start on a word, it can handle any starting 3877 * character. It can also prepare partial copies. 3878 * 3879 * In addition to the returned information, this will store instruction in 3880 * paEscEols for the following kmk_cc_eval_strcpyv() call. 3881 * 3882 * This will advance pCompiler->iEscEol, so that it's possible to use the common 3883 * macros and helpers for parsing what comes afterwards. 3884 * 3885 * @returns The number of chars that will be copied by kmk_cc_eval_strcpyv(). 3886 * @param pCompiler The compiler instance data. 3887 * @param pchWord Pointer to the first char to copy from the 3888 * current line. This must be the start of a 3889 * word. 3890 * @param cchLeft The number of chars left on the current line 3891 * starting at @a pchWord. 3892 */ 3893 static size_t kmk_cc_eval_prep_normal_line_ex(PKMKCCEVALCOMPILER pCompiler, const char * const pchWord, size_t cchLeft) 3894 { 3895 size_t cchRet; 3896 unsigned iEscEol = pCompiler->iEscEol; 3897 unsigned const cEscEols = pCompiler->cEscEols; 3898 3899 KMK_CC_ASSERT(cchLeft >= 0); 3900 KMK_CC_ASSERT(iEscEol <= cEscEols); 3901 3902 if (cchLeft > 0) 3903 { 3904 /* 3905 * If there are no escaped EOLs left, just copy exactly 3906 * what was passed in. 3907 */ 3908 if (iEscEol >= cEscEols) 3909 { 3910 KMK_CC_EVAL_ENSURE_STRCOPY_SEGS(pCompiler, 1); 3911 pCompiler->cStrCopySegs = 1; 3912 pCompiler->paStrCopySegs[0].pchSrc = pchWord; 3913 pCompiler->paStrCopySegs[0].cchSrcAndPrependSpace = cchRet = cchLeft; 3914 } 3915 /* 3916 * Ok, we have to deal with escaped EOLs and do the proper 3917 * replacement of escaped newlines with space. The deal is that we 3918 * collaps all whitespace before and after one or more newlines into a 3919 * single space. (FreeBSD make does this differently, by the by.) 3920 */ 3921 else 3922 { 3923 const char * const pszContent = pCompiler->pszContent; 3924 size_t offWord = pchWord - pCompiler->pszContent; 3925 size_t const offLineEnd = offWord + cchLeft; /* Note! Not necessarily end of line.*/ 3926 size_t offEsc; 3927 size_t fPendingSpace = 0; 3928 unsigned cSegs = 0; 3929 size_t cchSeg; 3930 3931 /* Go nuts checking our preconditions here. */ 3932 KMK_CC_ASSERT(offWord >= pCompiler->offLine); 3933 KMK_CC_ASSERT(offWord + cchLeft <= pCompiler->offLine + pCompiler->cchLine); 3934 KMK_CC_ASSERT(offWord + cchLeft <= pCompiler->cchContent); 3935 KMK_CC_ASSERT(offWord <= pCompiler->paEscEols[iEscEol].offEsc); 3936 KMK_CC_ASSERT(offWord >= (iEscEol ? pCompiler->paEscEols[cEscEols - 1].offEol + pCompiler->cchEolSeq 3937 : pCompiler->offLine)); 3938 KMK_CC_ASSERT(offWord < offLineEnd); 3939 3940 /* Make sure we've got more than enough segments to fill in. */ 3941 KMK_CC_EVAL_ENSURE_STRCOPY_SEGS(pCompiler, cEscEols - iEscEol + 2); 3942 3943 /* 3944 * All but the last line. 3945 */ 3946 cchRet = 0; 3947 do 3948 { 3949 KMK_CC_ASSERT(offWord < offLineEnd); 3950 offEsc = pCompiler->paEscEols[iEscEol].offEsc; 3951 if (offWord < offEsc) 3952 { 3953 /* Strip trailing spaces. */ 3954 while (offEsc > offWord && KMK_CC_EVAL_IS_SPACE(pszContent[offEsc - 1])) 3955 offEsc--; 3956 cchSeg = offEsc - offWord; 3957 if (cchSeg) 3958 { 3959 /* Add segment. */ 3960 pCompiler->paStrCopySegs[cSegs].pchSrc = &pszContent[offWord]; 3961 if (offEsc < offLineEnd) 3962 { 3963 pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = fPendingSpace 3964 ? -(ssize_t)cchSeg : (ssize_t)cchSeg; 3965 cchRet += cchSeg + fPendingSpace; 3966 cSegs += 1; 3967 fPendingSpace = 1; 3968 } 3969 else 3970 { 3971 cchSeg = offLineEnd - offWord; 3972 pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = fPendingSpace 3973 ? -(ssize_t)cchSeg : (ssize_t)cchSeg; 3974 pCompiler->cStrCopySegs = cSegs + 1; 3975 pCompiler->iEscEol = iEscEol; 3976 return cchRet + cchSeg + fPendingSpace; 3977 } 3978 } 3979 } 3980 else 3981 KMK_CC_ASSERT(offWord == offEsc); 3982 3983 /* Next line. */ 3984 offWord = pCompiler->paEscEols[iEscEol].offEol + pCompiler->cchEolSeq; 3985 iEscEol++; 3986 3987 /* Strip leading spaces. */ 3988 while (offWord < offLineEnd && KMK_CC_EVAL_IS_SPACE(pszContent[offWord])) 3989 offWord++; 3990 if (offWord >= offLineEnd) 3991 { 3992 pCompiler->cStrCopySegs = cSegs; 3993 pCompiler->iEscEol = iEscEol; 3994 return cchRet; 3995 } 3996 } while (iEscEol < cEscEols); 3997 3998 /* 3999 * The last line. 4000 */ 4001 cchSeg = offLineEnd - offWord; 4002 cchRet += cchSeg; 4003 pCompiler->paStrCopySegs[cSegs].pchSrc = &pszContent[offWord]; 4004 pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = fPendingSpace 4005 ? -(ssize_t)cchSeg : (ssize_t)cchSeg; 4006 pCompiler->cStrCopySegs = cSegs + 1; 4007 pCompiler->iEscEol = iEscEol; 4008 } 4009 } 4010 /* 4011 * Odd case: Nothing to copy. 4012 */ 4013 else 4014 { 4015 cchRet = 0; 4016 pCompiler->cStrCopySegs = 0; 4017 } 4018 return cchRet; 4019 } 4020 4021 4022 /** 4023 * Prepares for copying a normal line, from the given position all the way to 4024 * the end. 4025 * 4026 * In addition to the returned information, this will store instruction in 4027 * paStrCopySegs and cSTrCopySeg for the following kmk_cc_eval_strcpyv() call. 4028 * 4029 * @returns The number of chars that will be copied by kmk_cc_eval_strcpyv(). 3631 4030 * @param pCompiler The compiler instance data. 3632 4031 * @param pchWord Pointer to the first char to copy from the … … 3648 4047 KMK_CC_ASSERT(iEscEol <= cEscEols); 3649 4048 4049 /* 4050 * If there are no escaped EOLs left, just copy what was specified, 4051 * optionally sans any trailing spaces. 4052 */ 3650 4053 if (iEscEol >= cEscEols) 3651 4054 { 3652 /*3653 * No escaped EOLs left, simple. Just need to strip trailing spaces3654 * when desired by the caller.3655 */3656 4055 cchRet = cchLeft; 3657 4056 if (fStripTrailingSpaces) 3658 4057 while (cchRet > 0 && KMK_CC_IS_SPACE_CH(pchWord[cchRet - 1])) 3659 4058 cchRet--; 3660 } 4059 4060 KMK_CC_EVAL_ENSURE_STRCOPY_SEGS(pCompiler, 1); 4061 pCompiler->cStrCopySegs = 1; 4062 pCompiler->paStrCopySegs[0].pchSrc = pchWord; 4063 pCompiler->paStrCopySegs[0].cchSrcAndPrependSpace = cchRet; 4064 } 4065 /* 4066 * Ok, we have to deal with escaped EOLs and do the proper 4067 * replacement of escaped newlines with space. The deal is that we 4068 * collaps all whitespace before and after one or more newlines into a 4069 * single space. (FreeBSD make does this differently, by the by.) 4070 */ 3661 4071 else 3662 4072 { 3663 /*3664 * This is a tad complicated. Working with offsets here is simpler.3665 */3666 4073 const char *pszContent = pCompiler->pszContent; 3667 4074 size_t offWord = pchWord - pCompiler->pszContent; 3668 4075 size_t offEsc; 3669 4076 size_t fPendingSpace; 4077 size_t cchSeg; 4078 unsigned cSegs = 0; 3670 4079 3671 4080 /* Go nuts checking our preconditions here. */ … … 3676 4085 KMK_CC_ASSERT(offWord >= (iEscEol ? pCompiler->paEscEols[cEscEols - 1].offEol + pCompiler->cchEolSeq : pCompiler->offLine)); 3677 4086 3678 /* First line - We're at the start of a word, so no left stripping needed. */ 4087 /* Make sure we've got more than enough segments to fill in. */ 4088 KMK_CC_EVAL_ENSURE_STRCOPY_SEGS(pCompiler, cEscEols - iEscEol + 2); 4089 4090 /* 4091 * First line - We're at the start of a word, so no left stripping needed. 4092 */ 3679 4093 offEsc = pCompiler->paEscEols[iEscEol].offEsc; 3680 4094 KMK_CC_ASSERT(offEsc > offWord); … … 3685 4099 fPendingSpace = 1; 3686 4100 cchRet = offEsc - offWord; 3687 pCompiler->paEscEols[iEscEol].offEsc = offEsc; 4101 pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = cchRet; 4102 pCompiler->paStrCopySegs[cSegs].pchSrc = pchWord; 3688 4103 3689 4104 offWord = pCompiler->paEscEols[iEscEol].offEol + pCompiler->cchEolSeq; 3690 4105 iEscEol++; 3691 4106 3692 /* All but the last line. */ 4107 /* 4108 * All but the last line. 4109 */ 3693 4110 while (iEscEol < cEscEols) 3694 4111 { 3695 4112 offEsc = pCompiler->paEscEols[iEscEol].offEsc; 4113 4114 /* Strip leading spaces. */ 3696 4115 while (offWord < offEsc && KMK_CC_EVAL_IS_SPACE(pszContent[offWord])) 3697 4116 offWord++; … … 3699 4118 if (offWord < offEsc) 3700 4119 { 4120 /* Strip trailing spaces. */ 3701 4121 while (KMK_CC_EVAL_IS_SPACE(pszContent[offEsc - 1])) 3702 4122 offEsc--; 3703 cchRet += offEsc - offWord + fPendingSpace; 4123 cchSeg = offEsc - offWord; 4124 pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = fPendingSpace ? -(ssize_t)cchSeg : (ssize_t)cchSeg; 4125 cchRet += cchSeg + fPendingSpace; 4126 pCompiler->paStrCopySegs[cSegs].pchSrc = &pszContent[offWord]; 4127 cSegs += 1; 3704 4128 fPendingSpace = 1; 3705 4129 } 3706 4130 3707 pCompiler->paEscEols[iEscEol - 1].offEol = offWord; 3708 pCompiler->paEscEols[iEscEol].offEsc = offEsc; 3709 4131 /* Next. */ 3710 4132 offWord = pCompiler->paEscEols[iEscEol].offEol + pCompiler->cchEolSeq; 3711 4133 iEscEol++; 3712 4134 } 3713 4135 3714 /* Final line. We must calculate the end of line offset our selves here. */ 4136 /* 4137 * Final line. We must calculate the end of line offset our selves here. 4138 */ 3715 4139 offEsc = &pchWord[cchLeft] - pszContent; 3716 4140 while (offWord < offEsc && KMK_CC_EVAL_IS_SPACE(pszContent[offWord])) … … 3722 4146 while (KMK_CC_EVAL_IS_SPACE(pszContent[offEsc - 1])) 3723 4147 offEsc--; 3724 cchRet += offEsc - offWord + fPendingSpace; 4148 cchSeg = offEsc - offWord; 4149 pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = fPendingSpace ? -(ssize_t)cchSeg : (ssize_t)cchSeg; 4150 cchRet += cchSeg + fPendingSpace; 4151 pCompiler->paStrCopySegs[cSegs].pchSrc = &pszContent[offWord]; 4152 cSegs += 1; 3725 4153 } 3726 pCompiler->paEscEols[iEscEol - 1].offEol = offWord; 4154 4155 pCompiler->cStrCopySegs = cSegs; 3727 4156 } 3728 4157 return cchRet; 3729 }3730 3731 3732 /**3733 * Copies a normal line to the buffer @a pszDst points to.3734 *3735 * Must only be used immediately after kmk_cc_eval_prep_normal_line().3736 *3737 * @param pCompiler The compiler instance data.3738 * @param pchLeft Pointer to the first char to copy from the current line.3739 * This does not have to the start of a word.3740 * @param cchPrepped The return value of kmk_cc_eval_prep_normal_line().3741 * @param pszDst The destination buffer, must be at least @a cchPrepped3742 * plus one (terminator) char big.3743 */3744 static void kmk_cc_eval_copy_prepped_normal_line(PKMKCCEVALCOMPILER pCompiler, const char *pchWord,3745 size_t cchPrepped, char *pszDst)3746 {3747 unsigned iEscEol = pCompiler->iEscEol;3748 unsigned const cEscEols = pCompiler->cEscEols;3749 if (iEscEol >= cEscEols)3750 {3751 /* Single line. */3752 memcpy(pszDst, pchWord, cchPrepped);3753 pszDst[cchPrepped] = '\0';3754 }3755 else3756 {3757 /* offEsc = end of copy on a line, offWord/offEol is where to start on the next. */3758 size_t offWord = pchWord - pCompiler->pszContent;3759 int fPendingSpace = 0;3760 char * const pszDstStart = pszDst;3761 size_t cchCopy;3762 do3763 {3764 cchCopy = pCompiler->paEscEols[iEscEol].offEsc - offWord;3765 KMK_CC_ASSERT(pCompiler->paEscEols[iEscEol].offEsc >= offWord);3766 if (cchCopy)3767 {3768 if (fPendingSpace)3769 *pszDst++ = ' ';3770 memcpy(pszDst, &pCompiler->pszContent[offWord], cchCopy);3771 pszDst += cchCopy;3772 fPendingSpace = 1;3773 }3774 offWord = pCompiler->paEscEols[iEscEol].offEol;3775 iEscEol++;3776 } while (iEscEol < cEscEols);3777 3778 /* The final line is delimited by cchPrepped. */3779 cchCopy = cchPrepped - (pszDst - pszDstStart);3780 KMK_CC_ASSERT(cchCopy <= cchPrepped);3781 if (cchCopy > 0)3782 {3783 if (fPendingSpace)3784 *pszDst++ = ' ';3785 memcpy(pszDst, &pCompiler->pszContent[offWord], cchCopy);3786 pszDst += cchCopy;3787 }3788 *pszDst = '\0';3789 KMK_CC_ASSERT(pszDst == &pszDstStart[cchPrepped]);3790 }3791 4158 } 3792 4159 … … 3847 4214 PKMKCCEVALIFEXPR pInstr = (PKMKCCEVALIFEXPR)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, 3848 4215 KMKCCEVALIFEXPR_SIZE(cchExpr)); 3849 kmk_cc_eval_ copy_prepped_normal_line(pCompiler, pchWord, cchExpr, pInstr->szExpr);4216 kmk_cc_eval_strcpyv(pInstr->szExpr, pCompiler->paStrCopySegs, pCompiler->cStrCopySegs, cchExpr); 3850 4217 pInstr->cchExpr = cchExpr; 3851 4218 pInstr->IfCore.Core.enmOpCode = kKmkCcEvalInstr_if; … … 3859 4226 3860 4227 4228 /** 4229 * Deals with 'ifdef var', 'ifndef var', 'else ifdef var' and 'else ifndef var' 4230 * statements. 4231 * 4232 * @returns 1 to indicate we've handled a keyword (see 4233 * kmk_cc_eval_try_handle_keyword). 4234 * @param pCompiler The compiler state. 4235 * @param pchWord First char after 'define'. 4236 * @param cchLeft The number of chars left to parse on this line. 4237 * @param fInElse Set if this is an 'else if' (rather than just 'if'). 4238 * @param fPositiveStmt Set if 'ifdef', clear if 'ifndef'. 4239 */ 3861 4240 static int kmk_cc_eval_do_ifdef(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, int fInElse, int fPositiveStmt) 3862 4241 { 4242 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); 4243 if (cchLeft) 4244 { 4245 /* 4246 * Skip to the end of the variable name. 4247 */ 4248 unsigned const iSavedEscEol = pCompiler->iEscEol; 4249 const char * const pchVarNm = pchWord; 4250 int fPlain; 4251 pchWord = kmk_cc_eval_skip_var_name(pCompiler, pchWord, cchLeft, &cchLeft, &fPlain); 4252 KMK_CC_ASSERT(pCompiler->iEscEol == iSavedEscEol || !fPlain); 4253 if (fPlain) 4254 { 4255 size_t const cchVarNm = pchWord - pchVarNm; 4256 PKMKCCEVALIFDEFPLAIN pInstr; 4257 pInstr = (PKMKCCEVALIFDEFPLAIN)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr)); 4258 pInstr->IfCore.Core.enmOpCode = fPositiveStmt ? kKmkCcEvalInstr_ifdef_plain : kKmkCcEvalInstr_ifndef_plain; 4259 pInstr->IfCore.Core.iLine = pCompiler->iLine; 4260 pInstr->pszName = strcache2_add(&variable_strcache, pchVarNm, cchVarNm); 4261 kmk_cc_eval_do_if_core(pCompiler, &pInstr->IfCore, fInElse); 4262 } 4263 else 4264 { 4265 PKMKCCEVALIFDEFDYNAMIC pInstr; 4266 size_t const cchVarNm = pchWord - pchVarNm; 4267 size_t cchCopy; 4268 char *pszCopy; 4269 pCompiler->iEscEol = iSavedEscEol; 4270 cchCopy = kmk_cc_eval_prep_normal_line(pCompiler, pchVarNm, cchVarNm, 0 /*fStripTrailingSpaces*/); 4271 4272 pInstr = (PKMKCCEVALIFDEFDYNAMIC)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr)); 4273 4274 /** @todo Make the subprogram embed necessary strings. */ 4275 pszCopy = kmk_cc_block_alloc_eval_string(pCompiler->ppBlockTail, cchCopy + 1); 4276 kmk_cc_eval_strcpyv(pszCopy, pCompiler->paStrCopySegs, pCompiler->cStrCopySegs, cchCopy); 4277 4278 pInstr->IfCore.Core.enmOpCode = fPositiveStmt ? kKmkCcEvalInstr_ifdef_dynamic : kKmkCcEvalInstr_ifndef_dynamic; 4279 pInstr->IfCore.Core.iLine = pCompiler->iLine; 4280 kmk_cc_eval_compile_string_exp_subprog(pCompiler, pszCopy, cchCopy, &pInstr->NameSubprog); 4281 4282 kmk_cc_eval_do_if_core(pCompiler, &pInstr->IfCore, fInElse); 4283 } 4284 4285 /* 4286 * Make sure there is nothing following the variable name. 4287 */ 4288 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); 4289 if (cchLeft) 4290 kmk_cc_eval_fatal(pCompiler, pchWord, "Bogus stuff after 'if%sdef' variable name", fPositiveStmt ? "" : "n"); 4291 } 4292 else 4293 kmk_cc_eval_fatal(pCompiler, pchWord, "Expected expression after 'if' directive"); 3863 4294 return 1; 3864 4295 } … … 3867 4298 static int kmk_cc_eval_do_ifeq(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, int fInElse, int fPositiveStmt) 3868 4299 { 4300 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); 4301 if (cchLeft) 4302 { 4303 /* 4304 * There are two forms: 4305 * 4306 * ifeq (string1, string2) 4307 * ifeq "string1" 'string2' 4308 * 4309 */ 4310 const char * const pchEnd = &pchWord[cchLeft]; 4311 PKMKCCEVALIFEQ pInstr; 4312 4313 struct 4314 { 4315 char *pszCopy; 4316 size_t cchCopy; 4317 int fPlain; 4318 } Left, Right; 4319 4320 char ch = *pchWord; 4321 if (ch == '(') 4322 { 4323 // unsigned cCounts; 4324 4325 /* Skip the parenthesis. */ 4326 pchWord++; 4327 cchLeft--; 4328 4329 /** @todo continue here. */ 4330 } 4331 else if (ch == '"' || ch == '\'') 4332 { 4333 const char *pchTmp; 4334 4335 /* 4336 * Quoted left side. 4337 */ 4338 /* Skip leading quote. */ 4339 pchWord++; 4340 cchLeft--; 4341 4342 /* Locate the end quote. */ 4343 pchTmp = (const char *)memchr(pchWord, ch, cchLeft); 4344 if (pchTmp) { /* likely */ } 4345 else kmk_cc_eval_fatal(pCompiler, pchWord - 1, "Unbalanced quote in first if%seq string", fPositiveStmt ? "" : "n"); 4346 4347 Left.cchCopy = kmk_cc_eval_prep_normal_line_ex(pCompiler, pchWord, pchTmp - pchWord); 4348 Left.pszCopy = kmk_cc_block_alloc_eval_string(pCompiler->ppBlockTail, Left.cchCopy + 1); 4349 kmk_cc_eval_strcpyv(Left.pszCopy, pCompiler->paStrCopySegs, pCompiler->cStrCopySegs, Left.cchCopy); 4350 Left.fPlain = memchr(Left.pszCopy, '$', Left.cchCopy) == NULL; 4351 4352 /* skip end quote */ 4353 pchWord = pchTmp + 1; 4354 cchLeft = pchEnd - pchWord; 4355 4356 /* Skip anything inbetween the left and right hand side (not mandatory). */ 4357 if ( cchLeft /** @todo replace with straight 'isspace' that takes escaped EOLs into account. */ 4358 && KMK_CC_EVAL_IS_SPACE_AFTER_WORD(pCompiler, pchWord[0], pchWord[1], cchLeft)) 4359 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); 4360 4361 /* 4362 * Quoted right side. 4363 */ 4364 if ( cchLeft > 0 4365 && ( (ch = *pchWord) != '"' || ch == '\'') ) 4366 { 4367 /* Skip leading quote. */ 4368 pchWord++; 4369 cchLeft--; 4370 4371 /* Locate the end quote. */ 4372 pchTmp = (const char *)memchr(pchWord, ch, cchLeft); 4373 if (pchTmp) { /* likely */ } 4374 else kmk_cc_eval_fatal(pCompiler, pchWord - 1, "Unbalanced quote in second if%seq string", fPositiveStmt ? "" : "n"); 4375 4376 Right.cchCopy = kmk_cc_eval_prep_normal_line_ex(pCompiler, pchWord, pchTmp - pchWord); 4377 Right.pszCopy = kmk_cc_block_alloc_eval_string(pCompiler->ppBlockTail, Right.cchCopy + 1); 4378 kmk_cc_eval_strcpyv(Left.pszCopy, pCompiler->paStrCopySegs, pCompiler->cStrCopySegs, Right.cchCopy); 4379 Right.fPlain = memchr(Right.pszCopy, '$', Right.cchCopy) == NULL; 4380 4381 /* skip end quote */ 4382 pchWord = pchTmp + 1; 4383 cchLeft = pchEnd - pchWord; 4384 } 4385 else 4386 kmk_cc_eval_fatal(pCompiler, pchWord, "Expected a second quoted string for 'if%seq'", 4387 fPositiveStmt ? "" : "n"); 4388 } 4389 else 4390 kmk_cc_eval_fatal(pCompiler, pchWord, "Expected parentheses or quoted string after 'if%seq'", 4391 fPositiveStmt ? "" : "n"); 4392 4393 /* 4394 * 4395 */ 4396 pInstr = (PKMKCCEVALIFEQ)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr)); 4397 4398 4399 /* 4400 * Make sure there is nothing following the variable name. 4401 */ 4402 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); 4403 if (cchLeft) 4404 kmk_cc_eval_fatal(pCompiler, pchWord, "Bogus stuff after 'if%sdef' variable name", fPositiveStmt ? "" : "n"); 4405 } 4406 else 4407 kmk_cc_eval_fatal(pCompiler, pchWord, "Expected expression after 'if' directive"); 3869 4408 return 1; 3870 4409 } … … 3933 4472 3934 4473 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "eq", 2)) 3935 return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 2, cchLeft +2, 1 /* in else */, 1 /* positive */);4474 return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 2, cchLeft - 2, 1 /* in else */, 1 /* positive */); 3936 4475 3937 4476 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "def", 3)) 3938 return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 3, cchLeft +3, 1 /* in else */, 1 /* positive */);4477 return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 3, cchLeft - 3, 1 /* in else */, 1 /* positive */); 3939 4478 3940 4479 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "neq", 3)) 3941 return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 3, cchLeft +3, 1 /* in else */, 0 /* positive */);4480 return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 3, cchLeft - 3, 1 /* in else */, 0 /* positive */); 3942 4481 3943 4482 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "1of", 3)) 3944 return kmk_cc_eval_do_if1of(pCompiler, pchWord + 3, cchLeft +3, 1 /* in else */, 1 /* positive */);4483 return kmk_cc_eval_do_if1of(pCompiler, pchWord + 3, cchLeft - 3, 1 /* in else */, 1 /* positive */); 3945 4484 3946 4485 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "ndef", 4)) 3947 return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 4, cchLeft +4, 1 /* in else */, 0 /* positive */);4486 return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 4, cchLeft - 4, 1 /* in else */, 0 /* positive */); 3948 4487 3949 4488 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "n1of", 4)) 3950 return kmk_cc_eval_do_if1of(pCompiler, pchWord + 4, cchLeft +4, 1 /* in else */, 0 /* positive */);4489 return kmk_cc_eval_do_if1of(pCompiler, pchWord + 4, cchLeft - 4, 1 /* in else */, 0 /* positive */); 3951 4490 3952 4491 pchWord -= 2; … … 4123 4662 * @param fQualifiers The qualifiers. 4124 4663 */ 4125 static int kmk_cc_eval_handle_var_export(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, 4126 unsigned fQualifiers) 4664 static int kmk_cc_eval_handle_var_export(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, unsigned fQualifiers) 4127 4665 { 4128 4666 … … 4142 4680 */ 4143 4681 static int kmk_cc_eval_try_handle_var_with_keywords(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, 4144 4682 unsigned fQualifiers) 4145 4683 { 4146 4684 for (;;) … … 4194 4732 else 4195 4733 kmk_cc_eval_fatal(pCompiler, NULL, 4196 4734 "Expected assignment operator or variable directive after variable qualifier(s)\n"); 4197 4735 } 4198 4736 } … … 4262 4800 4263 4801 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "eq", 2)) 4264 return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 2, cchLeft +2, 0 /* in else */, 1 /* positive */);4802 return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 2, cchLeft - 2, 0 /* in else */, 1 /* positive */); 4265 4803 4266 4804 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "def", 3)) 4267 return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 3, cchLeft +3, 0 /* in else */, 1 /* positive */);4805 return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 3, cchLeft - 3, 0 /* in else */, 1 /* positive */); 4268 4806 4269 4807 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "neq", 3)) 4270 return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 3, cchLeft +3, 0 /* in else */, 0 /* positive */);4808 return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 3, cchLeft - 3, 0 /* in else */, 0 /* positive */); 4271 4809 4272 4810 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "1of", 3)) 4273 return kmk_cc_eval_do_if1of(pCompiler, pchWord + 3, cchLeft +3, 0 /* in else */, 1 /* positive */);4811 return kmk_cc_eval_do_if1of(pCompiler, pchWord + 3, cchLeft - 3, 0 /* in else */, 1 /* positive */); 4274 4812 4275 4813 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "ndef", 4)) 4276 return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 4, cchLeft +4, 0 /* in else */, 0 /* positive */);4814 return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 4, cchLeft - 4, 0 /* in else */, 0 /* positive */); 4277 4815 4278 4816 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "n1of", 4)) 4279 return kmk_cc_eval_do_if1of(pCompiler, pchWord + 4, cchLeft +4, 0 /* in else */, 0 /* positive */);4817 return kmk_cc_eval_do_if1of(pCompiler, pchWord + 4, cchLeft - 4, 0 /* in else */, 0 /* positive */); 4280 4818 } 4281 4819 /* include... */ … … 4293 4831 return kmk_cc_eval_do_include(pCompiler, pchWord, cchLeft, kKmkCcEvalInstr_includedep); 4294 4832 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "-queue", 6)) 4295 return kmk_cc_eval_do_include(pCompiler, pchWord + 6, cchLeft +6, kKmkCcEvalInstr_includedep_queue);4833 return kmk_cc_eval_do_include(pCompiler, pchWord + 6, cchLeft - 6, kKmkCcEvalInstr_includedep_queue); 4296 4834 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "-flush", 6)) 4297 return kmk_cc_eval_do_include(pCompiler, pchWord + 6, cchLeft +6, kKmkCcEvalInstr_includedep_flush);4835 return kmk_cc_eval_do_include(pCompiler, pchWord + 6, cchLeft - 6, kKmkCcEvalInstr_includedep_flush); 4298 4836 } 4299 4837 } … … 4302 4840 { 4303 4841 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "else", 4)) 4304 return kmk_cc_eval_do_else(pCompiler, pchWord + 4, cchLeft +4);4842 return kmk_cc_eval_do_else(pCompiler, pchWord + 4, cchLeft - 4); 4305 4843 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "endif", 5)) 4306 return kmk_cc_eval_do_endif(pCompiler, pchWord + 5, cchLeft +5);4844 return kmk_cc_eval_do_endif(pCompiler, pchWord + 5, cchLeft - 5); 4307 4845 /* export and endef are handled elsewhere, though stray endef's may end up here... */ 4308 4846 KMK_CC_ASSERT(!KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "export", 6)); … … 4313 4851 if ( KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "sinclude", 8) 4314 4852 || KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "-include", 8)) 4315 return kmk_cc_eval_do_include(pCompiler, pchWord + 8, cchLeft +8, kKmkCcEvalInstr_include_silent);4853 return kmk_cc_eval_do_include(pCompiler, pchWord + 8, cchLeft - 8, kKmkCcEvalInstr_include_silent); 4316 4854 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "vpath", 5)) 4317 return kmk_cc_eval_do_vpath(pCompiler, pchWord + 5, cchLeft +5);4855 return kmk_cc_eval_do_vpath(pCompiler, pchWord + 5, cchLeft - 5); 4318 4856 4319 4857 KMK_CC_ASSERT(!KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "local", 5)); … … 4372 4910 /* Simple case: No escaped EOL, nor the end of the input. */ 4373 4911 pchTmp = (const char *)memchr(&pszContent[offNext], chFirstEol, cchContent - offNext); 4374 if (pchTmp && (&pszContent[offNext] == pchTmp || pchTmp[-1] != '\\') ) 4912 if ( pchTmp 4913 && ( &pszContent[offNext] == pchTmp 4914 || pchTmp[-1] != '\\') ) 4375 4915 { 4376 4916 if ( cchEolSeq == 1 4377 4917 || pchTmp[1] == Compiler.chSecondEol) 4378 4918 { 4379 /* Frequent: Blank line or comment line. Skip. */ 4380 if ( &pszContent[offNext] == pchTmp 4381 || pszContent[offNext] == '#') 4919 /* Frequent: Blank line. */ 4920 if (&pszContent[offNext] == pchTmp) 4382 4921 { 4383 iLine++; 4922 fprintf(stderr, "#%03u: <empty>\n", Compiler.iLine, &pszContent[off]); 4923 Compiler.iLine++; 4384 4924 off = offNext += cchEolSeq; 4385 4925 continue; 4386 4926 } 4387 4388 cchLine = pchTmp - pszContent; 4389 offNext = cchLine + cchEolSeq; 4927 if (pszContent[offNext] == '#') 4928 { 4929 fprintf(stderr, "#%03u: <comment>\n", Compiler.iLine, &pszContent[off]); 4930 Compiler.iLine++; 4931 offNext = pchTmp - pszContent; 4932 off = offNext += cchEolSeq; 4933 continue; 4934 } 4935 4936 offNext = pchTmp - pszContent; 4937 cchLine = offNext - off; 4938 4939 offFirstWord = off; 4940 while (offFirstWord < offNext && KMK_CC_EVAL_IS_SPACE(pszContent[offFirstWord])) 4941 offFirstWord++; 4942 4943 offNext += cchEolSeq; 4390 4944 Compiler.cEscEols = 0; 4391 4945 Compiler.iEscEol = 0; 4392 4393 offFirstWord = off;4394 while (offFirstWord < cchLine && KMK_CC_EVAL_IS_SPACE(pszContent[offFirstWord]))4395 offFirstWord++;4396 4946 } 4397 4947 else 4398 kmk_cc_eval_fatal_eol(&Compiler, pchTmp, iLine, off);4948 kmk_cc_eval_fatal_eol(&Compiler, pchTmp, Compiler.iLine, off); 4399 4949 } 4400 4950 /* The complicated, less common cases. */ … … 4407 4957 { 4408 4958 if (offFirstWord == offNext) 4409 while (offFirstWord < cchLine && KMK_CC_EVAL_IS_SPACE(pszContent[offFirstWord])) 4959 { 4960 size_t offEol = off + cchLine; 4961 while (offFirstWord < off + cchLine && KMK_CC_EVAL_IS_SPACE(pszContent[offFirstWord])) 4410 4962 offFirstWord++; 4963 } 4411 4964 4412 4965 if (pchTmp) … … 4416 4969 { 4417 4970 size_t offEsc; 4418 offNext = pchTmp - pszContent; 4971 if (offFirstWord != offNext) 4972 offNext = pchTmp - pszContent; 4973 else 4974 { 4975 offNext = pchTmp - pszContent; 4976 while (offFirstWord < offNext && KMK_CC_EVAL_IS_SPACE(pszContent[offFirstWord])) 4977 offFirstWord++; 4978 } 4979 4419 4980 4420 4981 /* Is it an escape sequence? */ … … 4468 5029 } 4469 5030 else 4470 kmk_cc_eval_fatal_eol(&Compiler, pchTmp, iLine, off);5031 kmk_cc_eval_fatal_eol(&Compiler, pchTmp, Compiler.iLine, off); 4471 5032 } 4472 5033 else 4473 5034 { 4474 5035 /* End of input. Happens only once per compilation, nothing to optimize for. */ 5036 if (offFirstWord == offNext) 5037 while (offFirstWord < cchContent && KMK_CC_EVAL_IS_SPACE(pszContent[offFirstWord])) 5038 offFirstWord++; 4475 5039 offNext = cchContent; 4476 5040 cchLine = cchContent - off; … … 4481 5045 } 4482 5046 KMK_CC_ASSERT(offNext <= cchContent); 5047 KMK_CC_ASSERT(offNext >= off + cchLine); 4483 5048 KMK_CC_ASSERT(off + cchLine <= cchContent && cchLine <= cchContent); 4484 KMK_CC_ASSERT(offFirstWord <= cchLine);5049 KMK_CC_ASSERT(offFirstWord <= off + cchLine); 4485 5050 KMK_CC_ASSERT(offFirstWord >= off); 4486 5051 KMK_CC_ASSERT(pszContent[offFirstWord] != ' ' && pszContent[offFirstWord] != '\t'); 5052 { 5053 char chSaved = ((char *)pszContent)[off+cchLine] = '\0'; 5054 fprintf(stderr, "#%03u: %s\n", Compiler.iLine, &pszContent[off]); 5055 ((char *)pszContent)[off+cchLine] = chSaved; 5056 } 4487 5057 4488 5058 /* 4489 * Check for comments and skip blank lines.5059 * Skip blank lines. 4490 5060 */ 4491 if ( offFirstWord < cchLine 4492 && pszContent[offFirstWord] != '#') 5061 if (offFirstWord < off + cchLine) 4493 5062 { 4494 const char *pchWord = &pszContent[offFirstWord];4495 size_t cchLeft = cchLine - offFirstWord;4496 pchTmp = (const char *)memchr(pchWord, '#', cchLeft); /** @todo not correct for command lines! */4497 if (pchTmp)4498 {4499 cchLeft = pchTmp - pchWord;4500 cchLine = pchTmp - &pszContent[off];4501 }4502 4503 /*4504 * Update the compiler state that we pass around.4505 */4506 Compiler.iLine = iLine;4507 Compiler.offLine = off;4508 Compiler.cchLine = cchLine;4509 4510 5063 /* 4511 5064 * Command? Ignore command prefix if no open recipe (SunOS 4 behavior). … … 4517 5070 kmk_cc_eval_handle_command(&Compiler, &pszContent[off], cchLine); 4518 5071 } 4519 else 5072 /* 5073 * Since it's not a command line, we can now skip comment lines 5074 * even with a tab indentation. If it's not a comment line, we 5075 * tentatively strip any trailing comment. 5076 */ 5077 else if (pszContent[offFirstWord] != '#') 4520 5078 { 5079 const char *pchWord = &pszContent[offFirstWord]; 5080 size_t cchLeft = off + cchLine - offFirstWord; 5081 char ch; 5082 5083 Compiler.cchLineWithComments = cchLine; 5084 pchTmp = (const char *)memchr(pchWord, '#', cchLeft); 5085 if (pchTmp) 5086 { 5087 cchLeft = pchTmp - pchWord; 5088 cchLine = pchTmp - &pszContent[off]; 5089 } 5090 Compiler.cchLine = cchLine; 5091 Compiler.offLine = off; 5092 4521 5093 /* 4522 5094 * If not a directive or variable qualifier, it's either a variable 4523 5095 * assignment or a recipe. 4524 5096 */ 4525 ch ar ch= *pchWord;5097 ch = *pchWord; 4526 5098 if ( !KMK_CC_EVAL_IS_1ST_IN_KEYWORD(ch) 4527 5099 || !KMK_CC_EVAL_IS_2ND_IN_KEYWORD(pchWord[1]) … … 4540 5112 * Advance to the next line. 4541 5113 */ 4542 off = offNext;4543 iLine += Compiler.cEscEols + 1;5114 off = offNext; 5115 Compiler.iLine += Compiler.cEscEols + 1; 4544 5116 } 4545 5117 } … … 4734 5306 KMK_CC_ASSERT(pVar->evalprog || pProg); 4735 5307 4736 #if 04737 5308 if (pVar->evalprog) 4738 5309 { … … 4740 5311 pVar->evalprog = NULL; 4741 5312 } 4742 #endif4743 5313 4744 5314 if (pProg) … … 4764 5334 KMK_CC_ASSERT(pVar->evalprog || pProg); 4765 5335 4766 #if 04767 5336 if (pVar->evalprog) 4768 5337 { … … 4770 5339 pVar->evalprog = NULL; 4771 5340 } 4772 #endif4773 5341 4774 5342 if (pProg)
Note:
See TracChangeset
for help on using the changeset viewer.