Changeset 3233 in kBuild for trunk/src/kmk
- Timestamp:
- Sep 24, 2018 10:39:36 AM (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/kmk/kmk_cc_exec.c
r3154 r3233 555 555 kKmkCcEvalInstr_assign_recursive, 556 556 /** [local|override|export] variable := value - KMKCCEVALASSIGN. 557 * Also: [local|override|export] define variable := ... endef 557 558 * @note Can be used for target-specific variables. */ 558 559 kKmkCcEvalInstr_assign_simple, 559 560 /** [local|override|export] variable += value - KMKCCEVALASSIGN. 561 * Also: [local|override|export] define variable += ... endef 560 562 * @note Can be used for target-specific variables. */ 561 563 kKmkCcEvalInstr_assign_append, 562 /** [local|override|export] variable -= value - KMKCCEVALASSIGN. 564 /** [local|override|export] variable <= value - KMKCCEVALASSIGN. 565 * Also: [local|override|export] define variable <= ... endef 563 566 * @note Can be used for target-specific variables. */ 564 567 kKmkCcEvalInstr_assign_prepend, … … 566 569 * @note Can be used for target-specific variables. */ 567 570 kKmkCcEvalInstr_assign_if_new, 568 /** [local|override|export] define variable ... endef - KMKCCEVALASSIGNDEF. */ 569 kKmkCcEvalInstr_assign_define, 571 /* [local|override|export] define variable[=] ... endef - KMKCCEVALASSIGNDEF. */ 572 kKmkCcEvalInstr_define_recursive, 573 /* [local|override|export] define variable ?= ... endef - KMKCCEVALASSIGNDEF. */ 574 kKmkCcEvalInstr_define_if_new, 570 575 571 576 /** export variable1 [variable2...] - KMKCCEVALVARIABLES. */ … … 698 703 699 704 /** 700 * Instruction format for kKmkCcEvalInstr_assign_define. 705 * Instruction format for kKmkCcEvalInstr_define_recursive and 706 * kKmkCcEvalInstr_define_if_new. 701 707 */ 702 708 typedef struct kmk_cc_eval_assign_define … … 1079 1085 "assign_prepend", 1080 1086 "assign_if_new", 1081 "assign_define", 1087 "define_recursive", 1088 "define_if_new", 1082 1089 "export", 1083 1090 "unexport", … … 1158 1165 } 1159 1166 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'd', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* define */ 1160 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'e', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* export (, endef)*/1167 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'e', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* export, endef */ 1161 1168 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'l', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* local */ 1162 1169 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'o', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* override */ … … 2975 2982 /** Plain word. */ 2976 2983 kKmkCcEvalToken_WordPlain, 2984 /** Plain word with one or more escaped EOLs. (Currently not possible.) */ 2985 kKmkCcEvalToken_WordPlainWithEscEol, 2977 2986 /** Word that maybe in need of expanding. */ 2978 2987 kKmkCcEvalToken_WordWithDollar, 2988 /** Word that is in need of expanding and include one or more escped EOLs. */ 2989 kKmkCcEvalToken_WordWithDollarAndEscEol, 2979 2990 2980 2991 /** Recipe colon. */ … … 3063 3074 /** Length of the current line, sans the final EOL but with comments. */ 3064 3075 size_t cchLineWithComments; 3076 /** For 'define' only, the start offset of the next line. Modified to the 3077 * line following 'endef'. */ 3078 size_t offNext; 3065 3079 3066 3080 /** The first char in an EOL sequence. … … 3097 3111 /** @name Tokenzied words. 3098 3112 * @{ */ 3099 u int32_tcWords;3100 u int32_tcWordsAllocated;3113 unsigned cWords; 3114 unsigned cWordsAllocated; 3101 3115 PKMKCCEVALWORD paWords; 3102 3116 /** @} */ … … 3237 3251 for (;;) 3238 3252 kmk_cc_eval_fatal(pCompiler, pchEol, "Missing 2nd EOL character: found %#x instead of %#x\n", 3239 3253 pchEol, pCompiler->chSecondEol); 3240 3254 } 3241 3255 … … 3938 3952 3939 3953 3954 #if 0 /* unused - probably forever. */ 3940 3955 /** 3941 3956 * Skips to the end of a variable name. … … 3973 3988 /* 3974 3989 * The outer loop parses plain text. Variable expansion ($) is handled 3975 * by aninner loop.3990 * by the inner loop. 3976 3991 */ 3977 3992 while (off < offLineEnd) … … 4061 4076 return &pszContent[off]; 4062 4077 } 4078 #endif /* unused */ 4063 4079 4064 4080 … … 4186 4202 #endif /* unused atm */ 4187 4203 4204 4205 static size_t kmk_cc_eval_parse_var_exp(PKMKCCEVALCOMPILER pCompiler, const char *pch, size_t cchLeft, size_t off) 4206 { 4207 off++; 4208 if (off < cchLeft) 4209 { 4210 char const chOpen = pch[++off]; 4211 if (chOpen == '(' || chOpen == '{') 4212 { 4213 /* 4214 * Got a $(VAR) or ${VAR} to deal with here. This may include nested 4215 * variable references and span multiple lines (at least for function 4216 * calls). 4217 * 4218 * We scan forward till we've found the corresponding closing 4219 * parenthesis, considering any open parentheses of the same kind as 4220 * worth counting, even if there are no dollar preceeding them, just 4221 * like GNU make does. 4222 */ 4223 size_t const offStart = off - 1; 4224 char const chClose = chOpen == '(' ? ')' : '}'; 4225 unsigned cOpen = 1; 4226 off++; 4227 for (;;) 4228 { 4229 if (off < cchLeft) 4230 { 4231 char ch = pch[off]; 4232 if (!(KMK_CC_EVAL_IS_PAREN_OR_SLASH(ch))) 4233 off++; 4234 else 4235 { 4236 off++; 4237 if (ch == chClose) 4238 { 4239 if (--cOpen == 0) 4240 break; 4241 } 4242 else if (ch == chOpen) 4243 cOpen++; 4244 else if ( ch == '\\' 4245 && pCompiler->iEscEol < pCompiler->cEscEols 4246 && (size_t)(&pch[off] - pCompiler->pszContent) 4247 == pCompiler->paEscEols[pCompiler->iEscEol].offEsc) 4248 { 4249 off += pCompiler->paEscEols[pCompiler->iEscEol].offEol 4250 - pCompiler->paEscEols[pCompiler->iEscEol].offEsc 4251 + pCompiler->cchEolSeq; 4252 pCompiler->iEscEol++; 4253 } 4254 } 4255 } 4256 else if (cOpen == 1) 4257 kmk_cc_eval_fatal(pCompiler, &pch[offStart], "Variable reference is missing '%c'", chClose); 4258 else 4259 kmk_cc_eval_fatal(pCompiler, &pch[offStart], 4260 "%u variable references are missing '%c'", cOpen, chClose); 4261 } 4262 } 4263 /* Single char variable name. */ 4264 else if (!KMK_CC_EVAL_IS_SPACE(chOpen)) 4265 { /* likely */ } 4266 else 4267 kmk_cc_eval_fatal(pCompiler, &pch[off], "Expected variable name after '$', not space "); 4268 } 4269 else 4270 kmk_cc_eval_fatal(pCompiler, &pch[off], "Expected variable name after '$', end of line"); 4271 return off; 4272 } 4188 4273 4189 4274 /** … … 4407 4492 * Parses the remainder of the line into simple words. 4408 4493 * 4409 * The resulting words are classified as either kKmkCcEvalToken_WordPlain or4410 * kKmkCcEvalToken_WordWithDollar .4494 * The resulting words are classified as either kKmkCcEvalToken_WordPlain, 4495 * kKmkCcEvalToken_WordWithDollar, or kKmkCcEvalToken_WordWithDollarAndEscEol. 4411 4496 * 4412 4497 * @returns Number of words. … … 4448 4533 else if (ch == '$') 4449 4534 { 4535 #ifdef XXXX 4536 cchWord = kmk_cc_eval_parse_var_exp(pCompiler, pchWord, cchLeft, cchWord); 4537 enmToken = kKmkCcEvalToken_WordWithDollar; 4538 #else 4450 4539 enmToken = kKmkCcEvalToken_WordWithDollar; 4451 4540 cchWord = kmk_cc_eval_parse_along_dollar_simple(pCompiler, cchWord, pchWord, cchLeft); 4541 #endif 4452 4542 } 4453 4543 else … … 4457 4547 /* Add the word. */ 4458 4548 KMK_CC_EVAL_ENSURE_WORDS(pCompiler, cWords + 1); 4459 pCompiler->paWords[cWords].pchWord = pchWord;4460 pCompiler->paWords[cWords].cchWord = cchWord;4461 pCompiler->paWords[cWords].enmToken = enmToken;4549 pCompiler->paWords[cWords].pchWord = pchWord; 4550 pCompiler->paWords[cWords].cchWord = cchWord; 4551 pCompiler->paWords[cWords].enmToken = enmToken; 4462 4552 cWords++; 4463 4553 … … 4488 4578 cchWord++; 4489 4579 else if (ch == '$') 4580 #ifdef XXXX 4581 { 4582 const unsigned iEscEolBefore = pCompiler->iEscEol; 4583 cchWord = kmk_cc_eval_parse_var_exp(pCompiler, pchWord, cchLeft, cchWord); 4584 enmToken = pCompiler->iEscEol == iEscEolBefore 4585 ? kKmkCcEvalToken_WordWithDollar : kKmkCcEvalToken_WordWithDollarAndEscEol; 4586 } 4587 #else 4490 4588 { 4491 4589 enmToken = kKmkCcEvalToken_WordWithDollar; 4492 4590 cchWord = kmk_cc_eval_parse_along_dollar_esc_eol(pCompiler, cchWord, pchWord, cchLeft); 4493 4591 } 4592 #endif 4494 4593 else if (ch != '\\') 4495 4594 break; … … 5146 5245 /* 5147 5246 * Skip to the end of the variable name. 5247 * GNU make just does normal word parsing, so lets do that too. 5148 5248 */ 5149 unsigned const iSavedEscEol = pCompiler->iEscEol; 5150 const char * const pchVarNm = pchWord; 5151 int fPlain; 5152 /** @todo this isn't quite right. It is a variable name, correct. However, it 5153 * doesn't need to subscribe entirely to the rules of a variable name. 5154 * Just find the end of the word, taking variable refs into account, 5155 * and consider it what we need. */ 5156 pchWord = kmk_cc_eval_skip_var_name(pCompiler, pchWord, cchLeft, &cchLeft, &fPlain); 5157 KMK_CC_ASSERT(pCompiler->iEscEol == iSavedEscEol || !fPlain); 5158 if (fPlain) 5159 { 5160 size_t const cchVarNm = pchWord - pchVarNm; 5161 PKMKCCEVALIFDEFPLAIN pInstr; 5162 pInstr = (PKMKCCEVALIFDEFPLAIN)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr)); 5163 pInstr->IfCore.Core.enmOpcode = fPositiveStmt ? kKmkCcEvalInstr_ifdef_plain : kKmkCcEvalInstr_ifndef_plain; 5164 pInstr->IfCore.Core.iLine = pCompiler->iLine; 5165 pInstr->pszName = strcache2_add(&variable_strcache, pchVarNm, cchVarNm); 5166 kmk_cc_eval_do_if_core(pCompiler, &pInstr->IfCore, fInElse); 5249 unsigned const iSavedEscEol = pCompiler->iEscEol; 5250 unsigned cWords = kmk_cc_eval_parse_words(pCompiler, pchWord, cchLeft); 5251 if (cWords == 0) 5252 { 5253 PCKMKCCEVALWORD pWord = pCompiler->paWords; 5254 if (pWord->enmToken == kKmkCcEvalToken_WordPlain) 5255 { 5256 PKMKCCEVALIFDEFPLAIN pInstr; 5257 pInstr = (PKMKCCEVALIFDEFPLAIN)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr)); 5258 pInstr->IfCore.Core.enmOpcode = fPositiveStmt ? kKmkCcEvalInstr_ifdef_plain : kKmkCcEvalInstr_ifndef_plain; 5259 pInstr->IfCore.Core.iLine = pCompiler->iLine; 5260 pInstr->pszName = strcache2_add(&variable_strcache, pWord->pchWord, pWord->cchWord); 5261 kmk_cc_eval_do_if_core(pCompiler, &pInstr->IfCore, fInElse); 5262 } 5263 else 5264 { 5265 PKMKCCEVALIFDEFDYNAMIC pInstr; 5266 size_t cchCopy; 5267 char const *pszCopy; 5268 5269 pInstr = (PKMKCCEVALIFDEFDYNAMIC)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr)); 5270 5271 /** @todo Make the subprogram embed necessary strings. */ 5272 if (pWord->enmToken != kKmkCcEvalToken_WordWithDollar) 5273 { 5274 pszCopy = kmk_cc_block_strdup(pCompiler->ppBlockTail, pWord->pchWord, pWord->cchWord); 5275 cchCopy = pWord->cchWord; 5276 } 5277 else 5278 { 5279 KMK_CC_ASSERT(pWord->enmToken == kKmkCcEvalToken_WordWithDollarAndEscEol); 5280 pCompiler->iEscEol = iSavedEscEol; 5281 cchCopy = kmk_cc_eval_prep_normal_line_ex(pCompiler, pWord->pchWord, cchLeft); 5282 pszCopy = kmk_cc_eval_strdup_prepped(pCompiler, cchCopy); 5283 } 5284 kmk_cc_block_realign(pCompiler->ppBlockTail); 5285 5286 pInstr->IfCore.Core.enmOpcode = fPositiveStmt ? kKmkCcEvalInstr_ifdef_dynamic : kKmkCcEvalInstr_ifndef_dynamic; 5287 pInstr->IfCore.Core.iLine = pCompiler->iLine; 5288 pInstr->uPadding = 0; 5289 kmk_cc_eval_compile_string_exp_subprog(pCompiler, pszCopy, cchCopy, &pInstr->NameSubprog); 5290 5291 kmk_cc_eval_do_if_core(pCompiler, &pInstr->IfCore, fInElse); 5292 } 5167 5293 } 5168 5294 else 5169 5295 { 5170 PKMKCCEVALIFDEFDYNAMIC pInstr; 5171 size_t const cchVarNm = pchWord - pchVarNm; 5172 size_t cchCopy; 5173 char *pszCopy; 5174 pCompiler->iEscEol = iSavedEscEol; 5175 cchCopy = kmk_cc_eval_prep_normal_line(pCompiler, pchVarNm, cchVarNm); 5176 5177 pInstr = (PKMKCCEVALIFDEFDYNAMIC)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr)); 5178 5179 /** @todo Make the subprogram embed necessary strings. */ 5180 pszCopy = kmk_cc_eval_strdup_prepped(pCompiler, cchCopy); 5181 kmk_cc_block_realign(pCompiler->ppBlockTail); 5182 5183 pInstr->IfCore.Core.enmOpcode = fPositiveStmt ? kKmkCcEvalInstr_ifdef_dynamic : kKmkCcEvalInstr_ifndef_dynamic; 5184 pInstr->IfCore.Core.iLine = pCompiler->iLine; 5185 pInstr->uPadding = 0; 5186 kmk_cc_eval_compile_string_exp_subprog(pCompiler, pszCopy, cchCopy, &pInstr->NameSubprog); 5187 5188 kmk_cc_eval_do_if_core(pCompiler, &pInstr->IfCore, fInElse); 5296 KMK_CC_ASSERT(cWords > 1); 5297 kmk_cc_eval_fatal(pCompiler, pCompiler->paWords[1].pchWord, 5298 "Bogus stuff after 'if%sdef' variable name", fPositiveStmt ? "" : "n"); 5189 5299 } 5190 5191 /*5192 * Make sure there is nothing following the variable name.5193 */5194 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);5195 if (cchLeft)5196 kmk_cc_eval_fatal(pCompiler, pchWord, "Bogus stuff after 'if%sdef' variable name", fPositiveStmt ? "" : "n");5197 5300 } 5198 5301 else … … 5702 5805 * Split what's left up into words. 5703 5806 */ 5807 /** @todo GNU make supports escape sequences for spaces here (they confusingly refers to this as quoting). So, it's possible 5808 * to include C:/Program\ Files/kBuild/footer.kmk if we wanted to. It my intention to add support for double and/or single 5809 * quoted files names to offer an alternative way of addressing this. */ 5704 5810 unsigned cWords = kmk_cc_eval_parse_words(pCompiler, pchWord, cchLeft); 5705 5811 KMK_CC_EVAL_DPRINTF(("%s: cWords=%d\n", g_apszEvalInstrNms[enmOpcode], cWords)); … … 5926 6032 5927 6033 /** 6034 * Parse the value of a 'define' at pCompiler->offNext. 6035 * 6036 * This will update 'offNext' to the start of the line following the 'endef' 6037 * matching the 'define' of the value. 6038 * 6039 * The value is prepared for kmk_cc_eval_strcpyv. 6040 * 6041 * @returns The value length that we've prepared for copying. 6042 * @param pCompiler The compiler state. 6043 * @param pfPlainValue Where to return whether this is a plain value or 6044 * one needing expansion. 6045 */ 6046 static size_t kmk_cc_eval_parse_define_value(PKMKCCEVALCOMPILER pCompiler, int *pfPlainValue) 6047 { 6048 /* 6049 * Now we need to find the matching 'endef', we support nested ones. 6050 * 6051 * We look for the lines starting with 'endef' and 'define', like GNU 6052 * make does even if we really should also be checking for variable 6053 * qualifiers too. 6054 * 6055 * As we go on looking, we prepare the value in paStrCopySegs. 6056 * 6057 * Note! We duplicate code/logic from the top level compile loop here. 6058 */ 6059 const char * const pszContent = pCompiler->pszContent; 6060 size_t cchContent = pCompiler->cchContent; 6061 int const chFirstEol = pCompiler->chFirstEol; 6062 size_t const cchEolSeq = pCompiler->cchEolSeq; 6063 6064 unsigned cNestings = 1; 6065 size_t offNext = pCompiler->offNext; 6066 unsigned iLine = pCompiler->iLine; 6067 6068 unsigned cSegs = 0; 6069 size_t cchValue = 0; 6070 int fPlainValue = 1; 6071 6072 for (;;) 6073 { 6074 /* 6075 * Find end of line, preparing to copy it. 6076 */ 6077 if (offNext < cchContent) 6078 { 6079 unsigned const cSegsAtStartOfLine = cSegs; 6080 size_t const cchValueStartOfLine = cchValue; 6081 size_t offFirstWord = offNext; 6082 const char *pchLine = &pszContent[offNext]; 6083 size_t cchLine; 6084 const char *pchTmp; 6085 6086 pCompiler->cEscEols = 0; 6087 pCompiler->iEscEol = 0; 6088 6089 /* Add newline if necessary and make sure we've got a segment handy. */ 6090 KMK_CC_EVAL_ENSURE_STRCOPY_SEGS(pCompiler, cSegs + 2); 6091 if (cSegs) 6092 { 6093 cchValue++; 6094 pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = 1; 6095 pCompiler->paStrCopySegs[cSegs].pchSrc = "\n"; 6096 cSegs++; 6097 } 6098 6099 /* Simple case: No escaped EOL, nor the end of the input. */ 6100 pchTmp = (const char *)memchr(&pszContent[offNext], chFirstEol, cchContent - offNext); 6101 if ( pchTmp 6102 && ( &pszContent[offNext] == pchTmp 6103 || pchTmp[-1] != '\\')) 6104 { 6105 if ( cchEolSeq == 1 6106 || pchTmp[1] == pCompiler->chSecondEol) 6107 { 6108 offNext = pchTmp - pszContent; 6109 cchLine = pchTmp - pchLine; 6110 6111 cchValue += cchLine; 6112 pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = cchLine; 6113 pCompiler->paStrCopySegs[cSegs].pchSrc = pchLine; 6114 cSegs++; 6115 6116 while (offFirstWord < offNext && KMK_CC_EVAL_IS_SPACE(pszContent[offFirstWord])) 6117 offFirstWord++; 6118 6119 offNext += cchEolSeq; 6120 } 6121 else 6122 kmk_cc_eval_fatal_eol(pCompiler, pchTmp, iLine, offNext); 6123 } 6124 /* The complicated, less common cases. */ 6125 else 6126 { 6127 size_t fPendingSpace = 0; 6128 for (;;) 6129 { 6130 /* Find the first non-space char on this line. We always need it. */ 6131 size_t offThisFirstWord = offNext; 6132 size_t offEol = pchTmp ? pchTmp - pszContent : cchContent; 6133 if (offFirstWord == offNext) 6134 { 6135 while (offFirstWord < offEol && KMK_CC_EVAL_IS_SPACE(pszContent[offFirstWord])) 6136 offFirstWord++; 6137 if (pCompiler->cEscEols > 0) 6138 offThisFirstWord = offFirstWord; 6139 } 6140 else 6141 while (offThisFirstWord < offEol && KMK_CC_EVAL_IS_SPACE(pszContent[offThisFirstWord])) 6142 offThisFirstWord++; 6143 6144 /* We normally need one, so just make sure once. */ 6145 KMK_CC_EVAL_ENSURE_STRCOPY_SEGS(pCompiler, cSegs + 1); 6146 6147 if (pchTmp) 6148 { 6149 if ( cchEolSeq == 1 6150 || pchTmp[1] == pCompiler->chSecondEol) 6151 { 6152 size_t const offThis = offNext; 6153 size_t offEsc; 6154 int fDone; 6155 offNext = pchTmp - pszContent; 6156 6157 /* Is it an escape sequence? */ 6158 if ( !offNext 6159 || pchTmp[-1] != '\\') 6160 fDone = 1; 6161 else if (offNext < 2 || pchTmp[-2] != '\\') 6162 { 6163 offEsc = offNext - 1; 6164 fDone = 0; 6165 } 6166 else 6167 { 6168 /* Count how many backslashes there are. Must be odd number to be an escape 6169 sequence. Normally we keep half of them, except for command lines. */ 6170 size_t cSlashes = 2; 6171 while (offNext >= cSlashes && pchTmp[0 - cSlashes] == '\\') 6172 cSlashes--; 6173 fDone = !(cSlashes & 1); 6174 offEsc = offNext - (cSlashes >> 1); 6175 } 6176 6177 /* Anything to copy? */ 6178 /** @todo fixme tomorrow! */ 6179 cchLine = offThisFirstWord - offNext; 6180 if (cchLine) 6181 { 6182 pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = fPendingSpace 6183 ? -(ssize_t)cchLine : (ssize_t)cchLine; 6184 pCompiler->paStrCopySegs[cSegs].pchSrc = &pszContent[offThisFirstWord]; 6185 cSegs++; 6186 } 6187 6188 if (fDone) 6189 { 6190 cchLine = &pszContent[offNext] - pchLine; 6191 offNext += cchEolSeq; 6192 break; 6193 } 6194 6195 /* Record it. */ 6196 if (pCompiler->cEscEols < pCompiler->cEscEolsAllocated) { /* likely */ } 6197 else 6198 { 6199 KMK_CC_ASSERT(pCompiler->cEscEols == pCompiler->cEscEolsAllocated); 6200 pCompiler->cEscEolsAllocated = pCompiler->cEscEolsAllocated 6201 ? pCompiler->cEscEolsAllocated * 2 : 2; 6202 pCompiler->paEscEols = (PKMKCCEVALESCEOL)xrealloc(pCompiler->paEscEols, 6203 pCompiler->cEscEolsAllocated 6204 * sizeof(pCompiler->paEscEols[0])); 6205 } 6206 pCompiler->paEscEols[pCompiler->cEscEols].offEsc = offEsc; 6207 pCompiler->paEscEols[pCompiler->cEscEols].offEol = offNext; 6208 pCompiler->cEscEols++; 6209 6210 /* Anything to copy? */ 6211 cchLine = offThisFirstWord - offNext; 6212 if (cchLine) 6213 { 6214 } 6215 6216 /* Advance. */ 6217 offNext += cchEolSeq; 6218 if (offFirstWord == offEsc) 6219 { 6220 offFirstWord = offNext; 6221 pCompiler->iEscEol++; 6222 } 6223 } 6224 else 6225 kmk_cc_eval_fatal_eol(pCompiler, pchTmp, pCompiler->iLine, off); 6226 } 6227 else 6228 { 6229 /* End of input. Happens only once per compilation, nothing to optimize for. */ 6230 6231 if (offFirstWord == offNext) 6232 while (offFirstWord < cchContent && KMK_CC_EVAL_IS_SPACE(pszContent[offFirstWord])) 6233 offFirstWord++; 6234 6235 KMK_CC_EVAL_ENSURE_STRCOPY_SEGS(pCompiler, cSegs + 2); 6236 if (cSegs == cSegsAtStartOfLine) 6237 { 6238 /* No escaped EOLs. */ 6239 cchLine = &pszContent[cchContent] - pchLine; 6240 cchValue += cchLine; 6241 pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = cchLine; 6242 pCompiler->paStrCopySegs[cSegs].pchSrc = pchLine; 6243 cSegs++; 6244 } 6245 else 6246 { 6247 if (offFirstWordThisLine < cchContent) 6248 { 6249 cchLine = cchContent - offFirstWordThisLine; 6250 cchValue += cchLine; 6251 pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = fPendingSpace 6252 ? -(ssize_t)cchLine : (ssize_t)cchLine; 6253 pCompiler->paStrCopySegs[cSegs].pchSrc = &pszContent[offFirstWordThisLine]; 6254 cSegs++; 6255 } 6256 cchLine = &pszContent[cchContent] - pchLine; 6257 } 6258 offNext = cchContent; 6259 break; 6260 } 6261 pchTmp = (const char *)memchr(&pszContent[offNext], chFirstEol, cchContent - offNext); 6262 } 6263 } 6264 KMK_CC_ASSERT(offNext <= cchContent); 6265 KMK_CC_ASSERT(offNext >= off + cchLine); 6266 KMK_CC_ASSERT(off + cchLine <= cchContent && cchLine <= cchContent); 6267 KMK_CC_ASSERT(offFirstWord <= off + cchLine); 6268 KMK_CC_ASSERT(offFirstWord >= off); 6269 KMK_CC_ASSERT(pszContent[offFirstWord] != ' ' && pszContent[offFirstWord] != '\t'); 6270 6271 KMK_CC_EVAL_DPRINTF(("#%03u: %*.*s\n", pCompiler->iLine, (int)cchLine, (int)cchLine, &pszContent[off])); 6272 6273 /* 6274 * Look for 'endef' and 'define' directives. 6275 */ 6276 cchLine -= offFirstWord - off; 6277 if ( cchLine >= 5 /* shortest word is 5 chars ('endef', 'local') */ 6278 && pchLine[0] != pCompiler->chCmdPrefix) 6279 { 6280 pchTmp = &pszContent[offFirstWord]; 6281 if (!KMK_CC_EVAL_IS_1ST_IN_VARIABLE_KEYWORD(*pchTmp)) 6282 { /* Kind of likely (and saves one indent). */ } 6283 else if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchTmp, cchLine, "endef", 5)) 6284 { 6285 cNestings--; 6286 if (cNestings == 0) 6287 { 6288 cchValue = cchValueStartOfLine; 6289 cSegs = cSegsAtStartOfLine; 6290 break; 6291 } 6292 } 6293 else 6294 for (;;) 6295 { 6296 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchTmp, cchLine, "define", 6)) 6297 { 6298 cNestings++; 6299 break; 6300 } 6301 6302 /* GNU make doesn't do this, but I think it makes sense. */ 6303 if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchTmp, cchLine, "local", 5)) 6304 { 6305 pchTmp += 5; 6306 cchLine -= 5; 6307 } 6308 else if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchTmp, cchLine, "export", 6)) 6309 { 6310 pchTmp += 6; 6311 cchLine -= 6; 6312 } 6313 else if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchTmp, cchLine, "private", 7)) 6314 { 6315 pchTmp += 7; 6316 cchLine -= 7; 6317 } 6318 else if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchTmp, cchLine, "override", 8)) 6319 { 6320 pchTmp += 8; 6321 cchLine -= 8; 6322 } 6323 else 6324 break; 6325 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchTmp, cchLine); 6326 } 6327 } 6328 6329 /* 6330 * Advance to the next line. 6331 */ 6332 iLine += pCompiler->cEscEols + 1; 6333 } 6334 else 6335 kmk_cc_eval_fatal(pCompiler, NULL, ) 6336 } 6337 6338 /* 6339 * Update globals and return values. 6340 */ 6341 pCompiler->offNext = offNext; 6342 pCompiler->iLine = iLine; 6343 pCompiler->cStrCopySegs = cSegs; 6344 6345 *pfPlainValue = fPlainValue; 6346 return cchValue; 6347 } 6348 6349 /** 5928 6350 * Parses a 'define variable' expression. 5929 6351 * … … 5941 6363 static int kmk_cc_eval_do_var_define(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, unsigned fQualifiers) 5942 6364 { 6365 /* 6366 * Now comes the variable name. It may optionally be followed by an 6367 * assignment operator to indicate what kind of variable is being defined. 6368 */ 5943 6369 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft); 5944 kmk_cc_eval_fatal(pCompiler, pchWord, "define handling not implemented yet"); 6370 unsigned cWords = cchLeft ? kmk_cc_eval_parse_words(pCompiler, pchWord, cchLeft) : 0; 6371 if (cWords >= 1) 6372 { 6373 /* 6374 * Check for variable assignment operator. Kind of tedious... 6375 */ 6376 KMKCCEVALINSTR enmOpcode; 6377 PKMKCCEVALWORD pVarWord = pCompiler->paWords; 6378 if ( cWords == 1 6379 && ( pVarWord->cchWord == 0 6380 || pVarWord->pchWord[pVarWord->cchWord - 1] != '=')) 6381 enmOpcode = kKmkCcEvalInstr_define_recursive; /* very likely */ 6382 else if ( pVarWord->cchWord > 0 6383 && pVarWord->pchWord[pVarWord->cchWord - 1] == '=') 6384 { 6385 if (pVarWord->cchWord == 1) 6386 enmOpcode = kKmkCcEvalInstr_define_recursive; 6387 else 6388 { 6389 char chPenultimate = pVarWord->pchWord[pVarWord->cchWord - 2]; 6390 if (chPenultimate == '?') 6391 enmOpcode = kKmkCcEvalInstr_define_if_new; 6392 else if (chPenultimate == ':') 6393 enmOpcode = kKmkCcEvalInstr_assign_simple; 6394 else if (chPenultimate == '+') 6395 enmOpcode = kKmkCcEvalInstr_assign_append; 6396 else if (chPenultimate == '<') 6397 enmOpcode = kKmkCcEvalInstr_assign_prepend; 6398 else 6399 enmOpcode = kKmkCcEvalInstr_define_recursive; 6400 } 6401 pVarWord->cchWord -= enmOpcode == kKmkCcEvalInstr_define_recursive ? 1 : 2; 6402 if (cWords > 1) 6403 kmk_cc_eval_fatal(pCompiler, pCompiler->paWords[1].pchWord, 6404 "Bogus stuff after 'define' variable name and assignment operator"); 6405 } 6406 else 6407 { 6408 PCKMKCCEVALWORD pOpWord = &pCompiler->paWords[1]; 6409 KMK_CC_ASSERT(cWords > 1); 6410 if ( pOpWord->cchWord == 1 6411 && pOpWord->pchWord[0] == '=') 6412 enmOpcode = kKmkCcEvalInstr_define_recursive; 6413 else if ( pOpWord->cchWord == 2 6414 && pOpWord->pchWord[1] == '=') 6415 { 6416 char chFirst = pVarWord->pchWord[0]; 6417 if (chFirst == '?') 6418 enmOpcode = kKmkCcEvalInstr_define_if_new; 6419 else if (chFirst == ':') 6420 enmOpcode = kKmkCcEvalInstr_assign_simple; 6421 else if (chFirst == '+') 6422 enmOpcode = kKmkCcEvalInstr_assign_append; 6423 else if (chFirst == '<') 6424 enmOpcode = kKmkCcEvalInstr_assign_prepend; 6425 else 6426 kmk_cc_eval_fatal(pCompiler, pOpWord->pchWord, "Bogus stuff after 'define' variable name"); 6427 } 6428 else 6429 kmk_cc_eval_fatal(pCompiler, pOpWord->pchWord, "Bogus stuff after 'define' variable name"); 6430 if (cWords > 2) 6431 kmk_cc_eval_fatal(pCompiler, pCompiler->paWords[2].pchWord, 6432 "Bogus stuff after 'define' variable name and assignment operator"); 6433 } 6434 6435 /* 6436 * The variable name must not be empty. 6437 */ 6438 if (pVarWord->cchWord) 6439 { 6440 int const fPlainVarNm = pVarWord->enmToken == kKmkCcEvalToken_WordPlain; 6441 const char * pchVarNm = pVarWord->pchWord; 6442 size_t cchVarNm = pVarWord->cchWord; 6443 PKMKCCEVALASSIGN pInstr; 6444 size_t cchValue; 6445 const char *pszValue; 6446 int fPlainValue; 6447 6448 if ( enmOpcode == kKmkCcEvalInstr_define_recursive 6449 || enmOpcode == kKmkCcEvalInstr_define_if_new) 6450 { 6451 PKMKCCEVALASSIGNDEF pInstrDef; 6452 pInstrDef = (PKMKCCEVALASSIGNDEF)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstrDef)); 6453 pInstr = &pInstrDef->AssignCore; 6454 pInstrDef->pEvalProg = NULL; /** @todo consider this later at some point, need some trial and error approach. */ 6455 } 6456 else 6457 pInstr = (PKMKCCEVALASSIGN)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr)); 6458 6459 pInstr->Core.enmOpcode = enmOpcode; 6460 pInstr->Core.iLine = pCompiler->iLine; 6461 pInstr->fExport = (fQualifiers & KMK_CC_EVAL_QUALIFIER_EXPORT) != 0; 6462 pInstr->fOverride = (fQualifiers & KMK_CC_EVAL_QUALIFIER_OVERRIDE) != 0; 6463 pInstr->fPrivate = (fQualifiers & KMK_CC_EVAL_QUALIFIER_PRIVATE) != 0; 6464 pInstr->fLocal = (fQualifiers & KMK_CC_EVAL_QUALIFIER_LOCAL) != 0; 6465 6466 cchValue = kmk_cc_eval_parse_define_value(pCompiler, &fPlainValue); 6467 pszValue = kmk_cc_eval_strdup_prepped(pCompiler, cchValue); 6468 if (fPlainVarNm) 6469 pchVarNm = strcache2_add(&variable_strcache, pchVarNm, cchVarNm); 6470 else 6471 { 6472 /** @todo fix work copying. */ 6473 // pCompiler->iEscEol = iEscEolVarNm; 6474 cchVarNm = kmk_cc_eval_prep_normal_line_ex(pCompiler, pchVarNm, cchVarNm); 6475 pchVarNm = kmk_cc_eval_strdup_prepped(pCompiler, cchVarNm); 6476 } 6477 kmk_cc_block_realign(pCompiler->ppBlockTail); 6478 KMK_CC_EVAL_DPRINTF(("%s: define '%s'\n%s\nendef\n", g_apszEvalInstrNms[enmOpcode], pchVarNm, pszValue)); 6479 6480 kmk_cc_eval_init_subprogram_or_plain(pCompiler, &pInstr->Variable, pchVarNm, cchVarNm, fPlainVarNm); 6481 kmk_cc_eval_init_subprogram_or_plain(pCompiler, &pInstr->Value, pszValue, cchValue, fPlainValue); 6482 6483 pInstr->pNext = (PKMKCCEVALCORE)kmk_cc_block_get_next_ptr(*pCompiler->ppBlockTail); 6484 } 6485 else 6486 kmk_cc_eval_fatal(pCompiler, pchWord, "Empty variable name after 'define'"); 6487 } 6488 else 6489 kmk_cc_eval_fatal(pCompiler, pchWord, "Expected variable name after 'define'"); 5945 6490 return 1; 5946 6491 } … … 6034 6579 { 6035 6580 size_t const offStart = cch; 6036 cch++; 6037 if (cch < cchLeft) 6038 { 6039 char const chOpen = pchWord[cch]; 6040 if (chOpen == '(' || chOpen == '{') 6041 { 6042 /* 6043 * Got a $(VAR) or ${VAR} to deal with here. This may 6044 * include nested variable references and span multiple 6045 * lines (at least for function calls). 6046 * 6047 * We scan forward till we've found the corresponding 6048 * closing parenthesis, considering any open parentheses 6049 * of the same kind as worth counting, even if there are 6050 * no dollar preceeding them, just like GNU make does. 6051 */ 6052 size_t const cchStart = cch - 1; 6053 char const chClose = chOpen == '(' ? ')' : '}'; 6054 unsigned cOpen = 1; 6055 cch++; 6056 for (;;) 6057 { 6058 if (cch < cchLeft) 6059 { 6060 ch = pchWord[cch]; 6061 if (!(KMK_CC_EVAL_IS_PAREN_OR_SLASH(ch))) 6062 cch++; 6063 else 6064 { 6065 cch++; 6066 if (ch == chClose) 6067 { 6068 if (--cOpen == 0) 6069 break; 6070 } 6071 else if (ch == chOpen) 6072 cOpen++; 6073 else if ( ch == '\\' 6074 && pCompiler->iEscEol < pCompiler->cEscEols 6075 && (size_t)(&pchWord[cch] - pCompiler->pszContent) 6076 == pCompiler->paEscEols[pCompiler->iEscEol].offEsc) 6077 { 6078 cch += pCompiler->paEscEols[pCompiler->iEscEol].offEol 6079 - pCompiler->paEscEols[pCompiler->iEscEol].offEsc 6080 + pCompiler->cchEolSeq; 6081 pCompiler->iEscEol++; 6082 } 6083 } 6084 } 6085 else if (cOpen == 1) 6086 kmk_cc_eval_fatal(pCompiler, &pchWord[cchStart], "Variable reference is missing '%c'", chClose); 6087 else 6088 kmk_cc_eval_fatal(pCompiler, &pchWord[cchStart], 6089 "%u variable references are missing '%c'", cOpen, chClose); 6090 } 6091 } 6092 /* Single char variable name. */ 6093 else if (!KMK_CC_EVAL_IS_SPACE(chOpen)) 6094 { /* likely */ } 6095 else 6096 kmk_cc_eval_fatal(pCompiler, &pchWord[cch], "Expected variable name after '$', not end of line"); 6097 } 6098 else 6099 kmk_cc_eval_fatal(pCompiler, &pchWord[cch], "Neither recipe nor variable assignment"); 6581 cch = kmk_cc_eval_parse_var_exp(pCompiler, pchWord, cchLeft, cch); 6582 cchSubprog += cch - offStart; 6100 6583 fPlainVarNm = 0; 6101 cchSubprog += cch - offStart;6102 6584 } 6103 6585 /* Check out potential recipe, simple assignment or DOS drive letter separator. */ … … 6179 6661 size_t cchValue; 6180 6662 PKMKCCEVALASSIGN pInstr; 6181 KMKCCEVALINSTR enmOp Code;6663 KMKCCEVALINSTR enmOpcode; 6182 6664 int fPlainValue; 6183 6665 char *pszValue; … … 6186 6668 if (ch == '=') 6187 6669 { 6188 enmOp Code = kKmkCcEvalInstr_assign_recursive;6670 enmOpcode = kKmkCcEvalInstr_assign_recursive; 6189 6671 pchWord++; 6190 6672 cchLeft--; … … 6193 6675 { 6194 6676 if (ch == ':') 6195 enmOp Code = kKmkCcEvalInstr_assign_simple;6677 enmOpcode = kKmkCcEvalInstr_assign_simple; 6196 6678 else if (ch == '+') 6197 enmOp Code = kKmkCcEvalInstr_assign_append;6679 enmOpcode = kKmkCcEvalInstr_assign_append; 6198 6680 else if (ch == '<') 6199 enmOp Code = kKmkCcEvalInstr_assign_prepend;6681 enmOpcode = kKmkCcEvalInstr_assign_prepend; 6200 6682 else if (ch == '?') 6201 enmOp Code = kKmkCcEvalInstr_assign_if_new;6683 enmOpcode = kKmkCcEvalInstr_assign_if_new; 6202 6684 else if (!fQualifiers) 6203 6685 return kmk_cc_eval_handle_recipe_cont_2nd_word(pCompiler, pchVarNm, cchVarNm, pchWord, cchLeft); … … 6225 6707 6226 6708 pInstr = (PKMKCCEVALASSIGN)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr)); 6227 pInstr->Core.enmOpcode = enmOp Code;6709 pInstr->Core.enmOpcode = enmOpcode; 6228 6710 pInstr->Core.iLine = pCompiler->iLine; 6229 6711 pInstr->fExport = (fQualifiers & KMK_CC_EVAL_QUALIFIER_EXPORT) != 0; … … 6244 6726 } 6245 6727 kmk_cc_block_realign(pCompiler->ppBlockTail); 6246 KMK_CC_EVAL_DPRINTF(("%s: '%s' '%s'\n", g_apszEvalInstrNms[enmOp Code], pchVarNm, pszValue));6728 KMK_CC_EVAL_DPRINTF(("%s: '%s' '%s'\n", g_apszEvalInstrNms[enmOpcode], pchVarNm, pszValue)); 6247 6729 6248 6730 kmk_cc_eval_init_subprogram_or_plain(pCompiler, &pInstr->Variable, pchVarNm, cchVarNm, fPlainVarNm); … … 6724 7206 for (;;) 6725 7207 { 6726 if (offFirstWord == offNext)6727 {6728 size_t offEol = off + cchLine;6729 while (offFirstWord < offEol && KMK_CC_EVAL_IS_SPACE(pszContent[offFirstWord]))6730 offFirstWord++;6731 }6732 6733 7208 if (pchTmp) 6734 7209 { … … 6853 7328 cchLine = pchTmp - &pszContent[off]; 6854 7329 } 6855 Compiler.cchLine = cchLine; 6856 Compiler.offLine = off; 7330 Compiler.cchLine = cchLine; /** @todo only used by assertions. */ 7331 Compiler.offLine = off; /** @todo only used by fatal errors. */ 6857 7332 6858 7333 #ifdef KMK_CC_STRICT … … 6866 7341 ch = *pchWord; 6867 7342 if ( !KMK_CC_EVAL_IS_1ST_IN_KEYWORD(ch) 6868 || !KMK_CC_EVAL_IS_2ND_IN_KEYWORD(pchWord[1]) 6869 || !kmk_cc_eval_try_handle_keyword(&Compiler, ch, pchWord, cchLeft) ) 7343 || !KMK_CC_EVAL_IS_2ND_IN_KEYWORD(pchWord[1])) 6870 7344 { 6871 pchTmp = (const char *)memchr(pchWord, '=', cchLeft); 6872 if (pchTmp) 7345 if (memchr(pchWord, '=', cchLeft)) 6873 7346 kmk_cc_eval_handle_assignment_or_recipe(&Compiler, pchWord, cchLeft, 0 /*fQualifiers*/); 6874 7347 else 6875 7348 kmk_cc_eval_handle_recipe(&Compiler, pchWord, cchLeft); 6876 7349 } 6877 /* else: handled a keyword expression */ 7350 else 7351 { 7352 /* Possible directive or variable qualifier. */ 7353 Compiler.offNext = offNext; 7354 if (kmk_cc_eval_try_handle_keyword(&Compiler, ch, pchWord, cchLeft)) 7355 offNext = Compiler.offNext; 7356 /* No, that wasn't it... */ 7357 else if (memchr(pchWord, '=', cchLeft)) 7358 kmk_cc_eval_handle_assignment_or_recipe(&Compiler, pchWord, cchLeft, 0 /*fQualifiers*/); 7359 else 7360 kmk_cc_eval_handle_recipe(&Compiler, pchTmp, pchWord, cchLeft); 7361 } 6878 7362 } 6879 7363 }
Note:
See TracChangeset
for help on using the changeset viewer.