Changeset 2799 in kBuild for trunk/src/kmk/kmk_cc_exec.c
- Timestamp:
- Sep 19, 2015 8:36:31 PM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/kmk/kmk_cc_exec.c
r2797 r2799 68 68 # ifdef _MSC_VER 69 69 # define KMK_CC_ASSERT(a_TrueExpr) do { if (!(a_TrueExpr)) __debugbreak(); } while (0) 70 # elif defined(__GNUC__) && (defined(KBUILD_ARCH_X86) || defined(KBUILD_ARCH_AMD64)) 71 # define KMK_CC_ASSERT(a_TrueExpr) do { if (!(a_TrueExpr)) __asm__ __volatile__("int3;nop"); } while (0) 70 72 # else 71 73 # define KMK_CC_ASSERT(a_TrueExpr) assert(a_TrueExpr) … … 123 125 #define KMK_CC_IS_SPACE_CH(a_ch) isspace((unsigned char)(a_ch)) 124 126 127 /** Aligns a size for the block allocator. */ 128 #define KMK_CC_BLOCK_ALIGN_SIZE(a_cb) ( ((a_cb) + (sizeof(void *) - 1U)) & ~(uint32_t)(sizeof(void *) - 1U) ) 129 125 130 126 131 /** @defgroup grp_kmk_cc_evalprog Makefile Evaluation 127 132 * @{ 128 133 */ 134 #if 1 135 # define KMK_CC_EVAL_DPRINTF_UNPACK(...) __VA_ARGS__ 136 # define KMK_CC_EVAL_DPRINTF(a) fprintf(stderr, KMK_CC_EVAL_DPRINTF_UNPACK a) 137 #else 138 # define KMK_CC_EVAL_DPRINTF(a) do { } while (0) 139 #endif 140 129 141 /** @name KMK_CC_EVAL_QUALIFIER_XXX - Variable qualifiers. 130 142 * @{ */ … … 183 195 #define KMK_CC_EVAL_CH_PAREN_OR_SLASH UINT16_C(256) 184 196 #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) 197 /** Used when parsing ifeq/ifneq (,) sequences. 198 * Matches parentheses, comma and dollar (for non-plain string detection). */ 199 #define KMK_CC_EVAL_CH_PAREN_COMMA_OR_DOLLAR UINT16_C(512) 200 #define KMK_CC_EVAL_IS_PAREN_COMMA_OR_DOLLAR(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_PAREN_COMMA_OR_DOLLAR) 185 201 /** @} */ 186 202 … … 767 783 /** Calculates the size of an KMKCCEVALIFEXPR structure for @a a_cchExpr long 768 784 * expression string (terminator is automatically added). */ 769 #define KMKCCEVALIFEXPR_SIZE(a_cchExpr) KMK_CC_ SIZEOF_VAR_STRUCT(KMKCCEVALIFEXPR, szExpr, (a_cchExpr) + 1)785 #define KMKCCEVALIFEXPR_SIZE(a_cchExpr) KMK_CC_BLOCK_ALIGN_SIZE(KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEVALIFEXPR, szExpr, (a_cchExpr) + 1)) 770 786 771 787 /** … … 1054 1070 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '}', KMK_CC_EVAL_CH_PAREN_OR_SLASH); 1055 1071 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\\', KMK_CC_EVAL_CH_PAREN_OR_SLASH); 1072 1073 /* For parsing ifeq and if1of expressions. (GNU weirdly does not respect {} style function references.) */ 1074 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '(', KMK_CC_EVAL_CH_PAREN_COMMA_OR_DOLLAR); 1075 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ')', KMK_CC_EVAL_CH_PAREN_COMMA_OR_DOLLAR); 1076 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ',', KMK_CC_EVAL_CH_PAREN_COMMA_OR_DOLLAR); 1077 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '$', KMK_CC_EVAL_CH_PAREN_COMMA_OR_DOLLAR); 1056 1078 } 1057 1079 … … 1274 1296 { 1275 1297 PKMKCCBLOCK pBlockTail = *ppBlockTail; 1276 if (pBlockTail->offNext & (sizeof(void *) - 1 ))1277 { 1278 pBlockTail->offNext = (pBlockTail->offNext + sizeof(void *) - 1) & ~(sizeof(void *) - 1);1298 if (pBlockTail->offNext & (sizeof(void *) - 1U)) 1299 { 1300 pBlockTail->offNext = KMK_CC_BLOCK_ALIGN_SIZE(pBlockTail->offNext); 1279 1301 KMK_CC_ASSERT(pBlockTail->cbBlock - pBlockTail->offNext >= sizeof(KMKCCEXPJUMP)); 1280 1302 } … … 1344 1366 { 1345 1367 PKMKCCBLOCK pBlockTail = *ppBlockTail; 1346 uint32_t cbLeft = pBlockTail->cbBlock - pBlockTail->offNext;1368 uint32_t cbLeft = pBlockTail->cbBlock - pBlockTail->offNext; 1347 1369 1348 1370 KMK_CC_ASSERT(cbLeft >= sizeof(KMKCCEXPJUMP)); … … 1412 1434 1413 1435 pRet = (PKMKCCEXPCORE)(pNewBlock + 1); 1436 KMK_CC_ASSERT(((size_t)pRet & (sizeof(void *) - 1)) == 0); 1414 1437 1415 1438 /* Emit jump. */ … … 1443 1466 PKMKCCEXPCORE pRet = (PKMKCCEXPCORE)((char *)pBlockTail + pBlockTail->offNext); 1444 1467 pBlockTail->offNext += cb; 1468 KMK_CC_ASSERT(((size_t)pRet & (sizeof(void *) - 1)) == 0); 1445 1469 return pRet; 1446 1470 } … … 1519 1543 1520 1544 /** 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);1542 }1543 1544 1545 /**1546 1545 * Frees all memory used by an allocator. 1547 1546 * … … 1577 1576 PKMKCCEXPCORE pCore = kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pCore)); 1578 1577 pCore->enmOpCode = kKmkCcExpInstr_Return; 1578 kmk_cc_block_realign(ppBlockTail); 1579 1579 } 1580 1580 … … 3042 3042 pCompiler->iLine = iLine; 3043 3043 3044 pCompiler->cStrCopySegsAllocated = 0; 3045 pCompiler->paStrCopySegs = NULL; 3046 3044 3047 pCompiler->cIfs = 0; 3045 3048 … … 3143 3146 3144 3147 3148 /** 3149 * Initializes a subprogam or plain operand structure. 3150 * 3151 * @param pCompiler The compiler state. 3152 * @param pOperand The subprogram or plain structure to init. 3153 * @param pszString The string. 3154 * @param cchString The length of the string. 3155 * @param fPlain Whether it's plain or not. If not, we'll compile it. 3156 */ 3157 static void kmk_cc_eval_do_subprogram_or_plain(PKMKCCEVALCOMPILER pCompiler, PKMKCCEXPSUBPROGORPLAIN pOperand, 3158 const char *pszString, size_t cchString, int fPlain) 3159 { 3160 pOperand->fPlainIsInVarStrCache = 0; 3161 pOperand->bUser = 0; 3162 pOperand->bUser2 = 0; 3163 pOperand->fSubprog = fPlain; 3164 if (fPlain) 3165 { 3166 pOperand->u.Plain.cch = cchString; 3167 pOperand->u.Plain.psz = pszString; 3168 } 3169 else 3170 kmk_cc_eval_compile_string_exp_subprog(pCompiler, pszString, cchString, &pOperand->u.Subprog); 3171 } 3172 3173 3174 3145 3175 /** @name KMK_CC_WORD_COMP_CONST_XXX - Optimal(/insane) constant work matching. 3146 3176 * @{ 3147 3177 */ 3148 #if defined(KBUILD_ARCH_X86) || defined(KBUILD_ARCH_AMD64) /* Unaligned access is reasonably cheap. */ 3178 #if (defined(KBUILD_ARCH_X86) || defined(KBUILD_ARCH_AMD64)) /* Unaligned access is reasonably cheap. */ \ 3179 && !defined(GCC_ADDRESS_SANITIZER) 3149 3180 # define KMK_CC_WORD_COMP_CONST_2(a_pchLine, a_pszWord) \ 3150 3181 ( *(uint16_t const *)(a_pchLine) == *(uint16_t const *)(a_pszWord) ) … … 3861 3892 } 3862 3893 3894 3895 /** 3896 * Allocate a byte buffer and ocpy the prepared string segments into it. 3897 * 3898 * The caller must call kmk_cc_block_realign! 3899 * 3900 * @returns Pointer to the duplicated string. 3901 * @param pCompiler The compiler instance data. 3902 * @param cchPrepped The length of the prepped string segments. 3903 */ 3904 static char *kmk_cc_eval_strdup_prepped(PKMKCCEVALCOMPILER pCompiler, size_t cchPrepped) 3905 { 3906 char *pszCopy = kmk_cc_block_byte_alloc(pCompiler->ppBlockTail, cchPrepped + 1); 3907 kmk_cc_eval_strcpyv(pszCopy, pCompiler->paStrCopySegs, pCompiler->cStrCopySegs, cchPrepped); 3908 return pszCopy; 3909 } 3910 3911 3912 /** 3913 * Strip trailing spaces from prepped copy 3914 * 3915 * @param paSegs The segments to strip trailing chars from. 3916 * @param pcSegs The number of segments (in/out). 3917 * @param pcchDstPrepped The total number of chars prepped (in/out). 3918 */ 3919 static void kmk_cc_eval_strip_right_v(PKMKCCEVALSTRCPYSEG paSegs, unsigned *pcSegs, size_t *pcchDstPrepped) 3920 { 3921 /* 3922 * Work our way thru the segments, from the end obviously. 3923 */ 3924 size_t cchDstPrepped = *pcchDstPrepped; 3925 unsigned cSegs = *pcSegs; 3926 while (cSegs > 0) 3927 { 3928 unsigned iSeg = cSegs - 1; 3929 const char *pszSrc = paSegs[iSeg].pchSrc; 3930 size_t cchSrc = paSegs[iSeg].cchSrcAndPrependSpace >= 0 3931 ? paSegs[iSeg].cchSrcAndPrependSpace : -paSegs[iSeg].cchSrcAndPrependSpace; 3932 if (cchSrc) 3933 { 3934 /* 3935 * Check for trailing spaces. 3936 */ 3937 size_t cchSrcOrg; 3938 if (!KMK_CC_EVAL_IS_SPACE(pszSrc[cchSrc - 1])) 3939 { 3940 /* Special case: No trailing spaces at all. No need to update 3941 input/output variables. */ 3942 if (cSegs == *pcSegs) 3943 return; 3944 break; 3945 } 3946 3947 /* Skip the rest of the trailing spaces. */ 3948 cchSrcOrg = cchSrc; 3949 do 3950 cchSrc--; 3951 while (cchSrc > 0 && KMK_CC_EVAL_IS_SPACE(pszSrc[cchSrc - 1])); 3952 3953 if (cchSrc > 0) 3954 { 3955 /* 3956 * There are non-space chars in this segment. So, update the 3957 * segment and total char count and we're done. 3958 */ 3959 cchDstPrepped -= cchSrcOrg - cchSrc; 3960 if (paSegs[iSeg].cchSrcAndPrependSpace < 0) 3961 paSegs[iSeg].cchSrcAndPrependSpace = -(ssize_t)cchSrc; 3962 else 3963 paSegs[iSeg].cchSrcAndPrependSpace = cchSrc; 3964 break; 3965 } 3966 3967 /* 3968 * Skip the whole segment. 3969 */ 3970 cchDstPrepped -= cchSrcOrg + (paSegs[iSeg].cchSrcAndPrependSpace < 0); 3971 } 3972 cSegs--; 3973 } 3974 *pcchDstPrepped = cchDstPrepped; 3975 *pcSegs = cSegs; 3976 } 3977 3863 3978 /** 3864 3979 * Helper for ensuring that we've got sufficient number of string copy segments. … … 3870 3985 else \ 3871 3986 { \ 3872 unsigned c Segs = ((a_cRequiredSegs) + 3 /*15*/) & ~(unsigned)3/*15*/; \3987 unsigned cEnsureSegs = ((a_cRequiredSegs) + 3 /*15*/) & ~(unsigned)3/*15*/; \ 3873 3988 KMK_CC_ASSERT((a_cRequiredSegs) < 0x8000); \ 3874 (a_pCompiler)->paStrCopySegs = (PKMKCCEVALSTRCPYSEG)xmalloc(c Segs * sizeof((a_pCompiler)->paStrCopySegs)[0]); \3989 (a_pCompiler)->paStrCopySegs = (PKMKCCEVALSTRCPYSEG)xmalloc(cEnsureSegs * sizeof((a_pCompiler)->paStrCopySegs)[0]); \ 3875 3990 } \ 3876 3991 } while (0) … … 4207 4322 * kmk_cc_eval_try_handle_keyword). 4208 4323 * @param pCompiler The compiler state. 4209 * @param pchWord First char after ' define'.4324 * @param pchWord First char after 'if'. 4210 4325 * @param cchLeft The number of chars left to parse on this line. 4211 4326 * @param fInElse Set if this is an 'else if' (rather than just 'if'). … … 4238 4353 * kmk_cc_eval_try_handle_keyword). 4239 4354 * @param pCompiler The compiler state. 4240 * @param pchWord First char after ' define'.4355 * @param pchWord First char after 'if[n]def'. 4241 4356 * @param cchLeft The number of chars left to parse on this line. 4242 4357 * @param fInElse Set if this is an 'else if' (rather than just 'if'). … … 4278 4393 4279 4394 /** @todo Make the subprogram embed necessary strings. */ 4280 pszCopy = kmk_cc_ block_alloc_eval_string(pCompiler->ppBlockTail, cchCopy + 1);4281 kmk_cc_ eval_strcpyv(pszCopy, pCompiler->paStrCopySegs, pCompiler->cStrCopySegs, cchCopy);4395 pszCopy = kmk_cc_eval_strdup_prepped(pCompiler, cchCopy); 4396 kmk_cc_block_realign(pCompiler->ppBlockTail); 4282 4397 4283 4398 pInstr->IfCore.Core.enmOpCode = fPositiveStmt ? kKmkCcEvalInstr_ifdef_dynamic : kKmkCcEvalInstr_ifndef_dynamic; … … 4301 4416 4302 4417 4418 /** 4419 * Deals with 'ifeq (a,b)', 'ifeq "a" "b"', 'ifneq (a,b)', 'ifneq "a" "b"', 4420 * 'else ifeq (a,b)', 'else ifeq "a" "b"', 'else ifneq (a,b)' and 4421 * 'else ifneq "a" "b"' statements. 4422 * 4423 * @returns 1 to indicate we've handled a keyword (see 4424 * kmk_cc_eval_try_handle_keyword). 4425 * @param pCompiler The compiler state. 4426 * @param pchWord First char after 'if[n]eq'. 4427 * @param cchLeft The number of chars left to parse on this line. 4428 * @param fInElse Set if this is an 'else if' (rather than just 'if'). 4429 * @param fPositiveStmt Set if 'ifeq', clear if 'ifneq'. 4430 */ 4303 4431 static int kmk_cc_eval_do_ifeq(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, int fInElse, int fPositiveStmt) 4304 4432 { … … 4314 4442 */ 4315 4443 const char * const pchEnd = &pchWord[cchLeft]; 4316 PKMKCCEVALIFEQ pInstr ;4444 PKMKCCEVALIFEQ pInstr = (PKMKCCEVALIFEQ)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr)); 4317 4445 4318 4446 struct … … 4326 4454 if (ch == '(') 4327 4455 { 4328 // unsigned cCounts; 4329 4330 4456 int cCounts; 4457 size_t off; 4458 4459 /* 4460 * The left side ends with a comma. We respect parentheses, but 4461 * not curly brackets. 4462 */ 4331 4463 4332 4464 /* Skip the parenthesis. */ … … 4334 4466 cchLeft--; 4335 4467 4336 /** @todo continue here. */ 4468 /* Find the comma, checking for non-plainness. */ 4469 cCounts = 0; 4470 Left.fPlain = 1; 4471 for (off = 0; off < cchLeft; off++) 4472 { 4473 ch = pchWord[off]; 4474 if (!KMK_CC_EVAL_IS_PAREN_COMMA_OR_DOLLAR(ch)) 4475 { /* likely */ } 4476 else if (ch == '$') 4477 Left.fPlain = 0; 4478 else if (ch == '(') 4479 cCounts++; 4480 else if (ch == ')') 4481 cCounts--; /** @todo warn if it goes negative. */ 4482 else if (ch == ',' && cCounts == 0) 4483 break; 4484 else 4485 KMK_CC_ASSERT(cCounts > 0); 4486 } 4487 if (ch == ',' && cCounts == 0) { /* likely */ } 4488 else kmk_cc_eval_fatal(pCompiler, &pchWord[off], "Expected ',' before end of line"); 4489 4490 /* Copy out the string. */ 4491 Left.cchCopy = kmk_cc_eval_prep_normal_line_ex(pCompiler, pchWord, off); 4492 kmk_cc_eval_strip_right_v(pCompiler->paStrCopySegs, &pCompiler->cStrCopySegs, &Left.cchCopy); 4493 Left.pszCopy = kmk_cc_eval_strdup_prepped(pCompiler, Left.cchCopy); 4494 4495 /* Skip past the comma and any following spaces. */ 4496 pchWord += off + 1; 4497 cchLeft -= off + 1; 4498 if ( cchLeft /** @todo replace with straight 'isspace' that takes escaped EOLs into account. */ 4499 && KMK_CC_EVAL_IS_SPACE_AFTER_WORD(pCompiler, pchWord[0], pchWord[1], cchLeft)) 4500 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); 4501 4502 /* 4503 * Ditto for the right side, only it ends with a closing parenthesis. 4504 */ 4505 cCounts = 1; 4506 Right.fPlain = 1; 4507 for (off = 0; off < cchLeft; off++) 4508 { 4509 ch = pchWord[off]; 4510 if (!KMK_CC_EVAL_IS_PAREN_COMMA_OR_DOLLAR(ch)) 4511 { /* likely */ } 4512 else if (ch == '$') 4513 Right.fPlain = 0; 4514 else if (ch == '(') 4515 cCounts++; 4516 else if (ch == ')') 4517 { 4518 if (--cCounts == 0) 4519 break; 4520 } 4521 else 4522 KMK_CC_ASSERT(cCounts > 0 || ch == ','); 4523 } 4524 if (ch == ')' && cCounts == 0) { /* likely */ } 4525 else kmk_cc_eval_fatal(pCompiler, &pchWord[off], "Expected ')' before end of line"); 4526 4527 /* Copy out the string. */ 4528 Right.cchCopy = kmk_cc_eval_prep_normal_line_ex(pCompiler, pchWord, off); 4529 kmk_cc_eval_strip_right_v(pCompiler->paStrCopySegs, &pCompiler->cStrCopySegs, &Right.cchCopy); 4530 Right.pszCopy = kmk_cc_eval_strdup_prepped(pCompiler, Right.cchCopy); 4531 4532 /* Skip past the parenthesis. */ 4533 pchWord += off + 1; 4534 cchLeft -= off + 1; 4337 4535 } 4338 4536 else if (ch == '"' || ch == '\'') … … 4353 4551 4354 4552 Left.cchCopy = kmk_cc_eval_prep_normal_line_ex(pCompiler, pchWord, pchTmp - pchWord); 4355 Left.pszCopy = kmk_cc_block_alloc_eval_string(pCompiler->ppBlockTail, Left.cchCopy + 1); 4356 kmk_cc_eval_strcpyv(Left.pszCopy, pCompiler->paStrCopySegs, pCompiler->cStrCopySegs, Left.cchCopy); 4553 Left.pszCopy = kmk_cc_eval_strdup_prepped(pCompiler, Left.cchCopy); 4357 4554 Left.fPlain = memchr(Left.pszCopy, '$', Left.cchCopy) == NULL; 4358 4555 … … 4382 4579 4383 4580 Right.cchCopy = kmk_cc_eval_prep_normal_line_ex(pCompiler, pchWord, pchTmp - pchWord); 4384 Right.pszCopy = kmk_cc_block_alloc_eval_string(pCompiler->ppBlockTail, Right.cchCopy + 1); 4385 kmk_cc_eval_strcpyv(Left.pszCopy, pCompiler->paStrCopySegs, pCompiler->cStrCopySegs, Right.cchCopy); 4581 Right.pszCopy = kmk_cc_eval_strdup_prepped(pCompiler, Right.cchCopy); 4386 4582 Right.fPlain = memchr(Right.pszCopy, '$', Right.cchCopy) == NULL; 4387 4583 … … 4397 4593 kmk_cc_eval_fatal(pCompiler, pchWord, "Expected parentheses or quoted string after 'if%seq'", 4398 4594 fPositiveStmt ? "" : "n"); 4595 kmk_cc_block_realign(pCompiler->ppBlockTail); 4399 4596 4400 4597 /* 4401 * 4598 * Initialize the instruction. 4402 4599 */ 4403 pInstr = (PKMKCCEVALIFEQ)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr)); 4404 4600 pInstr->IfCore.Core.enmOpCode = fPositiveStmt ? kKmkCcEvalInstr_ifeq : kKmkCcEvalInstr_ifneq; 4601 pInstr->IfCore.Core.iLine = pCompiler->iLine; 4602 kmk_cc_eval_do_subprogram_or_plain(pCompiler, &pInstr->Left, Left.pszCopy, Left.cchCopy, Left.fPlain); 4603 kmk_cc_eval_do_subprogram_or_plain(pCompiler, &pInstr->Right, Right.pszCopy, Right.cchCopy, Right.fPlain); 4604 kmk_cc_eval_do_if_core(pCompiler, &pInstr->IfCore, fInElse); 4405 4605 4406 4606 /* … … 4417 4617 4418 4618 4619 /** 4620 * Deals with 'if1of (set-a,set-b)', 'ifn1of (set-a,set-b)', 4621 * 'else if1of (set-a,set-b)' and 'else ifn1of (set-a,set-b)' statements. 4622 * 4623 * @returns 1 to indicate we've handled a keyword (see 4624 * kmk_cc_eval_try_handle_keyword). 4625 * @param pCompiler The compiler state. 4626 * @param pchWord First char after 'if[n]1of'. 4627 * @param cchLeft The number of chars left to parse on this line. 4628 * @param fInElse Set if this is an 'else if' (rather than just 'if'). 4629 * @param fPositiveStmt Set if 'if1of', clear if 'ifn1of'. 4630 */ 4419 4631 static int kmk_cc_eval_do_if1of(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, int fInElse, int fPositiveStmt) 4420 4632 { 4633 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); 4634 if (cchLeft) 4635 { 4636 /* 4637 * This code is (currently) very similar to kmk_cc_eval_do_ifeq. 4638 * However, we may want to add hashing optimizations of plain text, 4639 * and we don't want to support the quoted form as it is not necessary 4640 * and may interfere with support for quoted words later on. 4641 */ 4642 PKMKCCEVALIF1OF pInstr = (PKMKCCEVALIF1OF)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr)); 4643 4644 struct 4645 { 4646 char *pszCopy; 4647 size_t cchCopy; 4648 int fPlain; 4649 } Left, Right; 4650 4651 char ch = *pchWord; 4652 if (ch == '(') 4653 { 4654 int cCounts; 4655 size_t off; 4656 4657 /* 4658 * The left side ends with a comma. We respect parentheses, but 4659 * not curly brackets. 4660 */ 4661 4662 /* Skip the parenthesis. */ 4663 pchWord++; 4664 cchLeft--; 4665 4666 /* Find the comma, checking for non-plainness. */ 4667 cCounts = 0; 4668 Left.fPlain = 1; 4669 for (off = 0; off < cchLeft; off++) 4670 { 4671 ch = pchWord[off]; 4672 if (!KMK_CC_EVAL_IS_PAREN_COMMA_OR_DOLLAR(ch)) 4673 { /* likely */ } 4674 else if (ch == '$') 4675 Left.fPlain = 0; 4676 else if (ch == '(') 4677 cCounts++; 4678 else if (ch == ')') 4679 cCounts--; /** @todo warn if it goes negative. */ 4680 else if (ch == ',' && cCounts == 0) 4681 break; 4682 else 4683 KMK_CC_ASSERT(cCounts > 0); 4684 } 4685 if (ch == ',' && cCounts == 0) { /* likely */ } 4686 else kmk_cc_eval_fatal(pCompiler, &pchWord[off], "Expected ',' before end of line"); 4687 4688 /* Copy out the string. */ 4689 Left.cchCopy = kmk_cc_eval_prep_normal_line_ex(pCompiler, pchWord, off); 4690 kmk_cc_eval_strip_right_v(pCompiler->paStrCopySegs, &pCompiler->cStrCopySegs, &Left.cchCopy); 4691 Left.pszCopy = kmk_cc_eval_strdup_prepped(pCompiler, Left.cchCopy); 4692 4693 /* Skip past the comma and any following spaces. */ 4694 pchWord += off + 1; 4695 cchLeft -= off + 1; 4696 if ( cchLeft /** @todo replace with straight 'isspace' that takes escaped EOLs into account. */ 4697 && KMK_CC_EVAL_IS_SPACE_AFTER_WORD(pCompiler, pchWord[0], pchWord[1], cchLeft)) 4698 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); 4699 4700 /* 4701 * Ditto for the right side, only it ends with a closing parenthesis. 4702 */ 4703 cCounts = 1; 4704 Right.fPlain = 1; 4705 for (off = 0; off < cchLeft; off++) 4706 { 4707 ch = pchWord[off]; 4708 if (!KMK_CC_EVAL_IS_PAREN_COMMA_OR_DOLLAR(ch)) 4709 { /* likely */ } 4710 else if (ch == '$') 4711 Right.fPlain = 0; 4712 else if (ch == '(') 4713 cCounts++; 4714 else if (ch == ')') 4715 { 4716 if (--cCounts == 0) 4717 break; 4718 } 4719 else 4720 KMK_CC_ASSERT(cCounts > 0 || ch == ','); 4721 } 4722 if (ch == ')' && cCounts == 0) { /* likely */ } 4723 else kmk_cc_eval_fatal(pCompiler, &pchWord[off], "Expected ')' before end of line"); 4724 4725 /* Copy out the string. */ 4726 Right.cchCopy = kmk_cc_eval_prep_normal_line_ex(pCompiler, pchWord, off); 4727 kmk_cc_eval_strip_right_v(pCompiler->paStrCopySegs, &pCompiler->cStrCopySegs, &Right.cchCopy); 4728 Right.pszCopy = kmk_cc_eval_strdup_prepped(pCompiler, Right.cchCopy); 4729 4730 /* Skip past the parenthesis. */ 4731 pchWord += off + 1; 4732 cchLeft -= off + 1; 4733 } 4734 else 4735 kmk_cc_eval_fatal(pCompiler, pchWord, "Expected parentheses after 'if%s1of'", fPositiveStmt ? "" : "n"); 4736 kmk_cc_block_realign(pCompiler->ppBlockTail); 4737 4738 /* 4739 * Initialize the instruction. 4740 */ 4741 pInstr->IfCore.Core.enmOpCode = fPositiveStmt ? kKmkCcEvalInstr_if1of : kKmkCcEvalInstr_ifn1of; 4742 pInstr->IfCore.Core.iLine = pCompiler->iLine; 4743 kmk_cc_eval_do_subprogram_or_plain(pCompiler, &pInstr->Left, Left.pszCopy, Left.cchCopy, Left.fPlain); 4744 kmk_cc_eval_do_subprogram_or_plain(pCompiler, &pInstr->Right, Right.pszCopy, Right.cchCopy, Right.fPlain); 4745 kmk_cc_eval_do_if_core(pCompiler, &pInstr->IfCore, fInElse); 4746 4747 /* 4748 * Make sure there is nothing following the variable name. 4749 */ 4750 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); 4751 if (cchLeft) 4752 kmk_cc_eval_fatal(pCompiler, pchWord, "Bogus stuff after 'if%s1of' variable name", fPositiveStmt ? "" : "n"); 4753 } 4754 else 4755 kmk_cc_eval_fatal(pCompiler, pchWord, "Expected expression after 'if' directive"); 4421 4756 return 1; 4422 4757 } … … 4620 4955 * @param fQualifiers The qualifiers. 4621 4956 */ 4622 static int kmk_cc_eval_do_var_define(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, 4623 unsigned fQualifiers) 4957 static int kmk_cc_eval_do_var_define(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, unsigned fQualifiers) 4624 4958 { 4625 4959 … … 4629 4963 4630 4964 static int kmk_cc_eval_try_handle_assignment(PKMKCCEVALCOMPILER pCompiler, const char *pchTmp, 4631 4965 const char *pchWord, size_t cchLeft, unsigned fQualifiers) 4632 4966 { 4633 4967 return 0; … … 4886 5220 KMKCCEVALCOMPILER Compiler; 4887 5221 kmk_cc_eval_init_compiler(&Compiler, pEvalProg, iLine, pszContent, cchContent); 5222 KMK_CC_EVAL_DPRINTF(("\nkmk_cc_eval_compile_worker - begin (%s/%s/%d)\n", pEvalProg->pszFilename, pEvalProg->pszVarName, iLine)); 4888 5223 4889 5224 { … … 4927 5262 if (&pszContent[offNext] == pchTmp) 4928 5263 { 4929 fprintf(stderr, "#%03u: <empty>\n", Compiler.iLine);5264 KMK_CC_EVAL_DPRINTF(("#%03u: <empty>\n", Compiler.iLine)); 4930 5265 Compiler.iLine++; 4931 5266 off = offNext += cchEolSeq; … … 4934 5269 if (pszContent[offNext] == '#') 4935 5270 { 4936 fprintf(stderr, "#%03u: <comment>\n", Compiler.iLine);5271 KMK_CC_EVAL_DPRINTF(("#%03u: <comment>\n", Compiler.iLine)); 4937 5272 Compiler.iLine++; 4938 5273 offNext = pchTmp - pszContent; … … 5057 5392 KMK_CC_ASSERT(offFirstWord >= off); 5058 5393 KMK_CC_ASSERT(pszContent[offFirstWord] != ' ' && pszContent[offFirstWord] != '\t'); 5059 { 5060 char chSaved = ((char *)pszContent)[off+cchLine] = '\0'; 5061 fprintf(stderr, "#%03u: %s\n", Compiler.iLine, &pszContent[off]); 5062 ((char *)pszContent)[off+cchLine] = chSaved; 5063 } 5394 5395 KMK_CC_EVAL_DPRINTF(("#%03u: %*.*s\n", Compiler.iLine, (int)cchLine, (int)cchLine, &pszContent[off])); 5064 5396 5065 5397 /* … … 5129 5461 5130 5462 kmk_cc_eval_delete_compiler(&Compiler); 5463 KMK_CC_EVAL_DPRINTF(("kmk_cc_eval_compile_worker - done (%s/%s)\n\n", pEvalProg->pszFilename, pEvalProg->pszVarName)); 5131 5464 return 0; 5132 5465 } 5133 5466 5134 5467 5135 /*#define KMK_CC_EVAL_ENABLE*/5136 5468 5137 5469 static PKMKCCEVALPROG kmk_cc_eval_compile(const char *pszContent, size_t cchContent, … … 5158 5490 * Do the actual compiling. 5159 5491 */ 5160 #ifdef KMK_CC_EVAL_ENABLE5492 #ifdef CONFIG_WITH_EVAL_COMPILER 5161 5493 if (kmk_cc_eval_compile_worker(pEvalProg, pszContent, cchContent, iLine) == 0) 5162 5494 #else … … 5198 5530 if (!pEvalProg) 5199 5531 { 5200 #ifdef KMK_CC_EVAL_ENABLE5532 #ifdef CONFIG_WITH_EVAL_COMPILER 5201 5533 pEvalProg = kmk_cc_eval_compile(pVar->value, pVar->value_length, 5202 5534 pVar->fileinfo.filenm, pVar->fileinfo.lineno, pVar->name);
Note:
See TracChangeset
for help on using the changeset viewer.