VirtualBox

source: kBuild/trunk/src/kmk/kmk_cc_exec.c@ 2799

Last change on this file since 2799 was 2799, checked in by bird, 10 years ago

Fixed glob.h inclusion issue causing stack corruption. Fixed alignment issue in the string expansion compiler. More makefile eval 'compiler' work.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 214.1 KB
Line 
1#ifdef CONFIG_WITH_COMPILER
2/* $Id: kmk_cc_exec.c 2799 2015-09-19 20:36:31Z bird $ */
3/** @file
4 * kmk_cc - Make "Compiler".
5 */
6
7/*
8 * Copyright (c) 2015 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
9 *
10 * This file is part of kBuild.
11 *
12 * kBuild is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 3 of the License, or
15 * (at your option) any later version.
16 *
17 * kBuild is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with kBuild. If not, see <http://www.gnu.org/licenses/>
24 *
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include "make.h"
32
33#include "dep.h"
34#include "variable.h"
35#include "rule.h"
36#include "debug.h"
37#include "hash.h"
38#include <ctype.h>
39#ifdef HAVE_STDINT_H
40# include <stdint.h>
41#endif
42#include <stdarg.h>
43#include <assert.h>
44#include "k/kDefs.h"
45#include "k/kTypes.h"
46
47
48/*********************************************************************************************************************************
49* Defined Constants And Macros *
50*********************************************************************************************************************************/
51/** @def KMK_CC_WITH_STATS
52 * Enables the collection of extra statistics. */
53#ifndef KMK_CC_WITH_STATS
54# ifdef CONFIG_WITH_MAKE_STATS
55# define KMK_CC_WITH_STATS
56# endif
57#endif
58
59/** @def KMK_CC_STRICT
60 * Indicates whether assertions and other checks are enabled. */
61#ifndef KMK_CC_STRICT
62# ifndef NDEBUG
63# define KMK_CC_STRICT
64# endif
65#endif
66
67#ifdef KMK_CC_STRICT
68# ifdef _MSC_VER
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)
72# else
73# define KMK_CC_ASSERT(a_TrueExpr) assert(a_TrueExpr)
74# endif
75#else
76# define KMK_CC_ASSERT(a_TrueExpr) do {} while (0)
77#endif
78#define KMK_CC_ASSERT_ALIGNED(a_uValue, a_uAlignment) \
79 KMK_CC_ASSERT( ((a_uValue) & ((a_uAlignment) - 1)) == 0 )
80
81
82/** @def KMK_CC_OFFSETOF
83 * Offsetof for simple stuff. */
84#if defined(__GNUC__)
85# define KMK_CC_OFFSETOF(a_Struct, a_Member) __builtin_offsetof(a_Struct, a_Member)
86#else
87# define KMK_CC_OFFSETOF(a_Struct, a_Member) ( (uintptr_t)&( ((a_Struct *)(void *)0)->a_Member) )
88#endif
89
90/** def KMK_CC_SIZEOF_MEMBER */
91#define KMK_CC_SIZEOF_MEMBER(a_Struct, a_Member) ( sizeof( ((a_Struct *)(void *)0x1000)->a_Member) )
92
93/** @def KMK_CC_SIZEOF_VAR_STRUCT
94 * Size of a struct with a variable sized array as the final member. */
95#define KMK_CC_SIZEOF_VAR_STRUCT(a_Struct, a_FinalArrayMember, a_cArray) \
96 ( KMK_CC_OFFSETOF(a_Struct, a_FinalArrayMember) + KMK_CC_SIZEOF_MEMBER(a_Struct, a_FinalArrayMember) * (a_cArray) )
97
98
99
100/** @def KMK_CC_STATIC_ASSERT_EX
101 * Compile time assertion with text.
102 */
103#ifdef _MSC_VER_
104# if _MSC_VER >= 1600
105# define KMK_CC_STATIC_ASSERT_EX(a_Expr, a_szExpl) static_assert(a_Expr, a_szExpl)
106# else
107# define KMK_CC_STATIC_ASSERT_EX(a_Expr, a_szExpl) typedef int RTASSERTVAR[(a_Expr) ? 1 : 0]
108# endif
109#elif defined(__GNUC__) && defined(__GXX_EXPERIMENTAL_CXX0X__)
110# define KMK_CC_STATIC_ASSERT_EX(a_Expr, a_szExpl) static_assert(a_Expr, a_szExpl)
111#elif !defined(__GNUC__) && !defined(__IBMC__) && !defined(__IBMCPP__)
112# define KMK_CC_STATIC_ASSERT_EX(a_Expr, a_szExpl) typedef int KMK_CC_STATIC_ASSERT_EX_TYPE[(a_Expr) ? 1 : 0]
113#else
114# define KMK_CC_STATIC_ASSERT_EX(a_Expr, a_szExpl) extern int KMK_CC_STATIC_ASSERT_EX_VAR[(a_Expr) ? 1 : 0]
115extern int KMK_CC_STATIC_ASSERT_EX_VAR[1];
116#endif
117/** @def KMK_CC_STATIC_ASSERT
118 * Compile time assertion, simple variant.
119 */
120#define KMK_CC_STATIC_ASSERT(a_Expr) KMK_CC_STATIC_ASSERT_EX(a_Expr, #a_Expr)
121
122
123/** @def KMK_CC_IS_SPACE_CH
124 * Checks if it's a space char. */
125#define KMK_CC_IS_SPACE_CH(a_ch) isspace((unsigned char)(a_ch))
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
130
131/** @defgroup grp_kmk_cc_evalprog Makefile Evaluation
132 * @{
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
141/** @name KMK_CC_EVAL_QUALIFIER_XXX - Variable qualifiers.
142 * @{ */
143#define KMK_CC_EVAL_QUALIFIER_LOCAL 1
144#define KMK_CC_EVAL_QUALIFIER_EXPORT 2
145#define KMK_CC_EVAL_QUALIFIER_OVERRIDE 4
146#define KMK_CC_EVAL_QUALIFIER_PRIVATE 8
147/** @} */
148
149/** Eval: Max nesting depth of makefile conditionals.
150 * Affects stack usage in kmk_cc_eval_compile_worker. */
151#define KMK_CC_EVAL_MAX_IF_DEPTH 32
152/** Eval: Maximum number of escaped end of line sequences to track.
153 * Affects stack usage in kmk_cc_eval_compile_worker, but not the actual
154 * number of consequtive escaped newlines in the input file/variable. */
155#define KMK_CC_EVAL_MAX_ESC_EOLS 2
156
157/** Minimum keyword length. */
158#define KMK_CC_EVAL_KEYWORD_MIN 2
159/** Maximum keyword length. */
160#define KMK_CC_EVAL_KEYWORD_MAX 16
161
162/** @name KMK_CC_EVAL_CH_XXX - flags found in g_abEvalCcChars.
163 * @{ */
164/** Normal character, nothing special. */
165#define KMK_CC_EVAL_CH_NORMAL UINT16_C(0)
166/** Blank character. */
167#define KMK_CC_EVAL_CH_BLANK UINT16_C(1)
168#define KMK_CC_EVAL_IS_BLANK(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_BLANK)
169/** Space character. */
170#define KMK_CC_EVAL_CH_SPACE UINT16_C(2)
171#define KMK_CC_EVAL_IS_SPACE(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_SPACE)
172/** Space character or potential EOL escape backslash. */
173#define KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH UINT16_C(4)
174#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)
175/** Anything we need to take notice of when parsing something could be a
176 * variable name or a recipe.
177 * All space characters, backslash (EOL escape), variable expansion dollar,
178 * variable assignment operator chars, recipe colon and recipe percent. */
179#define KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE UINT16_C(8)
180#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)
181/** Possible EOL character. */
182#define KMK_CC_EVAL_CH_EOL_CANDIDATE UINT16_C(16)
183#define KMK_CC_EVAL_IS_EOL_CANDIDATE(a_ch) (KMK_CC_EVAL_BM_GET(g_abEvalCcChars, a_ch) & KMK_CC_EVAL_CH_EOL_CANDIDATE)
184/** First character in a keyword. */
185#define KMK_CC_EVAL_CH_1ST_IN_KEYWORD UINT16_C(32)
186#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)
187/** Second character in a keyword. */
188#define KMK_CC_EVAL_CH_2ND_IN_KEYWORD UINT16_C(64)
189#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)
190/** First character in a variable qualifier keyword or 'define'. */
191#define KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD UINT16_C(128)
192#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)
193/** Used when parsing variable names, looking for the end of a nested
194 * variable reference. Matches parentheses and backslash (escaped eol). */
195#define KMK_CC_EVAL_CH_PAREN_OR_SLASH UINT16_C(256)
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)
201/** @} */
202
203/** Sets a bitmap entry.
204 * @param a_abBitmap Typically g_abEvalCcChars.
205 * @param a_ch The character to set.
206 * @param a_uVal The value to OR in. */
207#define KMK_CC_EVAL_BM_OR(g_abBitmap, a_ch, a_uVal) do { (g_abBitmap)[(unsigned char)(a_ch)] |= (a_uVal); } while (0)
208
209/** Gets a bitmap entry.
210 * @returns The value corresponding to @a a_ch.
211 * @param a_abBitmap Typically g_abEvalCcChars.
212 * @param a_ch The character to set. */
213#define KMK_CC_EVAL_BM_GET(g_abBitmap, a_ch) ( (g_abBitmap)[(unsigned char)(a_ch)] )
214
215/** @} */
216
217
218/*********************************************************************************************************************************
219* Structures and Typedefs *
220*********************************************************************************************************************************/
221/**
222 * Block of expand instructions.
223 *
224 * To avoid wasting space on "next" pointers, as well as a lot of time walking
225 * these chains when destroying programs, we work with blocks of instructions.
226 */
227typedef struct kmk_cc_block
228{
229 /** The pointer to the next block (LIFO). */
230 struct kmk_cc_block *pNext;
231 /** The size of this block. */
232 uint32_t cbBlock;
233 /** The offset of the next free byte in the block. When set to cbBlock the
234 * block is 100% full. */
235 uint32_t offNext;
236} KMKCCBLOCK;
237typedef KMKCCBLOCK *PKMKCCBLOCK;
238
239
240/** @defgroup grp_kmk_cc_exp String Expansion
241 * @{*/
242
243/**
244 * String expansion statistics.
245 */
246typedef struct KMKCCEXPSTATS
247{
248 /** Recent average size. */
249 uint32_t cchAvg;
250} KMKCCEXPSTATS;
251typedef KMKCCEXPSTATS *PKMKCCEXPSTATS;
252
253/**
254 * Expansion instructions.
255 */
256typedef enum KMKCCEXPINSTR
257{
258 /** Copy a plain string. */
259 kKmkCcExpInstr_CopyString = 0,
260 /** Insert an expanded variable value, which name we already know. */
261 kKmkCcExpInstr_PlainVariable,
262 /** Insert an expanded variable value, the name is dynamic (sub prog). */
263 kKmkCcExpInstr_DynamicVariable,
264 /** Insert an expanded variable value, which name we already know, doing
265 * search an replace on a string. */
266 kKmkCcExpInstr_SearchAndReplacePlainVariable,
267 /** Insert the output of function that requires no argument expansion. */
268 kKmkCcExpInstr_PlainFunction,
269 /** Insert the output of function that requires dynamic expansion of one ore
270 * more arguments. (Dynamic is perhaps not such a great name, but whatever.) */
271 kKmkCcExpInstr_DynamicFunction,
272 /** Jump to a new instruction block. */
273 kKmkCcExpInstr_Jump,
274 /** We're done, return. Has no specific structure. */
275 kKmkCcExpInstr_Return,
276 /** The end of valid instructions (exclusive). */
277 kKmkCcExpInstr_End
278} KMKCCEXPINSTR;
279
280/** Instruction core. */
281typedef struct kmk_cc_exp_core
282{
283 /** The instruction opcode number (KMKCCEXPINSTR). */
284 KMKCCEXPINSTR enmOpCode;
285} KMKCCEXPCORE;
286typedef KMKCCEXPCORE *PKMKCCEXPCORE;
287
288/**
289 * String expansion subprogram.
290 */
291#pragma pack(1) /* save some precious bytes */
292typedef struct kmk_cc_exp_subprog
293{
294 /** Pointer to the first instruction. */
295 PKMKCCEXPCORE pFirstInstr;
296 /** Statistics. */
297 KMKCCEXPSTATS Stats;
298} KMKCCEXPSUBPROG;
299#pragma pack()
300typedef KMKCCEXPSUBPROG *PKMKCCEXPSUBPROG;
301KMK_CC_STATIC_ASSERT(sizeof(KMKCCEXPSUBPROG) == 12 || sizeof(void *) != 8);
302
303
304/**
305 * String expansion subprogram or plain string.
306 */
307#pragma pack(1) /* save some precious bytes */
308typedef struct kmk_cc_exp_subprog_or_string
309{
310 /** Either a plain string pointer or a subprogram. */
311 union
312 {
313 /** Subprogram for expanding this argument. */
314 KMKCCEXPSUBPROG Subprog;
315 /** Pointer to the plain string. */
316 struct
317 {
318 /** Pointer to the string. */
319 const char *psz;
320 /** String length. */
321 uint32_t cch;
322 } Plain;
323 } u;
324 /** Set if subprogram (u.Subprog), clear if plain string (u.Plain). */
325 uint8_t fSubprog;
326 /** Set if the plain string is kept in the variable_strcache.
327 * @remarks Here rather than in u.Plain to make use of alignment padding. */
328 uint8_t fPlainIsInVarStrCache;
329 /** Context/user specific. */
330 uint8_t bUser;
331 /** Context/user specific #2. */
332 uint8_t bUser2;
333} KMKCCEXPSUBPROGORPLAIN;
334#pragma pack()
335typedef KMKCCEXPSUBPROGORPLAIN *PKMKCCEXPSUBPROGORPLAIN;
336KMK_CC_STATIC_ASSERT( sizeof(void *) == 8
337 ? sizeof(KMKCCEXPSUBPROGORPLAIN) == 16
338 : sizeof(void *) == 4
339 ? sizeof(KMKCCEXPSUBPROGORPLAIN) == 12
340 : 1);
341
342/**
343 * kKmkCcExpInstr_CopyString instruction format.
344 */
345typedef struct kmk_cc_exp_copy_string
346{
347 /** The core instruction. */
348 KMKCCEXPCORE Core;
349 /** The number of bytes to copy. */
350 uint32_t cchCopy;
351 /** Pointer to the source string (not terminated at cchCopy). */
352 const char *pachSrc;
353} KMKCCEXPCOPYSTRING;
354typedef KMKCCEXPCOPYSTRING *PKMKCCEXPCOPYSTRING;
355
356/**
357 * kKmkCcExpInstr_PlainVariable instruction format.
358 */
359typedef struct kmk_cc_exp_plain_variable
360{
361 /** The core instruction. */
362 KMKCCEXPCORE Core;
363 /** The name of the variable (points into variable_strcache). */
364 const char *pszName;
365} KMKCCEXPPLAINVAR;
366typedef KMKCCEXPPLAINVAR *PKMKCCEXPPLAINVAR;
367
368/**
369 * kKmkCcExpInstr_DynamicVariable instruction format.
370 */
371typedef struct kmk_cc_exp_dynamic_variable
372{
373 /** The core instruction. */
374 KMKCCEXPCORE Core;
375 /** The subprogram that will give us the variable name. */
376 KMKCCEXPSUBPROG Subprog;
377 /** Where to continue after this instruction. (This is necessary since the
378 * instructions of the subprogram are emitted after this instruction.) */
379 PKMKCCEXPCORE pNext;
380} KMKCCEXPDYNVAR;
381typedef KMKCCEXPDYNVAR *PKMKCCEXPDYNVAR;
382
383/**
384 * kKmkCcExpInstr_SearchAndReplacePlainVariable instruction format.
385 */
386typedef struct kmk_cc_exp_sr_plain_variable
387{
388 /** The core instruction. */
389 KMKCCEXPCORE Core;
390 /** Where to continue after this instruction. (This is necessary since the
391 * instruction contains string data of variable size.) */
392 PKMKCCEXPCORE pNext;
393 /** The name of the variable (points into variable_strcache). */
394 const char *pszName;
395 /** Search pattern. */
396 const char *pszSearchPattern;
397 /** Replacement pattern. */
398 const char *pszReplacePattern;
399 /** Offset into pszSearchPattern of the significant '%' char. */
400 uint32_t offPctSearchPattern;
401 /** Offset into pszReplacePattern of the significant '%' char. */
402 uint32_t offPctReplacePattern;
403} KMKCCEXPSRPLAINVAR;
404typedef KMKCCEXPSRPLAINVAR *PKMKCCEXPSRPLAINVAR;
405
406/**
407 * Instruction format parts common to both kKmkCcExpInstr_PlainFunction and
408 * kKmkCcExpInstr_DynamicFunction.
409 */
410typedef struct kmk_cc_exp_function_core
411{
412 /** The core instruction. */
413 KMKCCEXPCORE Core;
414 /** Number of arguments. */
415 uint32_t cArgs; /**< @todo uint16_t to save 7 bytes of unecessary alignment padding on 64-bit systems, or merge fDirty into this member. */
416 /** Set if the function could be modifying the input arguments. */
417 uint8_t fDirty;
418 /** Where to continue after this instruction. (This is necessary since the
419 * instructions are of variable size and may be followed by string data.) */
420 PKMKCCEXPCORE pNext;
421 /**
422 * Pointer to the function table entry.
423 *
424 * @returns New variable buffer position.
425 * @param pchDst Current variable buffer position.
426 * @param papszArgs Pointer to a NULL terminated array of argument strings.
427 * @param pszFuncName The name of the function being called.
428 */
429 char * (*pfnFunction)(char *pchDst, char **papszArgs, const char *pszFuncName);
430 /** Pointer to the function name in the variable string cache. */
431 const char *pszFuncName;
432} KMKCCEXPFUNCCORE;
433typedef KMKCCEXPFUNCCORE *PKMKCCEXPFUNCCORE;
434
435/**
436 * Instruction format for kKmkCcExpInstr_PlainFunction.
437 */
438typedef struct kmk_cc_exp_plain_function
439{
440 /** The bits comment to both plain and dynamic functions. */
441 KMKCCEXPFUNCCORE FnCore;
442 /** Variable sized argument list (cArgs + 1 in length, last entry is NULL).
443 * The string pointers are to memory following this instruction, to memory in
444 * the next block or to memory in the variable / makefile we're working on
445 * (if zero terminated appropriately). */
446 const char *apszArgs[1];
447} KMKCCEXPPLAINFUNC;
448typedef KMKCCEXPPLAINFUNC *PKMKCCEXPPLAINFUNC;
449/** Calculates the size of an KMKCCEXPPLAINFUNC structure with the apszArgs
450 * member holding a_cArgs entries plus a NULL terminator. */
451#define KMKCCEXPPLAINFUNC_SIZE(a_cArgs) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEXPDYNFUNC, aArgs, (a_cArgs) + 1)
452
453/**
454 * Instruction format for kKmkCcExpInstr_DynamicFunction.
455 */
456typedef struct kmk_cc_exp_dyn_function
457{
458 /** The bits comment to both plain and dynamic functions. */
459 KMKCCEXPFUNCCORE FnCore;
460 /** Variable sized argument list (FnCore.cArgs in length).
461 * The subprograms / strings are allocated after this array (or in the next
462 * block). */
463 KMKCCEXPSUBPROGORPLAIN aArgs[1];
464} KMKCCEXPDYNFUNC;
465typedef KMKCCEXPDYNFUNC *PKMKCCEXPDYNFUNC;
466/** Calculates the size of an KMKCCEXPDYNFUNC structure with the apszArgs
467 * member holding a_cArgs entries (no zero terminator). */
468#define KMKCCEXPDYNFUNC_SIZE(a_cArgs) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEXPDYNFUNC, aArgs, a_cArgs)
469
470/**
471 * Instruction format for kKmkCcExpInstr_Jump.
472 */
473typedef struct kmk_cc_exp_jump
474{
475 /** The core instruction. */
476 KMKCCEXPCORE Core;
477 /** Where to jump to (new instruction block, typically). */
478 PKMKCCEXPCORE pNext;
479} KMKCCEXPJUMP;
480typedef KMKCCEXPJUMP *PKMKCCEXPJUMP;
481
482/**
483 * String expansion program.
484 */
485typedef struct kmk_cc_expandprog
486{
487 /** Pointer to the first instruction for this program. */
488 PKMKCCEXPCORE pFirstInstr;
489 /** List of blocks for this program (LIFO). */
490 PKMKCCBLOCK pBlockTail;
491 /** Statistics. */
492 KMKCCEXPSTATS Stats;
493#ifdef KMK_CC_STRICT
494 /** The hash of the input string. Used to check that we get all the change
495 * notifications we require. */
496 uint32_t uInputHash;
497#endif
498 /** Reference count. */
499 uint32_t volatile cRefs;
500} KMKCCEXPPROG;
501/** Pointer to a string expansion program. */
502typedef KMKCCEXPPROG *PKMKCCEXPPROG;
503
504/** @} */
505
506
507/** @addtogroup grp_kmk_cc_evalprog
508 * @{ */
509
510/** Pointer to a makefile evaluation program. */
511typedef struct kmk_cc_evalprog *PKMKCCEVALPROG;
512
513/**
514 * Makefile evaluation instructions.
515 */
516typedef enum KMKCCEVALINSTR
517{
518 /** Jump instruction - KMKCCEVALJUMP. */
519 kKmkCcEvalInstr_jump = 0,
520
521 /** [local|override|export] variable = value - KMKCCEVALASSIGN.
522 * @note Can be used for target-specific variables. */
523 kKmkCcEvalInstr_assign_recursive,
524 /** [local|override|export] variable := value - KMKCCEVALASSIGN.
525 * @note Can be used for target-specific variables. */
526 kKmkCcEvalInstr_assign_simple,
527 /** [local|override|export] variable += value - KMKCCEVALASSIGN.
528 * @note Can be used for target-specific variables. */
529 kKmkCcEvalInstr_assign_append,
530 /** [local|override|export] variable -= value - KMKCCEVALASSIGN.
531 * @note Can be used for target-specific variables. */
532 kKmkCcEvalInstr_assign_prepend,
533 /** [local|override|export] variable ?= value - KMKCCEVALASSIGN.
534 * @note Can be used for target-specific variables. */
535 kKmkCcEvalInstr_assign_if_new,
536 /** [local|override|export] define variable ... endef - KMKCCEVALASSIGNDEF. */
537 kKmkCcEvalInstr_assign_define,
538
539 /** export variable1 [variable2...] - KMKCCEVALEXPORT. */
540 kKmkCcEvalInstr_export,
541 /** unexport variable1 [variable2...] - KMKCCEVALEXPORT. */
542 kKmkCcEvalInstr_unexport,
543 /** export - KMKCCEVALCORE. */
544 kKmkCcEvalInstr_export_all,
545 /** unexport - KMKCCEVALCORE. */
546 kKmkCcEvalInstr_unexport_all,
547
548 /** [else] ifdef variable - KMKCCEVALIFDEFPLAIN. */
549 kKmkCcEvalInstr_ifdef_plain,
550 /** [else] ifndef variable - KMKCCEVALIFDEFPLAIN. */
551 kKmkCcEvalInstr_ifndef_plain,
552 /** [else] ifdef variable - KMKCCEVALIFDEFDYNAMIC. */
553 kKmkCcEvalInstr_ifdef_dynamic,
554 /** [else] ifndef variable - KMKCCEVALIFDEFDYNAMIC. */
555 kKmkCcEvalInstr_ifndef_dynamic,
556 /** [else] ifeq (a,b) - KMKCCEVALIFEQ. */
557 kKmkCcEvalInstr_ifeq,
558 /** [else] ifeq (a,b) - KMKCCEVALIFEQ. */
559 kKmkCcEvalInstr_ifneq,
560 /** [else] if1of (set-a,set-b) - KMKCCEVALIF1OF. */
561 kKmkCcEvalInstr_if1of,
562 /** [else] ifn1of (set-a,set-b) - KMKCCEVALIF1OF. */
563 kKmkCcEvalInstr_ifn1of,
564 /** [else] if expr - KMKCCEVALIFEXPR. */
565 kKmkCcEvalInstr_if,
566
567 /** include file1 [file2...] - KMKCCEVALINCLUDE. */
568 kKmkCcEvalInstr_include,
569 /** [sinclude|-include] file1 [file2...] - KMKCCEVALINCLUDE. */
570 kKmkCcEvalInstr_include_silent,
571 /** includedep file1 [file2...] - KMKCCEVALINCLUDE. */
572 kKmkCcEvalInstr_includedep,
573 /** includedep-queue file1 [file2...] - KMKCCEVALINCLUDE. */
574 kKmkCcEvalInstr_includedep_queue,
575 /** includedep-flush file1 [file2...] - KMKCCEVALINCLUDE. */
576 kKmkCcEvalInstr_includedep_flush,
577
578 /** Recipe without commands (defines dependencies) - KMKCCEVALRECIPE. */
579 kKmkCcEvalInstr_recipe_no_commands,
580 /** Recipe with commands (defines dependencies) - KMKCCEVALRECIPE. */
581 kKmkCcEvalInstr_recipe_start_normal,
582 /** Recipe with commands (defines dependencies) - KMKCCEVALRECIPE. */
583 kKmkCcEvalInstr_recipe_start_double_colon,
584 /** Recipe with commands (defines dependencies) - KMKCCEVALRECIPE. */
585 kKmkCcEvalInstr_recipe_start_pattern,
586 /** Adds more commands to the current recipe - KMKCCEVALRECIPECOMMANDS. */
587 kKmkCcEvalInstr_recipe_commands,
588 /** Special instruction for indicating the end of the recipe commands - KMKCCEVALCORE. */
589 kKmkCcEvalInstr_recipe_end,
590 /** Cancel previously defined pattern rule - KMKCCEVALRECIPE. */
591 kKmkCcEvalInstr_recipe_cancel_pattern,
592
593 /** vpath pattern directories - KMKCCEVALVPATH. */
594 kKmkCcEvalInstr_vpath,
595 /** vpath pattern directories - KMKCCEVALVPATH. */
596 kKmkCcEvalInstr_vpath_clear_pattern,
597 /** vpath - KMKCCEVALCORE. */
598 kKmkCcEvalInstr_vpath_clear_all,
599
600 /** The end of valid instructions (exclusive). */
601 kKmkCcEvalInstr_End
602} KMKCCEVALINSTR;
603
604/**
605 * Instruction core common to all instructions.
606 */
607typedef struct kmk_cc_eval_core
608{
609 /** The instruction opcode number (KMKCCEVALINSTR). */
610 KMKCCEVALINSTR enmOpCode;
611 /** The line number in the source this statement is associated with. */
612 unsigned iLine;
613} KMKCCEVALCORE;
614/** Pointer to an instruction core structure. */
615typedef KMKCCEVALCORE *PKMKCCEVALCORE;
616
617/**
618 * Instruction format for kKmkCcEvalInstr_jump.
619 */
620typedef struct kmk_cc_eval_jump
621{
622 /** The core instruction. */
623 KMKCCEVALCORE Core;
624 /** Where to jump to (new instruction block or endif, typically). */
625 PKMKCCEVALCORE pNext;
626} KMKCCEVALJUMP;
627typedef KMKCCEVALJUMP *PKMKCCEVALJUMP;
628
629/**
630 * Instruction format for kKmkCcEvalInstr_assign_recursive,
631 * kKmkCcEvalInstr_assign_simple, kKmkCcEvalInstr_assign_append,
632 * kKmkCcEvalInstr_assign_prepend and kKmkCcEvalInstr_assign_if_new.
633 */
634typedef struct kmk_cc_eval_assign
635{
636 /** The core instruction. */
637 KMKCCEVALCORE Core;
638 /** Whether the 'export' directive was used. */
639 uint8_t fExport;
640 /** Whether the 'override' directive was used. */
641 uint8_t fOverride;
642 /** Whether the 'local' directive was used. */
643 uint8_t fLocal;
644 /** The variable name.
645 * @remarks Plain text names are in variable_strcache. */
646 KMKCCEXPSUBPROGORPLAIN Variable;
647 /** The value or value expression. */
648 KMKCCEXPSUBPROGORPLAIN Value;
649 /** Pointer to the next instruction. */
650 PKMKCCEVALCORE pNext;
651} KMKCCEVALASSIGN;
652typedef KMKCCEVALASSIGN *PKMKCCEVALASSIGN;
653
654/**
655 * Instruction format for kKmkCcEvalInstr_assign_define.
656 */
657typedef struct kmk_cc_eval_assign_define
658{
659 /** The assignment core structure. */
660 KMKCCEVALASSIGN AssignCore;
661 /** Makefile evaluation program compiled from the define.
662 * NULL if it does not compile.
663 * @todo Let's see if this is actually doable... */
664 PKMKCCEVALPROG pEvalProg;
665} KMKCCEVALASSIGNDEF;
666typedef KMKCCEVALASSIGNDEF *PKMKCCEVALASSIGNDEF;
667
668/**
669 * Instruction format for kKmkCcEvalInstr_export and kKmkCcEvalInstr_unexport.
670 */
671typedef struct kmk_cc_eval_export
672{
673 /** The core instruction. */
674 KMKCCEVALCORE Core;
675 /** The number of variables named in aVars. */
676 uint32_t cVars;
677 /** Pointer to the next instruction. */
678 PKMKCCEVALCORE pNext;
679 /** The variable names.
680 * Expressions will be expanded and split on space.
681 * @remarks Plain text names are in variable_strcache. */
682 KMKCCEXPSUBPROGORPLAIN aVars[1];
683} KMKCCEVALEXPORT;
684typedef KMKCCEVALEXPORT *PKMKCCEVALEXPORT;
685/** Calculates the size of an KMKCCEVALEXPORT structure for @a a_cVars. */
686#define KMKCCEVALEXPORT_SIZE(a_cVars) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEVALVPATH, aVars, a_cVars)
687
688/**
689 * Core structure for all conditionals (kKmkCcEvalInstr_if*).
690 */
691typedef struct kmk_cc_eval_if_core
692{
693 /** The core instruction. */
694 KMKCCEVALCORE Core;
695 /** Condition true: Pointer to the next instruction. */
696 PKMKCCEVALCORE pNextTrue;
697 /** Condition false: Pointer to the next instruction (i.e. 'else if*'
698 * or whatever follows 'else' / 'endif'. */
699 PKMKCCEVALCORE pNextFalse;
700 /** Pointer to the previous conditional for 'else if*' directives.
701 * This is only to assist the compilation process. */
702 struct kmk_cc_eval_if_core *pPrevCond;
703 /** Pointer to the jump out of the true block, if followed by 'else'.
704 * This is only to assist the compilation process. */
705 PKMKCCEVALJUMP pTrueEndJump;
706} KMKCCEVALIFCORE;
707typedef KMKCCEVALIFCORE *PKMKCCEVALIFCORE;
708
709/**
710 * Instruction format for kKmkCcEvalInstr_ifdef_plain and
711 * kKmkCcEvalInstr_ifndef_plain.
712 * The variable name is known at compilation time.
713 */
714typedef struct kmk_cc_eval_ifdef_plain
715{
716 /** The 'if' core structure. */
717 KMKCCEVALIFCORE IfCore;
718 /** The name of the variable (points into variable_strcache). */
719 const char *pszName;
720} KMKCCEVALIFDEFPLAIN;
721typedef KMKCCEVALIFDEFPLAIN *PKMKCCEVALIFDEFPLAIN;
722
723/**
724 * Instruction format for kKmkCcEvalInstr_ifdef_dynamic and
725 * kKmkCcEvalInstr_ifndef_dynamic.
726 * The variable name is dynamically expanded at run time.
727 */
728typedef struct kmk_cc_eval_ifdef_dynamic
729{
730 /** The 'if' core structure. */
731 KMKCCEVALIFCORE IfCore;
732 /** The subprogram that will give us the variable name. */
733 KMKCCEXPSUBPROG NameSubprog;
734} KMKCCEVALIFDEFDYNAMIC;
735typedef KMKCCEVALIFDEFDYNAMIC *PKMKCCEVALIFDEFDYNAMIC;
736
737/**
738 * Instruction format for kKmkCcEvalInstr_ifeq and kKmkCcEvalInstr_ifneq.
739 */
740typedef struct kmk_cc_eval_ifeq
741{
742 /** The 'if' core structure. */
743 KMKCCEVALIFCORE IfCore;
744 /** The left hand side string expression (dynamic or plain). */
745 KMKCCEXPSUBPROGORPLAIN Left;
746 /** The rigth hand side string expression (dynamic or plain). */
747 KMKCCEXPSUBPROGORPLAIN Right;
748} KMKCCEVALIFEQ;
749typedef KMKCCEVALIFEQ *PKMKCCEVALIFEQ;
750
751/**
752 * Instruction format for kKmkCcEvalInstr_if1of and kKmkCcEvalInstr_ifn1of.
753 *
754 * @todo This can be optimized further by pre-hashing plain text items. One of
755 * the sides are usually plain text.
756 */
757typedef struct kmk_cc_eval_if1of
758{
759 /** The 'if' core structure. */
760 KMKCCEVALIFCORE IfCore;
761 /** The left hand side string expression (dynamic or plain). */
762 KMKCCEXPSUBPROGORPLAIN Left;
763 /** The rigth hand side string expression (dynamic or plain). */
764 KMKCCEXPSUBPROGORPLAIN Right;
765} KMKCCEVALIF1OF;
766typedef KMKCCEVALIF1OF *PKMKCCEVALIF1OF;
767
768/**
769 * Instruction format for kKmkCcEvalInstr_if.
770 *
771 * @todo Parse and compile the expression. At least strip whitespace in it.
772 */
773typedef struct kmk_cc_eval_if_expr
774{
775 /** The 'if' core structure. */
776 KMKCCEVALIFCORE IfCore;
777 /** The expression string length. */
778 uint16_t cchExpr;
779 /** The expression string. */
780 char szExpr[1];
781} KMKCCEVALIFEXPR;
782typedef KMKCCEVALIFEXPR *PKMKCCEVALIFEXPR;
783/** Calculates the size of an KMKCCEVALIFEXPR structure for @a a_cchExpr long
784 * expression string (terminator is automatically added). */
785#define KMKCCEVALIFEXPR_SIZE(a_cchExpr) KMK_CC_BLOCK_ALIGN_SIZE(KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEVALIFEXPR, szExpr, (a_cchExpr) + 1))
786
787/**
788 * Instruction format for kKmkCcEvalInstr_include,
789 * kKmkCcEvalInstr_include_silent, kKmkCcEvalInstr_includedep,
790 * kKmkCcEvalInstr_includedep_queue, kKmkCcEvalInstr_includedep_flush.
791 */
792typedef struct kmk_cc_eval_include
793{
794 /** The core instruction. */
795 KMKCCEVALCORE Core;
796 /** The number of files. */
797 uint32_t cFiles;
798 /** Pointer to the next instruction (subprogs and strings after this one). */
799 PKMKCCEVALCORE pNext;
800 /** The files to be included.
801 * Expressions will be expanded and split on space.
802 * @todo Plain text file name could be replaced by file string cache entries. */
803 KMKCCEXPSUBPROGORPLAIN aFiles[1];
804} KMKCCEVALINCLUDE;
805typedef KMKCCEVALINCLUDE *PKMKCCEVALINCLUDE;
806/** Calculates the size of an KMKCCEVALINCLUDE structure for @a a_cFiles files. */
807#define KMKCCEVALINCLUDE_SIZE(a_cFiles) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEVALINCLUDE, aFiles, a_cFiles)
808
809/**
810 * Instruction format for kKmkCcEvalInstr_recipe_no_commands,
811 * kKmkCcEvalInstr_recipe_start_normal,
812 * kKmkCcEvalInstr_recipe_start_double_colon, kKmkCcEvalInstr_includedep_queue,
813 * kKmkCcEvalInstr_recipe_start_pattern.
814 */
815typedef struct kmk_cc_eval_recipe
816{
817 /** The core instruction. */
818 KMKCCEVALCORE Core;
819 /** The total number of files and dependencies in aFilesAndDeps. */
820 uint16_t cFilesAndDeps;
821
822 /** Number of targets (from index 0).
823 * This is always 1 if this is an explicit multitarget or pattern recipe,
824 * indicating the main target. */
825 uint16_t cTargets;
826 /** Explicit multitarget & patterns: First always made target. */
827 uint16_t iFirstAlwaysMadeTargets;
828 /** Explicit multitarget & patterns: Number of always targets. */
829 uint16_t cAlwaysMadeTargets;
830 /** Explicit multitarget: First maybe made target. */
831 uint16_t iFirstMaybeTarget;
832 /** Explicit multitarget: Number of maybe made targets. */
833 uint16_t cMaybeTargets;
834
835 /** First dependency. */
836 uint16_t iFirstDep;
837 /** Number of ordinary dependnecies. */
838 uint16_t cDeps;
839 /** First order only dependency. */
840 uint16_t iFirstOrderOnlyDep;
841 /** Number of ordinary dependnecies. */
842 uint16_t cOrderOnlyDeps;
843
844 /** Pointer to the next instruction (subprogs and strings after this one). */
845 PKMKCCEVALCORE pNext;
846 /** The .MUST_MAKE variable value, if present.
847 * If not present, this is a zero length plain string. */
848 KMKCCEXPSUBPROGORPLAIN MustMake;
849 /** The target files and dependencies.
850 * This is sorted into several sections, as defined by the above indexes and
851 * counts. Expressions will be expanded and split on space.
852 *
853 * The KMKCCEXPSUBPROGORPLAIN::bUser member one of KMKCCEVALRECIPE_FD_XXX.
854 *
855 * @todo Plain text file name could be replaced by file string cache entries. */
856 KMKCCEXPSUBPROGORPLAIN aFilesAndDeps[1];
857} KMKCCEVALRECIPE;
858typedef KMKCCEVALRECIPE *PKMKCCEVALRECIPE;
859/** Calculates the size of an KMKCCEVALRECIPE structure for @a a_cFiles
860 * files. */
861#define KMKCCEVALRECIPE_SIZE(a_cFilesAndDeps) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEVALRECIPE, aFilesAndDeps, a_cFilesAndDeps)
862/** @name KMKCCEVALRECIPE_FD_XXX - Values for KMKCCEVALRECIPE::aFilesAndDeps[x].bUser
863 * @{ */
864#define KMKCCEVALRECIPE_FD_NORMAL 0
865#define KMKCCEVALRECIPE_FD_SEC_EXP 1
866#define KMKCCEVALRECIPE_FD_SPECIAL_POSIX 2
867#define KMKCCEVALRECIPE_FD_SPECIAL_SECONDEXPANSION 3
868#define KMKCCEVALRECIPE_FD_SPECIAL_ONESHELL 4
869/** @} */
870
871
872/**
873 * Instruction format for kKmkCcEvalInstr_recipe_commands.
874 */
875typedef struct kmk_cc_eval_recipe_commands
876{
877 /** The core instruction. */
878 KMKCCEVALCORE Core;
879 /** The number of search directories. */
880 uint32_t cCommands;
881 /** Pointer to the next instruction (subprogs and strings after this one). */
882 PKMKCCEVALCORE pNext;
883 /** Commands to add to the current recipe.
884 * Expressions will be expanded and split on space. */
885 KMKCCEXPSUBPROGORPLAIN aCommands[1];
886} KMKCCEVALRECIPECOMMANDS;
887typedef KMKCCEVALRECIPECOMMANDS *PKMKCCEVALRECIPECOMMANDS;
888/** Calculates the size of an KMKCCEVALRECIPECOMMANDS structure for
889 * @a a_cCommands commands. */
890#define KMKCCEVALRECIPECOMMANDS_SIZE(a_cCommands) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEVALRECIPECOMMANDS, aCommands, a_cCommands)
891
892/**
893 * Instruction format for kKmkCcEvalInstr_vpath and
894 * kKmkCcEvalInstr_vpath_clear_pattern.
895 */
896typedef struct kmk_cc_eval_vpath
897{
898 /** The core instruction. */
899 KMKCCEVALCORE Core;
900 /** The number of search directories.
901 * This will be zero for kKmkCcEvalInstr_vpath_clear_pattern. */
902 uint32_t cDirs;
903 /** Pointer to the next instruction (subprogs and strings after this one). */
904 PKMKCCEVALCORE pNext;
905 /** The pattern. */
906 KMKCCEXPSUBPROGORPLAIN Pattern;
907 /** The directory. Expressions will be expanded and split on space. */
908 KMKCCEXPSUBPROGORPLAIN aDirs[1];
909} KMKCCEVALVPATH;
910typedef KMKCCEVALVPATH *PKMKCCEVALVPATH;
911/** Calculates the size of an KMKCCEVALVPATH structure for @a a_cFiles files. */
912#define KMKCCEVALVPATH_SIZE(a_cFiles) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEVALVPATH, aDirs, a_cDirs)
913
914
915/**
916 * Makefile evaluation program.
917 */
918typedef struct kmk_cc_evalprog
919{
920 /** Pointer to the first instruction for this program. */
921 PKMKCCEVALCORE pFirstInstr;
922 /** List of blocks for this program (LIFO). */
923 PKMKCCBLOCK pBlockTail;
924 /** The name of the file containing this program. */
925 const char *pszFilename;
926 /** The name of the variable containing this program, if applicable. */
927 const char *pszVarName;
928#ifdef KMK_CC_STRICT
929 /** The hash of the input string. Used to check that we get all the change
930 * notifications we require. */
931 uint32_t uInputHash;
932#endif
933 /** Reference count. */
934 uint32_t volatile cRefs;
935} KMKCCEVALPROG;
936typedef KMKCCEVALPROG *PKMKCCEVALPROG;
937
938/** @} */
939
940
941/*********************************************************************************************************************************
942* Global Variables *
943*********************************************************************************************************************************/
944static uint32_t g_cVarForExpandCompilations = 0;
945static uint32_t g_cVarForExpandExecs = 0;
946static uint32_t g_cVarForEvalCompilations = 0;
947static uint32_t g_cVarForEvalExecs = 0;
948static uint32_t g_cFileForEvalCompilations = 0;
949static uint32_t g_cFileForEvalExecs = 0;
950#ifdef KMK_CC_WITH_STATS
951static uint32_t g_cBlockAllocated = 0;
952static uint32_t g_cbAllocated = 0;
953
954static uint32_t g_cBlocksAllocatedExpProgs = 0;
955static uint32_t g_cbAllocatedExpProgs = 0;
956static uint32_t g_cSingleBlockExpProgs = 0;
957static uint32_t g_cTwoBlockExpProgs = 0;
958static uint32_t g_cMultiBlockExpProgs = 0;
959static uint32_t g_cbUnusedMemExpProgs = 0;
960
961static uint32_t g_cBlocksAllocatedEvalProgs = 0;
962static uint32_t g_cbAllocatedEvalProgs = 0;
963static uint32_t g_cSingleBlockEvalProgs = 0;
964static uint32_t g_cTwoBlockEvalProgs = 0;
965static uint32_t g_cMultiBlockEvalProgs = 0;
966static uint32_t g_cbUnusedMemEvalProgs = 0;
967
968#endif
969
970/** Generic character classification, taking an 'unsigned char' index.
971 * ASSUMES unsigned char is 8-bits. */
972static uint16_t g_abEvalCcChars[256];
973
974
975/**
976 * Makefile evaluation keywords.
977 */
978static const char * const g_apszEvalKeywords[] =
979{
980 "define",
981 "export",
982 "else",
983 "endef",
984 "endif",
985 "ifdef",
986 "ifndef",
987 "ifeq",
988 "ifneq",
989 "if1of",
990 "ifn1of",
991 "if",
992 "include",
993 "includedep",
994 "includedep-queue",
995 "includedep-flush",
996 "local",
997 "override",
998 "private",
999 "sinclude",
1000 "unexport",
1001 "undefine",
1002 "vpath",
1003 "-include",
1004};
1005
1006
1007/*********************************************************************************************************************************
1008* Internal Functions *
1009*********************************************************************************************************************************/
1010static int kmk_cc_exp_compile_subprog(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr, PKMKCCEXPSUBPROG pSubprog);
1011static char *kmk_exec_expand_subprog_to_tmp(PKMKCCEXPSUBPROG pSubprog, uint32_t *pcch);
1012
1013
1014/**
1015 * Initializes global variables for the 'compiler'.
1016 */
1017void kmk_cc_init(void)
1018{
1019 unsigned i;
1020
1021 /*
1022 * Initialize the bitmap.
1023 */
1024 memset(g_abEvalCcChars, 0, sizeof(g_abEvalCcChars));
1025
1026 /* blank chars */
1027 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ' ', KMK_CC_EVAL_CH_BLANK);
1028 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\t', KMK_CC_EVAL_CH_BLANK);
1029
1030 /* space chars and zero terminator. */
1031#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
1032 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ' ', MY_SPACE_BITS);
1033 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\t', MY_SPACE_BITS);
1034 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\n', MY_SPACE_BITS | KMK_CC_EVAL_CH_EOL_CANDIDATE);
1035 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\v', MY_SPACE_BITS);
1036 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\f', MY_SPACE_BITS);
1037 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\r', MY_SPACE_BITS | KMK_CC_EVAL_CH_EOL_CANDIDATE);
1038 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '\\', KMK_CC_EVAL_CH_SPACE_OR_BACKSLASH | KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE);
1039#undef MY_SPACE_BITS
1040
1041 /* keywords */
1042 for (i = 0; i < K_ELEMENTS(g_apszEvalKeywords); i++)
1043 {
1044 size_t cch = strlen(g_apszEvalKeywords[i]);
1045 KMK_CC_ASSERT(cch >= KMK_CC_EVAL_KEYWORD_MIN);
1046 KMK_CC_ASSERT(cch <= KMK_CC_EVAL_KEYWORD_MAX);
1047
1048 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, g_apszEvalKeywords[i][0], KMK_CC_EVAL_CH_1ST_IN_KEYWORD);
1049 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, g_apszEvalKeywords[i][1], KMK_CC_EVAL_CH_2ND_IN_KEYWORD);
1050 }
1051 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'd', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* define */
1052 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'e', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* export (, endef) */
1053 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'l', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* local */
1054 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'o', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* override */
1055 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'p', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* private */
1056 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'u', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* undefine */
1057
1058 /* Assignment punctuation and recipe stuff. */
1059 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '=', KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE);
1060 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ':', KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE);
1061 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '<', KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE);
1062 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '?', KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE);
1063 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '+', KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE);
1064 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '%', KMK_CC_EVAL_CH_SPACE_OR_VAR_OR_RECIPE); /* uncertain... */
1065
1066 /* For locating the end of variable expansion. */
1067 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '(', KMK_CC_EVAL_CH_PAREN_OR_SLASH);
1068 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, ')', KMK_CC_EVAL_CH_PAREN_OR_SLASH);
1069 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '{', KMK_CC_EVAL_CH_PAREN_OR_SLASH);
1070 KMK_CC_EVAL_BM_OR(g_abEvalCcChars, '}', KMK_CC_EVAL_CH_PAREN_OR_SLASH);
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);
1078}
1079
1080
1081/**
1082 * Prints stats (for kmk -p).
1083 */
1084void kmk_cc_print_stats(void)
1085{
1086#ifdef KMK_CC_WITH_STATS
1087 uint32_t const cEvalCompilations = g_cFileForEvalCompilations + g_cVarForEvalCompilations;
1088#endif
1089
1090 puts(_("\n# The kmk 'compiler' and kmk 'program executor':\n"));
1091
1092 printf(_("# Variables compiled for string expansion: %6u\n"), g_cVarForExpandCompilations);
1093 printf(_("# Variables string expansion runs: %6u\n"), g_cVarForExpandExecs);
1094 printf(_("# String expansion runs per compile: %6u\n"), g_cVarForExpandExecs / g_cVarForExpandCompilations);
1095#ifdef KMK_CC_WITH_STATS
1096 printf(_("# Single alloc block exp progs: %6u (%u%%)\n"
1097 "# Two alloc block exp progs: %6u (%u%%)\n"
1098 "# Three or more alloc block exp progs: %6u (%u%%)\n"
1099 ),
1100 g_cSingleBlockExpProgs, (uint32_t)((uint64_t)g_cSingleBlockExpProgs * 100 / g_cVarForExpandCompilations),
1101 g_cTwoBlockExpProgs, (uint32_t)((uint64_t)g_cTwoBlockExpProgs * 100 / g_cVarForExpandCompilations),
1102 g_cMultiBlockExpProgs, (uint32_t)((uint64_t)g_cMultiBlockExpProgs * 100 / g_cVarForExpandCompilations));
1103 printf(_("# Total amount of memory for exp progs: %8u bytes\n"
1104 "# in: %6u blocks\n"
1105 "# avg block size: %6u bytes\n"
1106 "# unused memory: %8u bytes (%u%%)\n"
1107 "# avg unused memory per block: %6u bytes\n"
1108 "\n"),
1109 g_cbAllocatedExpProgs, g_cBlocksAllocatedExpProgs, g_cbAllocatedExpProgs / g_cBlocksAllocatedExpProgs,
1110 g_cbUnusedMemExpProgs, (uint32_t)((uint64_t)g_cbUnusedMemExpProgs * 100 / g_cbAllocatedExpProgs),
1111 g_cbUnusedMemExpProgs / g_cBlocksAllocatedExpProgs);
1112 puts("");
1113#endif
1114 printf(_("# Variables compiled for string eval: %6u\n"), g_cVarForEvalCompilations);
1115 printf(_("# Variables string eval runs: %6u\n"), g_cVarForEvalExecs);
1116 printf(_("# String evals runs per compile: %6u\n"), g_cVarForEvalExecs / g_cVarForEvalCompilations);
1117 printf(_("# Files compiled: %6u\n"), g_cFileForEvalCompilations);
1118 printf(_("# Files runs: %6u\n"), g_cFileForEvalExecs);
1119 printf(_("# Files eval runs per compile: %6u\n"), g_cFileForEvalExecs / g_cFileForEvalCompilations);
1120#ifdef KMK_CC_WITH_STATS
1121 printf(_("# Single alloc block eval progs: %6u (%u%%)\n"
1122 "# Two alloc block eval progs: %6u (%u%%)\n"
1123 "# Three or more alloc block eval progs: %6u (%u%%)\n"
1124 ),
1125 g_cSingleBlockEvalProgs, (uint32_t)((uint64_t)g_cSingleBlockEvalProgs * 100 / cEvalCompilations),
1126 g_cTwoBlockEvalProgs, (uint32_t)((uint64_t)g_cTwoBlockEvalProgs * 100 / cEvalCompilations),
1127 g_cMultiBlockEvalProgs, (uint32_t)((uint64_t)g_cMultiBlockEvalProgs * 100 / cEvalCompilations));
1128 printf(_("# Total amount of memory for eval progs: %8u bytes\n"
1129 "# in: %6u blocks\n"
1130 "# avg block size: %6u bytes\n"
1131 "# unused memory: %8u bytes (%u%%)\n"
1132 "# avg unused memory per block: %6u bytes\n"
1133 "\n"),
1134 g_cbAllocatedEvalProgs, g_cBlocksAllocatedEvalProgs, g_cbAllocatedEvalProgs / g_cBlocksAllocatedEvalProgs,
1135 g_cbUnusedMemEvalProgs, (uint32_t)((uint64_t)g_cbUnusedMemEvalProgs * 100 / g_cbAllocatedEvalProgs),
1136 g_cbUnusedMemEvalProgs / g_cBlocksAllocatedEvalProgs);
1137 puts("");
1138 printf(_("# Total amount of block mem allocated: %8u bytes\n"), g_cbAllocated);
1139 printf(_("# Total number of block allocated: %8u\n"), g_cBlockAllocated);
1140 printf(_("# Average block size: %8u byte\n"), g_cbAllocated / g_cBlockAllocated);
1141#endif
1142
1143 puts("");
1144}
1145
1146
1147/*
1148 *
1149 * Various utility functions.
1150 * Various utility functions.
1151 * Various utility functions.
1152 *
1153 */
1154
1155/**
1156 * Counts the number of dollar chars in the string.
1157 *
1158 * @returns Number of dollar chars.
1159 * @param pchStr The string to search (does not need to be zero
1160 * terminated).
1161 * @param cchStr The length of the string.
1162 */
1163static uint32_t kmk_cc_count_dollars(const char *pchStr, uint32_t cchStr)
1164{
1165 uint32_t cDollars = 0;
1166 const char *pch;
1167 while ((pch = memchr(pchStr, '$', cchStr)) != NULL)
1168 {
1169 cDollars++;
1170 cchStr -= pch - pchStr + 1;
1171 pchStr = pch + 1;
1172 }
1173 return cDollars;
1174}
1175
1176#ifdef KMK_CC_STRICT
1177/**
1178 * Used to check that function arguments are left alone.
1179 * @returns Updated hash.
1180 * @param uHash The current hash value.
1181 * @param psz The string to hash.
1182 */
1183static uint32_t kmk_cc_debug_string_hash(uint32_t uHash, const char *psz)
1184{
1185 unsigned char ch;
1186 while ((ch = *(unsigned char const *)psz++) != '\0')
1187 uHash = (uHash << 6) + (uHash << 16) - uHash + (unsigned char)ch;
1188 return uHash;
1189}
1190
1191/**
1192 * Used to check that function arguments are left alone.
1193 * @returns Updated hash.
1194 * @param uHash The current hash value.
1195 * @param pch The string to hash, not terminated.
1196 * @param cch The number of chars to hash.
1197 */
1198static uint32_t kmk_cc_debug_string_hash_n(uint32_t uHash, const char *pch, uint32_t cch)
1199{
1200 while (cch-- > 0)
1201 {
1202 unsigned char ch = *(unsigned char const *)pch++;
1203 uHash = (uHash << 6) + (uHash << 16) - uHash + (unsigned char)ch;
1204 }
1205 return uHash;
1206}
1207
1208#endif
1209
1210
1211
1212/*
1213 *
1214 * The allocator.
1215 * The allocator.
1216 * The allocator.
1217 *
1218 */
1219
1220
1221/**
1222 * For the first allocation using the block allocator.
1223 *
1224 * @returns Pointer to the first allocation (@a cbFirst in size).
1225 * @param ppBlockTail Where to return the pointer to the first block.
1226 * @param cbFirst The size of the first allocation.
1227 * @param cbHint Hint about how much memory we might be needing.
1228 */
1229static void *kmk_cc_block_alloc_first(PKMKCCBLOCK *ppBlockTail, size_t cbFirst, size_t cbHint)
1230{
1231 uint32_t cbBlock;
1232 PKMKCCBLOCK pNewBlock;
1233
1234 KMK_CC_ASSERT_ALIGNED(cbFirst, sizeof(void *));
1235 KMK_CC_ASSERT(cbFirst <= 128);
1236
1237 /*
1238 * Turn the hint into a block size.
1239 */
1240 cbHint += cbFirst;
1241 if (cbHint <= 512)
1242 {
1243 if (cbHint <= 256)
1244 {
1245 if (cbFirst <= 64)
1246 cbBlock = 128;
1247 else
1248 cbBlock = 256;
1249 }
1250 else
1251 cbBlock = 256;
1252 }
1253 else if (cbHint < 2048)
1254 cbBlock = 1024;
1255 else if (cbHint < 3072)
1256 cbBlock = 2048;
1257 else
1258 cbBlock = 4096;
1259
1260 /*
1261 * Allocate and initialize the first block.
1262 */
1263 pNewBlock = (PKMKCCBLOCK)xmalloc(cbBlock);
1264 pNewBlock->cbBlock = cbBlock;
1265 pNewBlock->offNext = sizeof(*pNewBlock) + cbFirst;
1266 pNewBlock->pNext = NULL;
1267 *ppBlockTail = pNewBlock;
1268
1269#ifdef KMK_CC_WITH_STATS
1270 g_cBlockAllocated++;
1271 g_cbAllocated += cbBlock;
1272#endif
1273
1274 return pNewBlock + 1;
1275}
1276
1277
1278/**
1279 * Used for getting the address of the next instruction.
1280 *
1281 * @returns Pointer to the next allocation.
1282 * @param pBlockTail The allocator tail pointer.
1283 */
1284static void *kmk_cc_block_get_next_ptr(PKMKCCBLOCK pBlockTail)
1285{
1286 return (char *)pBlockTail + pBlockTail->offNext;
1287}
1288
1289
1290/**
1291 * Realigns the allocator after doing byte or string allocations.
1292 *
1293 * @param ppBlockTail Pointer to the allocator tail pointer.
1294 */
1295static void kmk_cc_block_realign(PKMKCCBLOCK *ppBlockTail)
1296{
1297 PKMKCCBLOCK pBlockTail = *ppBlockTail;
1298 if (pBlockTail->offNext & (sizeof(void *) - 1U))
1299 {
1300 pBlockTail->offNext = KMK_CC_BLOCK_ALIGN_SIZE(pBlockTail->offNext);
1301 KMK_CC_ASSERT(pBlockTail->cbBlock - pBlockTail->offNext >= sizeof(KMKCCEXPJUMP));
1302 }
1303}
1304
1305
1306/**
1307 * Grows the allocation with another block, byte allocator case.
1308 *
1309 * @returns Pointer to the byte allocation.
1310 * @param ppBlockTail Pointer to the allocator tail pointer.
1311 * @param cb The number of bytes to allocate.
1312 */
1313static void *kmk_cc_block_byte_alloc_grow(PKMKCCBLOCK *ppBlockTail, uint32_t cb)
1314{
1315 PKMKCCBLOCK pOldBlock = *ppBlockTail;
1316 PKMKCCBLOCK pPrevBlock = pOldBlock->pNext;
1317 PKMKCCBLOCK pNewBlock;
1318 uint32_t cbBlock;
1319
1320 /*
1321 * Check if there accidentally is some space left in the previous block first.
1322 */
1323 if ( pPrevBlock
1324 && pPrevBlock->cbBlock - pPrevBlock->offNext >= cb)
1325 {
1326 void *pvRet = (char *)pPrevBlock + pPrevBlock->offNext;
1327 pPrevBlock->offNext += cb;
1328 return pvRet;
1329 }
1330
1331 /*
1332 * Allocate a new block.
1333 */
1334
1335 /* Figure the block size. */
1336 cbBlock = pOldBlock->cbBlock;
1337 while (cbBlock - sizeof(KMKCCEXPJUMP) - sizeof(*pNewBlock) < cb)
1338 cbBlock *= 2;
1339
1340 /* Allocate and initialize the block it with the new instruction already accounted for. */
1341 pNewBlock = (PKMKCCBLOCK)xmalloc(cbBlock);
1342 pNewBlock->cbBlock = cbBlock;
1343 pNewBlock->offNext = sizeof(*pNewBlock) + cb;
1344 pNewBlock->pNext = pOldBlock;
1345 *ppBlockTail = pNewBlock;
1346
1347#ifdef KMK_CC_WITH_STATS
1348 g_cBlockAllocated++;
1349 g_cbAllocated += cbBlock;
1350#endif
1351
1352 return pNewBlock + 1;
1353}
1354
1355
1356/**
1357 * Make a byte allocation.
1358 *
1359 * Must call kmk_cc_block_realign() when done doing byte and string allocations.
1360 *
1361 * @returns Pointer to the byte allocation (byte aligned).
1362 * @param ppBlockTail Pointer to the allocator tail pointer.
1363 * @param cb The number of bytes to allocate.
1364 */
1365static void *kmk_cc_block_byte_alloc(PKMKCCBLOCK *ppBlockTail, uint32_t cb)
1366{
1367 PKMKCCBLOCK pBlockTail = *ppBlockTail;
1368 uint32_t cbLeft = pBlockTail->cbBlock - pBlockTail->offNext;
1369
1370 KMK_CC_ASSERT(cbLeft >= sizeof(KMKCCEXPJUMP));
1371 if (cbLeft >= cb + sizeof(KMKCCEXPJUMP))
1372 {
1373 void *pvRet = (char *)pBlockTail + pBlockTail->offNext;
1374 pBlockTail->offNext += cb;
1375 return pvRet;
1376 }
1377 return kmk_cc_block_byte_alloc_grow(ppBlockTail, cb);
1378}
1379
1380
1381/**
1382 * Duplicates the given string in a byte allocation.
1383 *
1384 * Must call kmk_cc_block_realign() when done doing byte and string allocations.
1385 *
1386 * @returns Pointer to the byte allocation (byte aligned).
1387 * @param ppBlockTail Pointer to the allocator tail pointer.
1388 * @param cb The number of bytes to allocate.
1389 */
1390static const char *kmk_cc_block_strdup(PKMKCCBLOCK *ppBlockTail, const char *pachStr, uint32_t cchStr)
1391{
1392 char *pszCopy;
1393 if (cchStr)
1394 {
1395 pszCopy = kmk_cc_block_byte_alloc(ppBlockTail, cchStr + 1);
1396 memcpy(pszCopy, pachStr, cchStr);
1397 pszCopy[cchStr] = '\0';
1398 return pszCopy;
1399 }
1400 return "";
1401}
1402
1403
1404/**
1405 * Grows the allocation with another block, string expansion program case.
1406 *
1407 * @returns Pointer to a string expansion instruction core.
1408 * @param ppBlockTail Pointer to the allocator tail pointer.
1409 * @param cb The number of bytes to allocate.
1410 */
1411static PKMKCCEXPCORE kmk_cc_block_alloc_exp_grow(PKMKCCBLOCK *ppBlockTail, uint32_t cb)
1412{
1413 PKMKCCBLOCK pOldBlock = *ppBlockTail;
1414 PKMKCCBLOCK pNewBlock;
1415 PKMKCCEXPCORE pRet;
1416 PKMKCCEXPJUMP pJump;
1417
1418 /* Figure the block size. */
1419 uint32_t cbBlock = !pOldBlock->pNext ? 128 : pOldBlock->cbBlock;
1420 while (cbBlock - sizeof(KMKCCEXPJUMP) - sizeof(*pNewBlock) < cb)
1421 cbBlock *= 2;
1422
1423 /* Allocate and initialize the block it with the new instruction already accounted for. */
1424 pNewBlock = (PKMKCCBLOCK)xmalloc(cbBlock);
1425 pNewBlock->cbBlock = cbBlock;
1426 pNewBlock->offNext = sizeof(*pNewBlock) + cb;
1427 pNewBlock->pNext = pOldBlock;
1428 *ppBlockTail = pNewBlock;
1429
1430#ifdef KMK_CC_WITH_STATS
1431 g_cBlockAllocated++;
1432 g_cbAllocated += cbBlock;
1433#endif
1434
1435 pRet = (PKMKCCEXPCORE)(pNewBlock + 1);
1436 KMK_CC_ASSERT(((size_t)pRet & (sizeof(void *) - 1)) == 0);
1437
1438 /* Emit jump. */
1439 pJump = (PKMKCCEXPJUMP)((char *)pOldBlock + pOldBlock->offNext);
1440 pJump->Core.enmOpCode = kKmkCcExpInstr_Jump;
1441 pJump->pNext = pRet;
1442 pOldBlock->offNext += sizeof(*pJump);
1443 KMK_CC_ASSERT(pOldBlock->offNext <= pOldBlock->cbBlock);
1444
1445 return pRet;
1446}
1447
1448
1449/**
1450 * Allocates a string expansion instruction of size @a cb.
1451 *
1452 * @returns Pointer to a string expansion instruction core.
1453 * @param ppBlockTail Pointer to the allocator tail pointer.
1454 * @param cb The number of bytes to allocate.
1455 */
1456static PKMKCCEXPCORE kmk_cc_block_alloc_exp(PKMKCCBLOCK *ppBlockTail, uint32_t cb)
1457{
1458 PKMKCCBLOCK pBlockTail = *ppBlockTail;
1459 uint32_t cbLeft = pBlockTail->cbBlock - pBlockTail->offNext;
1460
1461 KMK_CC_ASSERT(cbLeft >= sizeof(KMKCCEXPJUMP));
1462 KMK_CC_ASSERT( (cb & (sizeof(void *) - 1)) == 0 || cb == sizeof(KMKCCEXPCORE) /* final */ );
1463
1464 if (cbLeft >= cb + sizeof(KMKCCEXPJUMP))
1465 {
1466 PKMKCCEXPCORE pRet = (PKMKCCEXPCORE)((char *)pBlockTail + pBlockTail->offNext);
1467 pBlockTail->offNext += cb;
1468 KMK_CC_ASSERT(((size_t)pRet & (sizeof(void *) - 1)) == 0);
1469 return pRet;
1470 }
1471 return kmk_cc_block_alloc_exp_grow(ppBlockTail, cb);
1472}
1473
1474
1475/**
1476 * Grows the allocation with another block, makefile evaluation program case.
1477 *
1478 * @returns Pointer to a makefile evaluation instruction core.
1479 * @param ppBlockTail Pointer to the allocator tail pointer.
1480 * @param cb The number of bytes to allocate.
1481 */
1482static PKMKCCEVALCORE kmk_cc_block_alloc_eval_grow(PKMKCCBLOCK *ppBlockTail, uint32_t cb)
1483{
1484 PKMKCCBLOCK pOldBlock = *ppBlockTail;
1485 PKMKCCBLOCK pNewBlock;
1486 PKMKCCEVALCORE pRet;
1487 PKMKCCEVALJUMP pJump;
1488
1489 /* Figure the block size. */
1490 uint32_t cbBlock = !pOldBlock->pNext ? 128 : pOldBlock->cbBlock;
1491 while (cbBlock - sizeof(KMKCCEVALJUMP) - sizeof(*pNewBlock) < cb)
1492 cbBlock *= 2;
1493
1494 /* Allocate and initialize the block it with the new instruction already accounted for. */
1495 pNewBlock = (PKMKCCBLOCK)xmalloc(cbBlock);
1496 pNewBlock->cbBlock = cbBlock;
1497 pNewBlock->offNext = sizeof(*pNewBlock) + cb;
1498 pNewBlock->pNext = pOldBlock;
1499 *ppBlockTail = pNewBlock;
1500
1501#ifdef KMK_CC_WITH_STATS
1502 g_cBlockAllocated++;
1503 g_cbAllocated += cbBlock;
1504#endif
1505
1506 pRet = (PKMKCCEVALCORE)(pNewBlock + 1);
1507
1508 /* Emit jump. */
1509 pJump = (PKMKCCEVALJUMP)((char *)pOldBlock + pOldBlock->offNext);
1510 pJump->Core.enmOpCode = kKmkCcEvalInstr_jump;
1511 pJump->pNext = pRet;
1512 pOldBlock->offNext += sizeof(*pJump);
1513 KMK_CC_ASSERT(pOldBlock->offNext <= pOldBlock->cbBlock);
1514
1515 return pRet;
1516}
1517
1518
1519/**
1520 * Allocates a makefile evaluation instruction of size @a cb.
1521 *
1522 * @returns Pointer to a makefile evaluation instruction core.
1523 * @param ppBlockTail Pointer to the allocator tail pointer.
1524 * @param cb The number of bytes to allocate.
1525 */
1526static PKMKCCEVALCORE kmk_cc_block_alloc_eval(PKMKCCBLOCK *ppBlockTail, uint32_t cb)
1527{
1528 PKMKCCBLOCK pBlockTail = *ppBlockTail;
1529 uint32_t cbLeft = pBlockTail->cbBlock - pBlockTail->offNext;
1530
1531 KMK_CC_ASSERT(cbLeft >= sizeof(KMKCCEVALJUMP));
1532 KMK_CC_ASSERT( (cb & (sizeof(void *) - 1)) == 0 );
1533
1534 if (cbLeft >= cb + sizeof(KMKCCEVALJUMP))
1535 {
1536 PKMKCCEVALCORE pRet = (PKMKCCEVALCORE)((char *)pBlockTail + pBlockTail->offNext);
1537 pBlockTail->offNext += cb;
1538 return pRet;
1539 }
1540 return kmk_cc_block_alloc_eval_grow(ppBlockTail, cb);
1541}
1542
1543
1544/**
1545 * Frees all memory used by an allocator.
1546 *
1547 * @param ppBlockTail The allocator tail pointer.
1548 */
1549static void kmk_cc_block_free_list(PKMKCCBLOCK pBlockTail)
1550{
1551 while (pBlockTail)
1552 {
1553 PKMKCCBLOCK pThis = pBlockTail;
1554 pBlockTail = pBlockTail->pNext;
1555 free(pThis);
1556 }
1557}
1558
1559
1560/*
1561 *
1562 * The string expansion compiler.
1563 * The string expansion compiler.
1564 * The string expansion compiler.
1565 *
1566 */
1567
1568
1569/**
1570 * Emits a kKmkCcExpInstr_Return.
1571 *
1572 * @param ppBlockTail Pointer to the allocator tail pointer.
1573 */
1574static void kmk_cc_exp_emit_return(PKMKCCBLOCK *ppBlockTail)
1575{
1576 PKMKCCEXPCORE pCore = kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pCore));
1577 pCore->enmOpCode = kKmkCcExpInstr_Return;
1578 kmk_cc_block_realign(ppBlockTail);
1579}
1580
1581
1582/**
1583 * Checks if a function is known to mess up the arguments its given.
1584 *
1585 * When executing calls to "dirty" functions, all arguments must be duplicated
1586 * on the heap.
1587 *
1588 * @returns 1 if dirty, 0 if clean.
1589 * @param pszFunction The function name.
1590 */
1591static uint8_t kmk_cc_is_dirty_function(const char *pszFunction)
1592{
1593 switch (pszFunction[0])
1594 {
1595 default:
1596 return 0;
1597
1598 case 'e':
1599 if (!strcmp(pszFunction, "eval"))
1600 return 1;
1601 if (!strcmp(pszFunction, "evalctx"))
1602 return 1;
1603 return 0;
1604
1605 case 'f':
1606 if (!strcmp(pszFunction, "filter"))
1607 return 1;
1608 if (!strcmp(pszFunction, "filter-out"))
1609 return 1;
1610 if (!strcmp(pszFunction, "for"))
1611 return 1;
1612 return 0;
1613
1614 case 's':
1615 if (!strcmp(pszFunction, "sort"))
1616 return 1;
1617 return 0;
1618 }
1619}
1620
1621
1622/**
1623 * Emits a function call instruction taking arguments that needs expanding.
1624 *
1625 * @returns 0 on success, non-zero on failure.
1626 * @param ppBlockTail Pointer to the allocator tail pointer.
1627 * @param pszFunction The function name (const string from function.c).
1628 * @param pchArgs Pointer to the arguments expression string, leading
1629 * any blanks has been stripped.
1630 * @param cchArgs The length of the arguments expression string.
1631 * @param cArgs Number of arguments found.
1632 * @param chOpen The char used to open the function call.
1633 * @param chClose The char used to close the function call.
1634 * @param pfnFunction The function implementation.
1635 * @param cMaxArgs Maximum number of arguments the function takes.
1636 */
1637static int kmk_cc_exp_emit_dyn_function(PKMKCCBLOCK *ppBlockTail, const char *pszFunction,
1638 const char *pchArgs, uint32_t cchArgs, uint32_t cArgs, char chOpen, char chClose,
1639 make_function_ptr_t pfnFunction, unsigned char cMaxArgs)
1640{
1641 uint32_t iArg;
1642
1643 /*
1644 * The function instruction has variable size. The maximum argument count
1645 * isn't quite like the minium one. Zero means no limit. While a non-zero
1646 * value means that any commas beyond the max will be taken to be part of
1647 * the final argument.
1648 */
1649 uint32_t cActualArgs = cArgs <= cMaxArgs || !cMaxArgs ? cArgs : cMaxArgs;
1650 PKMKCCEXPDYNFUNC pInstr = (PKMKCCEXPDYNFUNC)kmk_cc_block_alloc_exp(ppBlockTail, KMKCCEXPDYNFUNC_SIZE(cActualArgs));
1651 pInstr->FnCore.Core.enmOpCode = kKmkCcExpInstr_DynamicFunction;
1652 pInstr->FnCore.cArgs = cActualArgs;
1653 pInstr->FnCore.pfnFunction = pfnFunction;
1654 pInstr->FnCore.pszFuncName = pszFunction;
1655 pInstr->FnCore.fDirty = kmk_cc_is_dirty_function(pszFunction);
1656
1657 /*
1658 * Parse the arguments. Plain arguments gets duplicated in the program
1659 * memory so that they are terminated and no extra processing is necessary
1660 * later on. ASSUMES that the function implementations do NOT change
1661 * argument memory. Other arguments the compiled into their own expansion
1662 * sub programs.
1663 */
1664 iArg = 0;
1665 for (;;)
1666 {
1667 /* Find the end of the argument. Check for $. */
1668 char ch = '\0';
1669 uint8_t fDollar = 0;
1670 int32_t cDepth = 0;
1671 uint32_t cchThisArg = 0;
1672 while (cchThisArg < cchArgs)
1673 {
1674 ch = pchArgs[cchThisArg];
1675 if (ch == chClose)
1676 {
1677 KMK_CC_ASSERT(cDepth > 0);
1678 if (cDepth > 0)
1679 cDepth--;
1680 }
1681 else if (ch == chOpen)
1682 cDepth++;
1683 else if (ch == ',' && cDepth == 0 && iArg + 1 < cActualArgs)
1684 break;
1685 else if (ch == '$')
1686 fDollar = 1;
1687 cchThisArg++;
1688 }
1689
1690 pInstr->aArgs[iArg].fSubprog = fDollar;
1691 if (fDollar)
1692 {
1693 /* Compile it. */
1694 int rc;
1695 kmk_cc_block_realign(ppBlockTail);
1696 rc = kmk_cc_exp_compile_subprog(ppBlockTail, pchArgs, cchThisArg, &pInstr->aArgs[iArg].u.Subprog);
1697 if (rc != 0)
1698 return rc;
1699 }
1700 else
1701 {
1702 /* Duplicate it. */
1703 pInstr->aArgs[iArg].u.Plain.psz = kmk_cc_block_strdup(ppBlockTail, pchArgs, cchThisArg);
1704 pInstr->aArgs[iArg].u.Plain.cch = cchThisArg;
1705 }
1706 iArg++;
1707 if (ch != ',')
1708 break;
1709 pchArgs += cchThisArg + 1;
1710 cchArgs -= cchThisArg + 1;
1711 }
1712 KMK_CC_ASSERT(iArg == cActualArgs);
1713
1714 /*
1715 * Realign the allocator and take down the address of the next instruction.
1716 */
1717 kmk_cc_block_realign(ppBlockTail);
1718 pInstr->FnCore.pNext = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail);
1719 return 0;
1720}
1721
1722
1723/**
1724 * Emits a function call instruction taking plain arguments.
1725 *
1726 * @returns 0 on success, non-zero on failure.
1727 * @param ppBlockTail Pointer to the allocator tail pointer.
1728 * @param pszFunction The function name (const string from function.c).
1729 * @param pchArgs Pointer to the arguments string, leading any blanks
1730 * has been stripped.
1731 * @param cchArgs The length of the arguments string.
1732 * @param cArgs Number of arguments found.
1733 * @param chOpen The char used to open the function call.
1734 * @param chClose The char used to close the function call.
1735 * @param pfnFunction The function implementation.
1736 * @param cMaxArgs Maximum number of arguments the function takes.
1737 */
1738static void kmk_cc_exp_emit_plain_function(PKMKCCBLOCK *ppBlockTail, const char *pszFunction,
1739 const char *pchArgs, uint32_t cchArgs, uint32_t cArgs, char chOpen, char chClose,
1740 make_function_ptr_t pfnFunction, unsigned char cMaxArgs)
1741{
1742 uint32_t iArg;
1743
1744 /*
1745 * The function instruction has variable size. The maximum argument count
1746 * isn't quite like the minium one. Zero means no limit. While a non-zero
1747 * value means that any commas beyond the max will be taken to be part of
1748 * the final argument.
1749 */
1750 uint32_t cActualArgs = cArgs <= cMaxArgs || !cMaxArgs ? cArgs : cMaxArgs;
1751 PKMKCCEXPPLAINFUNC pInstr = (PKMKCCEXPPLAINFUNC)kmk_cc_block_alloc_exp(ppBlockTail, KMKCCEXPPLAINFUNC_SIZE(cActualArgs));
1752 pInstr->FnCore.Core.enmOpCode = kKmkCcExpInstr_PlainFunction;
1753 pInstr->FnCore.cArgs = cActualArgs;
1754 pInstr->FnCore.pfnFunction = pfnFunction;
1755 pInstr->FnCore.pszFuncName = pszFunction;
1756 pInstr->FnCore.fDirty = kmk_cc_is_dirty_function(pszFunction);
1757
1758 /*
1759 * Parse the arguments. Plain arguments gets duplicated in the program
1760 * memory so that they are terminated and no extra processing is necessary
1761 * later on. ASSUMES that the function implementations do NOT change
1762 * argument memory.
1763 */
1764 iArg = 0;
1765 for (;;)
1766 {
1767 /* Find the end of the argument. */
1768 char ch = '\0';
1769 int32_t cDepth = 0;
1770 uint32_t cchThisArg = 0;
1771 while (cchThisArg < cchArgs)
1772 {
1773 ch = pchArgs[cchThisArg];
1774 if (ch == chClose)
1775 {
1776 KMK_CC_ASSERT(cDepth > 0);
1777 if (cDepth > 0)
1778 cDepth--;
1779 }
1780 else if (ch == chOpen)
1781 cDepth++;
1782 else if (ch == ',' && cDepth == 0 && iArg + 1 < cActualArgs)
1783 break;
1784 cchThisArg++;
1785 }
1786
1787 /* Duplicate it. */
1788 pInstr->apszArgs[iArg++] = kmk_cc_block_strdup(ppBlockTail, pchArgs, cchThisArg);
1789 if (ch != ',')
1790 break;
1791 pchArgs += cchThisArg + 1;
1792 cchArgs -= cchThisArg + 1;
1793 }
1794
1795 KMK_CC_ASSERT(iArg == cActualArgs);
1796 pInstr->apszArgs[iArg] = NULL;
1797
1798 /*
1799 * Realign the allocator and take down the address of the next instruction.
1800 */
1801 kmk_cc_block_realign(ppBlockTail);
1802 pInstr->FnCore.pNext = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail);
1803}
1804
1805
1806/**
1807 * Emits a kKmkCcExpInstr_DynamicVariable.
1808 *
1809 * @returns 0 on success, non-zero on failure.
1810 * @param ppBlockTail Pointer to the allocator tail pointer.
1811 * @param pchNameExpr The name of the variable (ASSUMED presistent
1812 * thru-out the program life time).
1813 * @param cchNameExpr The length of the variable name. If zero,
1814 * nothing will be emitted.
1815 */
1816static int kmk_cc_exp_emit_dyn_variable(PKMKCCBLOCK *ppBlockTail, const char *pchNameExpr, uint32_t cchNameExpr)
1817{
1818 PKMKCCEXPDYNVAR pInstr;
1819 int rc;
1820 KMK_CC_ASSERT(cchNameExpr > 0);
1821
1822 pInstr = (PKMKCCEXPDYNVAR)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr));
1823 pInstr->Core.enmOpCode = kKmkCcExpInstr_DynamicVariable;
1824
1825 rc = kmk_cc_exp_compile_subprog(ppBlockTail, pchNameExpr, cchNameExpr, &pInstr->Subprog);
1826
1827 pInstr->pNext = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail);
1828 return rc;
1829}
1830
1831
1832/**
1833 * Emits either a kKmkCcExpInstr_PlainVariable or
1834 * kKmkCcExpInstr_SearchAndReplacePlainVariable instruction.
1835 *
1836 * @param ppBlockTail Pointer to the allocator tail pointer.
1837 * @param pchName The name of the variable. (Does not need to be
1838 * valid beyond the call.)
1839 * @param cchName The length of the variable name. If zero,
1840 * nothing will be emitted.
1841 */
1842static void kmk_cc_exp_emit_plain_variable_maybe_sr(PKMKCCBLOCK *ppBlockTail, const char *pchName, uint32_t cchName)
1843{
1844 if (cchName > 0)
1845 {
1846 /*
1847 * Hopefully, we're not expected to do any search and replace on the
1848 * expanded variable string later... Requires both ':' and '='.
1849 */
1850 const char *pchEqual;
1851 const char *pchColon = (const char *)memchr(pchName, ':', cchName);
1852 if ( pchColon == NULL
1853 || (pchEqual = (const char *)memchr(pchColon + 1, ':', cchName - (pchColon - pchName - 1))) == NULL
1854 || pchEqual == pchEqual + 1)
1855 {
1856 PKMKCCEXPPLAINVAR pInstr = (PKMKCCEXPPLAINVAR)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr));
1857 pInstr->Core.enmOpCode = kKmkCcExpInstr_PlainVariable;
1858 pInstr->pszName = strcache2_add(&variable_strcache, pchName, cchName);
1859 }
1860 else if (pchColon != pchName)
1861 {
1862 /*
1863 * Okay, we need to do search and replace the variable value.
1864 * This is performed by patsubst_expand_pat using '%' patterns.
1865 */
1866 uint32_t cchName2 = (uint32_t)(pchColon - pchName);
1867 uint32_t cchSearch = (uint32_t)(pchEqual - pchColon - 1);
1868 uint32_t cchReplace = cchName - cchName2 - cchSearch - 2;
1869 const char *pchPct;
1870 char *psz;
1871 PKMKCCEXPSRPLAINVAR pInstr;
1872
1873 pInstr = (PKMKCCEXPSRPLAINVAR)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr));
1874 pInstr->Core.enmOpCode = kKmkCcExpInstr_SearchAndReplacePlainVariable;
1875 pInstr->pszName = strcache2_add(&variable_strcache, pchName, cchName2);
1876
1877 /* Figure out the search pattern, unquoting percent chars.. */
1878 psz = (char *)kmk_cc_block_byte_alloc(ppBlockTail, cchSearch + 2);
1879 psz[0] = '%';
1880 memcpy(psz + 1, pchColon + 1, cchSearch);
1881 psz[1 + cchSearch] = '\0';
1882 pchPct = find_percent(psz + 1); /* also performs unquoting */
1883 if (pchPct)
1884 {
1885 pInstr->pszSearchPattern = psz + 1;
1886 pInstr->offPctSearchPattern = (uint32_t)(pchPct - psz - 1);
1887 }
1888 else
1889 {
1890 pInstr->pszSearchPattern = psz;
1891 pInstr->offPctSearchPattern = 0;
1892 }
1893
1894 /* Figure out the replacement pattern, unquoting percent chars.. */
1895 if (cchReplace == 0)
1896 {
1897 pInstr->pszReplacePattern = "%";
1898 pInstr->offPctReplacePattern = 0;
1899 }
1900 else
1901 {
1902 psz = (char *)kmk_cc_block_byte_alloc(ppBlockTail, cchReplace + 2);
1903 psz[0] = '%';
1904 memcpy(psz + 1, pchEqual + 1, cchReplace);
1905 psz[1 + cchReplace] = '\0';
1906 pchPct = find_percent(psz + 1); /* also performs unquoting */
1907 if (pchPct)
1908 {
1909 pInstr->pszReplacePattern = psz + 1;
1910 pInstr->offPctReplacePattern = (uint32_t)(pchPct - psz - 1);
1911 }
1912 else
1913 {
1914 pInstr->pszReplacePattern = psz;
1915 pInstr->offPctReplacePattern = 0;
1916 }
1917 }
1918
1919 /* Note down where the next instruction is after realigning the allocator. */
1920 kmk_cc_block_realign(ppBlockTail);
1921 pInstr->pNext = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail);
1922 }
1923 }
1924}
1925
1926
1927/**
1928 * Emits a kKmkCcExpInstr_CopyString.
1929 *
1930 * @param ppBlockTail Pointer to the allocator tail pointer.
1931 * @param pchStr The string to emit (ASSUMED presistent thru-out
1932 * the program life time).
1933 * @param cchStr The number of chars to copy. If zero, nothing
1934 * will be emitted.
1935 */
1936static void kmk_cc_exp_emit_copy_string(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr)
1937{
1938 if (cchStr > 0)
1939 {
1940 PKMKCCEXPCOPYSTRING pInstr = (PKMKCCEXPCOPYSTRING)kmk_cc_block_alloc_exp(ppBlockTail, sizeof(*pInstr));
1941 pInstr->Core.enmOpCode = kKmkCcExpInstr_CopyString;
1942 pInstr->cchCopy = cchStr;
1943 pInstr->pachSrc = pchStr;
1944 }
1945}
1946
1947
1948/**
1949 * String expansion compilation function common to both normal and sub programs.
1950 *
1951 * @returns 0 on success, non-zero on failure.
1952 * @param ppBlockTail Pointer to the allocator tail pointer.
1953 * @param pchStr The expression to compile.
1954 * @param cchStr The length of the expression to compile.
1955 */
1956static int kmk_cc_exp_compile_common(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr)
1957{
1958 /*
1959 * Process the string.
1960 */
1961 while (cchStr > 0)
1962 {
1963 /* Look for dollar sign, marks variable expansion or dollar-escape. */
1964 int rc;
1965 const char *pchDollar = memchr(pchStr, '$', cchStr);
1966 if (pchDollar)
1967 {
1968 /*
1969 * Check for multiple dollar chars.
1970 */
1971 uint32_t offDollar = (uint32_t)(pchDollar - pchStr);
1972 uint32_t cDollars = 1;
1973 while ( offDollar + cDollars < cchStr
1974 && pchStr[offDollar + cDollars] == '$')
1975 cDollars++;
1976
1977 /*
1978 * Emit a string copy for any preceeding stuff, including half of
1979 * the dollars we found (dollar escape: $$ -> $).
1980 * (kmk_cc_exp_emit_copy_string ignore zero length strings).
1981 */
1982 kmk_cc_exp_emit_copy_string(ppBlockTail, pchStr, offDollar + cDollars / 2);
1983 pchStr += offDollar + cDollars;
1984 cchStr -= offDollar + cDollars;
1985
1986 /*
1987 * Odd number of dollar chars means there is a variable to expand
1988 * or function to call.
1989 */
1990 if (cDollars & 1)
1991 {
1992 if (cchStr > 0)
1993 {
1994 char const chOpen = *pchStr;
1995 if (chOpen == '(' || chOpen == '{')
1996 {
1997 /* There are several alternative ways of finding the ending
1998 parenthesis / braces.
1999
2000 GNU make does one thing for functions and variable containing
2001 any '$' chars before the first closing char. While for
2002 variables where a closing char comes before any '$' char, a
2003 simplified approach is taken. This means that for example:
2004
2005 Given VAR=var, the expressions "$(var())" and
2006 "$($(VAR)())" would be expanded differently.
2007 In the first case the variable "var(" would be
2008 used and in the second "var()".
2009
2010 This code will not duplicate this weird behavior, but work
2011 the same regardless of whether there is a '$' char before
2012 the first closing char. */
2013 make_function_ptr_t pfnFunction;
2014 const char *pszFunction;
2015 unsigned char cMaxArgs;
2016 unsigned char cMinArgs;
2017 char fExpandArgs;
2018 char const chClose = chOpen == '(' ? ')' : '}';
2019 char ch = 0;
2020 uint32_t cchName = 0;
2021 uint32_t cDepth = 1;
2022 uint32_t cMaxDepth = 1;
2023 cDollars = 0;
2024
2025 pchStr++;
2026 cchStr--;
2027
2028 /* First loop: Identify potential function calls and dynamic expansion. */
2029 KMK_CC_ASSERT(!func_char_map[(unsigned char)chOpen]);
2030 KMK_CC_ASSERT(!func_char_map[(unsigned char)chClose]);
2031 KMK_CC_ASSERT(!func_char_map[(unsigned char)'$']);
2032 while (cchName < cchStr)
2033 {
2034 ch = pchStr[cchName];
2035 if (!func_char_map[(unsigned char)ch])
2036 break;
2037 cchName++;
2038 }
2039
2040 if ( cchName >= MIN_FUNCTION_LENGTH
2041 && cchName <= MAX_FUNCTION_LENGTH
2042 && (isblank(ch) || ch == chClose || cchName == cchStr)
2043 && (pfnFunction = lookup_function_for_compiler(pchStr, cchName, &cMinArgs, &cMaxArgs,
2044 &fExpandArgs, &pszFunction)) != NULL)
2045 {
2046 /*
2047 * It's a function invocation, we should count parameters while
2048 * looking for the end.
2049 * Note! We use cchName for the length of the argument list.
2050 */
2051 uint32_t cArgs = 1;
2052 if (ch != chClose)
2053 {
2054 /* Skip leading spaces before the first arg. */
2055 cchName++;
2056 while (cchName < cchStr && isblank((unsigned char)pchStr[cchName]))
2057 cchName++;
2058
2059 pchStr += cchName;
2060 cchStr -= cchName;
2061 cchName = 0;
2062
2063 while (cchName < cchStr)
2064 {
2065 ch = pchStr[cchName];
2066 if (ch == ',')
2067 {
2068 if (cDepth == 1)
2069 cArgs++;
2070 }
2071 else if (ch == chClose)
2072 {
2073 if (!--cDepth)
2074 break;
2075 }
2076 else if (ch == chOpen)
2077 {
2078 if (++cDepth > cMaxDepth)
2079 cMaxDepth = cDepth;
2080 }
2081 else if (ch == '$')
2082 cDollars++;
2083 cchName++;
2084 }
2085 }
2086 else
2087 {
2088 pchStr += cchName;
2089 cchStr -= cchName;
2090 cchName = 0;
2091 }
2092 if (cArgs < cMinArgs)
2093 {
2094 fatal(NULL, _("Function '%s' takes a minimum of %d arguments: %d given"),
2095 pszFunction, (int)cMinArgs, (int)cArgs);
2096 return -1; /* not reached */
2097 }
2098 if (cDepth != 0)
2099 {
2100 fatal(NULL, chOpen == '('
2101 ? _("Missing closing parenthesis calling '%s'") : _("Missing closing braces calling '%s'"),
2102 pszFunction);
2103 return -1; /* not reached */
2104 }
2105 if (cMaxDepth > 16 && fExpandArgs)
2106 {
2107 fatal(NULL, _("Too many levels of nested function arguments expansions: %s"), pszFunction);
2108 return -1; /* not reached */
2109 }
2110 if (!fExpandArgs || cDollars == 0)
2111 kmk_cc_exp_emit_plain_function(ppBlockTail, pszFunction, pchStr, cchName,
2112 cArgs, chOpen, chClose, pfnFunction, cMaxArgs);
2113 else
2114 {
2115 rc = kmk_cc_exp_emit_dyn_function(ppBlockTail, pszFunction, pchStr, cchName,
2116 cArgs, chOpen, chClose, pfnFunction, cMaxArgs);
2117 if (rc != 0)
2118 return rc;
2119 }
2120 }
2121 else
2122 {
2123 /*
2124 * Variable, find the end while checking whether anything needs expanding.
2125 */
2126 if (ch == chClose)
2127 cDepth = 0;
2128 else if (cchName < cchStr)
2129 {
2130 if (ch != '$')
2131 {
2132 /* Second loop: Look for things that needs expanding. */
2133 while (cchName < cchStr)
2134 {
2135 ch = pchStr[cchName];
2136 if (ch == chClose)
2137 {
2138 if (!--cDepth)
2139 break;
2140 }
2141 else if (ch == chOpen)
2142 {
2143 if (++cDepth > cMaxDepth)
2144 cMaxDepth = cDepth;
2145 }
2146 else if (ch == '$')
2147 break;
2148 cchName++;
2149 }
2150 }
2151 if (ch == '$')
2152 {
2153 /* Third loop: Something needs expanding, just find the end. */
2154 cDollars = 1;
2155 cchName++;
2156 while (cchName < cchStr)
2157 {
2158 ch = pchStr[cchName];
2159 if (ch == chClose)
2160 {
2161 if (!--cDepth)
2162 break;
2163 }
2164 else if (ch == chOpen)
2165 {
2166 if (++cDepth > cMaxDepth)
2167 cMaxDepth = cDepth;
2168 }
2169 cchName++;
2170 }
2171 }
2172 }
2173 if (cDepth > 0) /* After warning, we just assume they're all there. */
2174 error(NULL, chOpen == '(' ? _("Missing closing parenthesis ") : _("Missing closing braces"));
2175 if (cMaxDepth >= 16)
2176 {
2177 fatal(NULL, _("Too many levels of nested variable expansions: '%.*s'"), (int)cchName + 2, pchStr - 1);
2178 return -1; /* not reached */
2179 }
2180 if (cDollars == 0)
2181 kmk_cc_exp_emit_plain_variable_maybe_sr(ppBlockTail, pchStr, cchName);
2182 else
2183 {
2184 rc = kmk_cc_exp_emit_dyn_variable(ppBlockTail, pchStr, cchName);
2185 if (rc != 0)
2186 return rc;
2187 }
2188 }
2189 pchStr += cchName + 1;
2190 cchStr -= cchName + (cDepth == 0);
2191 }
2192 else
2193 {
2194 /* Single character variable name. */
2195 kmk_cc_exp_emit_plain_variable_maybe_sr(ppBlockTail, pchStr, 1);
2196 pchStr++;
2197 cchStr--;
2198 }
2199 }
2200 else
2201 {
2202 error(NULL, _("Unexpected end of string after $"));
2203 break;
2204 }
2205 }
2206 }
2207 else
2208 {
2209 /*
2210 * Nothing more to expand, the remainder is a simple string copy.
2211 */
2212 kmk_cc_exp_emit_copy_string(ppBlockTail, pchStr, cchStr);
2213 break;
2214 }
2215 }
2216
2217 /*
2218 * Emit final instruction.
2219 */
2220 kmk_cc_exp_emit_return(ppBlockTail);
2221 return 0;
2222}
2223
2224
2225/**
2226 * Initializes string expansion program statistics.
2227 * @param pStats Pointer to the statistics structure to init.
2228 */
2229static void kmk_cc_exp_stats_init(PKMKCCEXPSTATS pStats)
2230{
2231 pStats->cchAvg = 0;
2232}
2233
2234
2235/**
2236 * Compiles a string expansion subprogram.
2237 *
2238 * The caller typically make a call to kmk_cc_block_get_next_ptr after this
2239 * function returns to figure out where to continue executing.
2240 *
2241 * @returns 0 on success, non-zero on failure.
2242 * @param ppBlockTail Pointer to the allocator tail pointer.
2243 * @param pchStr Pointer to the string to compile an expansion
2244 * program for (ASSUMED to be valid for the
2245 * lifetime of the program).
2246 * @param cchStr The length of the string to compile. Expected to
2247 * be at least on char long.
2248 * @param pSubprog The subprogram structure to initialize.
2249 */
2250static int kmk_cc_exp_compile_subprog(PKMKCCBLOCK *ppBlockTail, const char *pchStr, uint32_t cchStr, PKMKCCEXPSUBPROG pSubprog)
2251{
2252 KMK_CC_ASSERT(cchStr > 0);
2253 pSubprog->pFirstInstr = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(*ppBlockTail);
2254 kmk_cc_exp_stats_init(&pSubprog->Stats);
2255 return kmk_cc_exp_compile_common(ppBlockTail, pchStr, cchStr);
2256}
2257
2258
2259/**
2260 * Compiles a string expansion program.
2261 *
2262 * @returns Pointer to the program on success, NULL on failure.
2263 * @param pchStr Pointer to the string to compile an expansion
2264 * program for (ASSUMED to be valid for the
2265 * lifetime of the program).
2266 * @param cchStr The length of the string to compile. Expected to
2267 * be at least on char long.
2268 */
2269static PKMKCCEXPPROG kmk_cc_exp_compile(const char *pchStr, uint32_t cchStr)
2270{
2271 /*
2272 * Estimate block size, allocate one and initialize it.
2273 */
2274 PKMKCCEXPPROG pProg;
2275 PKMKCCBLOCK pBlock;
2276 pProg = kmk_cc_block_alloc_first(&pBlock, sizeof(*pProg),
2277 (kmk_cc_count_dollars(pchStr, cchStr) + 4) * 8);
2278 if (pProg)
2279 {
2280 pProg->pBlockTail = pBlock;
2281 pProg->pFirstInstr = (PKMKCCEXPCORE)kmk_cc_block_get_next_ptr(pBlock);
2282 kmk_cc_exp_stats_init(&pProg->Stats);
2283 pProg->cRefs = 1;
2284#ifdef KMK_CC_STRICT
2285 pProg->uInputHash = kmk_cc_debug_string_hash_n(0, pchStr, cchStr);
2286#endif
2287
2288 /*
2289 * Join forces with the subprogram compilation code.
2290 */
2291 if (kmk_cc_exp_compile_common(&pProg->pBlockTail, pchStr, cchStr) == 0)
2292 {
2293#ifdef KMK_CC_WITH_STATS
2294 pBlock = pProg->pBlockTail;
2295 if (!pBlock->pNext)
2296 g_cSingleBlockExpProgs++;
2297 else if (!pBlock->pNext->pNext)
2298 g_cTwoBlockExpProgs++;
2299 else
2300 g_cMultiBlockExpProgs++;
2301 for (; pBlock; pBlock = pBlock->pNext)
2302 {
2303 g_cBlocksAllocatedExpProgs++;
2304 g_cbAllocatedExpProgs += pBlock->cbBlock;
2305 g_cbUnusedMemExpProgs += pBlock->cbBlock - pBlock->offNext;
2306 }
2307#endif
2308 return pProg;
2309 }
2310 kmk_cc_block_free_list(pProg->pBlockTail);
2311 }
2312 return NULL;
2313}
2314
2315
2316/**
2317 * Updates the recursive_without_dollar member of a variable structure.
2318 *
2319 * This avoid compiling string expansion programs without only a CopyString
2320 * instruction. By setting recursive_without_dollar to 1, code calling
2321 * kmk_cc_compile_variable_for_expand and kmk_exec_expand_to_var_buf will
2322 * instead treat start treating it as a simple variable, which is faster.
2323 *
2324 * @returns The updated recursive_without_dollar value.
2325 * @param pVar Pointer to the variable.
2326 */
2327static int kmk_cc_update_variable_recursive_without_dollar(struct variable *pVar)
2328{
2329 int fValue;
2330 KMK_CC_ASSERT(pVar->recursive_without_dollar == 0);
2331
2332 if (memchr(pVar->value, '$', pVar->value_length))
2333 fValue = -1;
2334 else
2335 fValue = 1;
2336 pVar->recursive_without_dollar = fValue;
2337
2338 return fValue;
2339}
2340
2341
2342/**
2343 * Compiles a variable for string expansion.
2344 *
2345 * @returns Pointer to the string expansion program on success, NULL if no
2346 * program was created.
2347 * @param pVar Pointer to the variable.
2348 */
2349struct kmk_cc_expandprog *kmk_cc_compile_variable_for_expand(struct variable *pVar)
2350{
2351 KMK_CC_ASSERT(strlen(pVar->value) == pVar->value_length);
2352 KMK_CC_ASSERT(!pVar->expandprog);
2353 KMK_CC_ASSERT(pVar->recursive_without_dollar <= 0);
2354
2355 if ( !pVar->expandprog
2356 && pVar->recursive)
2357 {
2358 if ( pVar->recursive_without_dollar < 0
2359 || ( pVar->recursive_without_dollar == 0
2360 && kmk_cc_update_variable_recursive_without_dollar(pVar) < 0) )
2361 {
2362 pVar->expandprog = kmk_cc_exp_compile(pVar->value, pVar->value_length);
2363 g_cVarForExpandCompilations++;
2364 }
2365 }
2366 return pVar->expandprog;
2367}
2368
2369
2370/**
2371 * String expansion execution worker for outputting a variable.
2372 *
2373 * @returns The new variable buffer position.
2374 * @param pVar The variable to reference.
2375 * @param pchDst The current variable buffer position.
2376 */
2377static char *kmk_exec_expand_worker_reference_variable(struct variable *pVar, char *pchDst)
2378{
2379 if (pVar->value_length > 0)
2380 {
2381 if (!pVar->recursive || IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR(pVar))
2382 pchDst = variable_buffer_output(pchDst, pVar->value, pVar->value_length);
2383 else
2384 pchDst = reference_recursive_variable(pchDst, pVar);
2385 }
2386 else if (pVar->append)
2387 pchDst = reference_recursive_variable(pchDst, pVar);
2388 return pchDst;
2389}
2390
2391
2392/**
2393 * Executes a stream string expansion instructions, outputting to the current
2394 * varaible buffer.
2395 *
2396 * @returns The new variable buffer position.
2397 * @param pInstrCore The instruction to start executing at.
2398 * @param pchDst The current variable buffer position.
2399 */
2400static char *kmk_exec_expand_instruction_stream_to_var_buf(PKMKCCEXPCORE pInstrCore, char *pchDst)
2401{
2402 for (;;)
2403 {
2404 switch (pInstrCore->enmOpCode)
2405 {
2406 case kKmkCcExpInstr_CopyString:
2407 {
2408 PKMKCCEXPCOPYSTRING pInstr = (PKMKCCEXPCOPYSTRING)pInstrCore;
2409 pchDst = variable_buffer_output(pchDst, pInstr->pachSrc, pInstr->cchCopy);
2410
2411 pInstrCore = &(pInstr + 1)->Core;
2412 break;
2413 }
2414
2415 case kKmkCcExpInstr_PlainVariable:
2416 {
2417 PKMKCCEXPPLAINVAR pInstr = (PKMKCCEXPPLAINVAR)pInstrCore;
2418 struct variable *pVar = lookup_variable_strcached(pInstr->pszName);
2419 if (pVar)
2420 pchDst = kmk_exec_expand_worker_reference_variable(pVar, pchDst);
2421 else
2422 warn_undefined(pInstr->pszName, strcache2_get_len(&variable_strcache, pInstr->pszName));
2423
2424 pInstrCore = &(pInstr + 1)->Core;
2425 break;
2426 }
2427
2428 case kKmkCcExpInstr_DynamicVariable:
2429 {
2430 PKMKCCEXPDYNVAR pInstr = (PKMKCCEXPDYNVAR)pInstrCore;
2431 struct variable *pVar;
2432 uint32_t cchName;
2433 char *pszName = kmk_exec_expand_subprog_to_tmp(&pInstr->Subprog, &cchName);
2434 char *pszColon = (char *)memchr(pszName, ':', cchName);
2435 char *pszEqual;
2436 if ( pszColon == NULL
2437 || (pszEqual = (char *)memchr(pszColon + 1, '=', &pszName[cchName] - pszColon - 1)) == NULL
2438 || pszEqual == pszColon + 1)
2439 {
2440 pVar = lookup_variable(pszName, cchName);
2441 if (pVar)
2442 pchDst = kmk_exec_expand_worker_reference_variable(pVar, pchDst);
2443 else
2444 warn_undefined(pszName, cchName);
2445 }
2446 else if (pszColon != pszName)
2447 {
2448 /*
2449 * Oh, we have to do search and replace. How tedious.
2450 * Since the variable name is a temporary buffer, we can transform
2451 * the strings into proper search and replacement patterns directly.
2452 */
2453 pVar = lookup_variable(pszName, pszColon - pszName);
2454 if (pVar)
2455 {
2456 char const *pszExpandedVarValue = pVar->recursive ? recursively_expand(pVar) : pVar->value;
2457 char *pszSearchPat = pszColon + 1;
2458 char *pszReplacePat = pszEqual + 1;
2459 const char *pchPctSearchPat;
2460 const char *pchPctReplacePat;
2461
2462 *pszEqual = '\0';
2463 pchPctSearchPat = find_percent(pszSearchPat);
2464 pchPctReplacePat = find_percent(pszReplacePat);
2465
2466 if (!pchPctReplacePat)
2467 {
2468 if (pszReplacePat[-2] != '\0') /* On the offchance that a pct was unquoted by find_percent. */
2469 {
2470 memmove(pszName + 1, pszSearchPat, pszReplacePat - pszSearchPat);
2471 if (pchPctSearchPat)
2472 pchPctSearchPat -= pszSearchPat - &pszName[1];
2473 pszSearchPat = &pszName[1];
2474 }
2475 pchPctReplacePat = --pszReplacePat;
2476 *pszReplacePat = '%';
2477 }
2478
2479 if (!pchPctSearchPat)
2480 {
2481 pchPctSearchPat = --pszSearchPat;
2482 *pszSearchPat = '%';
2483 }
2484
2485 pchDst = patsubst_expand_pat(pchDst, pszExpandedVarValue,
2486 pszSearchPat, pszReplacePat,
2487 pchPctSearchPat, pchPctReplacePat);
2488
2489 if (pVar->recursive)
2490 free((void *)pszExpandedVarValue);
2491 }
2492 else
2493 warn_undefined(pszName, pszColon - pszName);
2494 }
2495 free(pszName);
2496
2497 pInstrCore = pInstr->pNext;
2498 break;
2499 }
2500
2501
2502 case kKmkCcExpInstr_SearchAndReplacePlainVariable:
2503 {
2504 PKMKCCEXPSRPLAINVAR pInstr = (PKMKCCEXPSRPLAINVAR)pInstrCore;
2505 struct variable *pVar = lookup_variable_strcached(pInstr->pszName);
2506 if (pVar)
2507 {
2508 char const *pszExpandedVarValue = pVar->recursive ? recursively_expand(pVar) : pVar->value;
2509 pchDst = patsubst_expand_pat(pchDst,
2510 pszExpandedVarValue,
2511 pInstr->pszSearchPattern,
2512 pInstr->pszReplacePattern,
2513 &pInstr->pszSearchPattern[pInstr->offPctSearchPattern],
2514 &pInstr->pszReplacePattern[pInstr->offPctReplacePattern]);
2515 if (pVar->recursive)
2516 free((void *)pszExpandedVarValue);
2517 }
2518 else
2519 warn_undefined(pInstr->pszName, strcache2_get_len(&variable_strcache, pInstr->pszName));
2520
2521 pInstrCore = pInstr->pNext;
2522 break;
2523 }
2524
2525 case kKmkCcExpInstr_PlainFunction:
2526 {
2527 PKMKCCEXPPLAINFUNC pInstr = (PKMKCCEXPPLAINFUNC)pInstrCore;
2528 uint32_t iArg;
2529 if (!pInstr->FnCore.fDirty)
2530 {
2531#ifdef KMK_CC_STRICT
2532 uint32_t uCrcBefore = 0;
2533 uint32_t uCrcAfter = 0;
2534 iArg = pInstr->FnCore.cArgs;
2535 while (iArg-- > 0)
2536 uCrcBefore = kmk_cc_debug_string_hash(uCrcBefore, pInstr->apszArgs[iArg]);
2537#endif
2538
2539 pchDst = pInstr->FnCore.pfnFunction(pchDst, (char **)&pInstr->apszArgs[0], pInstr->FnCore.pszFuncName);
2540
2541#ifdef KMK_CC_STRICT
2542 iArg = pInstr->FnCore.cArgs;
2543 while (iArg-- > 0)
2544 uCrcAfter = kmk_cc_debug_string_hash(uCrcAfter, pInstr->apszArgs[iArg]);
2545 KMK_CC_ASSERT(uCrcBefore == uCrcAfter);
2546#endif
2547 }
2548 else
2549 {
2550 char **papszShadowArgs = xmalloc((pInstr->FnCore.cArgs * 2 + 1) * sizeof(papszShadowArgs[0]));
2551 char **papszArgs = &papszShadowArgs[pInstr->FnCore.cArgs];
2552
2553 iArg = pInstr->FnCore.cArgs;
2554 papszArgs[iArg] = NULL;
2555 while (iArg-- > 0)
2556 papszArgs[iArg] = papszShadowArgs[iArg] = xstrdup(pInstr->apszArgs[iArg]);
2557
2558 pchDst = pInstr->FnCore.pfnFunction(pchDst, (char **)&pInstr->apszArgs[0], pInstr->FnCore.pszFuncName);
2559
2560 iArg = pInstr->FnCore.cArgs;
2561 while (iArg-- > 0)
2562 free(papszShadowArgs[iArg]);
2563 free(papszShadowArgs);
2564 }
2565
2566 pInstrCore = pInstr->FnCore.pNext;
2567 break;
2568 }
2569
2570 case kKmkCcExpInstr_DynamicFunction:
2571 {
2572 PKMKCCEXPDYNFUNC pInstr = (PKMKCCEXPDYNFUNC)pInstrCore;
2573 char **papszArgsShadow = xmalloc( (pInstr->FnCore.cArgs * 2 + 1) * sizeof(char *));
2574 char **papszArgs = &papszArgsShadow[pInstr->FnCore.cArgs];
2575 uint32_t iArg;
2576
2577 if (!pInstr->FnCore.fDirty)
2578 {
2579#ifdef KMK_CC_STRICT
2580 uint32_t uCrcBefore = 0;
2581 uint32_t uCrcAfter = 0;
2582#endif
2583 iArg = pInstr->FnCore.cArgs;
2584 papszArgs[iArg] = NULL;
2585 while (iArg-- > 0)
2586 {
2587 char *pszArg;
2588 if (pInstr->aArgs[iArg].fSubprog)
2589 pszArg = kmk_exec_expand_subprog_to_tmp(&pInstr->aArgs[iArg].u.Subprog, NULL);
2590 else
2591 pszArg = (char *)pInstr->aArgs[iArg].u.Plain.psz;
2592 papszArgsShadow[iArg] = pszArg;
2593 papszArgs[iArg] = pszArg;
2594#ifdef KMK_CC_STRICT
2595 uCrcBefore = kmk_cc_debug_string_hash(uCrcBefore, pszArg);
2596#endif
2597 }
2598 pchDst = pInstr->FnCore.pfnFunction(pchDst, papszArgs, pInstr->FnCore.pszFuncName);
2599
2600 iArg = pInstr->FnCore.cArgs;
2601 while (iArg-- > 0)
2602 {
2603#ifdef KMK_CC_STRICT
2604 KMK_CC_ASSERT(papszArgsShadow[iArg] == papszArgs[iArg]);
2605 uCrcAfter = kmk_cc_debug_string_hash(uCrcAfter, papszArgsShadow[iArg]);
2606#endif
2607 if (pInstr->aArgs[iArg].fSubprog)
2608 free(papszArgsShadow[iArg]);
2609 }
2610 KMK_CC_ASSERT(uCrcBefore == uCrcAfter);
2611 }
2612 else
2613 {
2614 iArg = pInstr->FnCore.cArgs;
2615 papszArgs[iArg] = NULL;
2616 while (iArg-- > 0)
2617 {
2618 char *pszArg;
2619 if (pInstr->aArgs[iArg].fSubprog)
2620 pszArg = kmk_exec_expand_subprog_to_tmp(&pInstr->aArgs[iArg].u.Subprog, NULL);
2621 else
2622 pszArg = xstrdup(pInstr->aArgs[iArg].u.Plain.psz);
2623 papszArgsShadow[iArg] = pszArg;
2624 papszArgs[iArg] = pszArg;
2625 }
2626
2627 pchDst = pInstr->FnCore.pfnFunction(pchDst, papszArgs, pInstr->FnCore.pszFuncName);
2628
2629 iArg = pInstr->FnCore.cArgs;
2630 while (iArg-- > 0)
2631 free(papszArgsShadow[iArg]);
2632 }
2633 free(papszArgsShadow);
2634
2635 pInstrCore = pInstr->FnCore.pNext;
2636 break;
2637 }
2638
2639 case kKmkCcExpInstr_Jump:
2640 {
2641 PKMKCCEXPJUMP pInstr = (PKMKCCEXPJUMP)pInstrCore;
2642 pInstrCore = pInstr->pNext;
2643 break;
2644 }
2645
2646 case kKmkCcExpInstr_Return:
2647 return pchDst;
2648
2649 default:
2650 fatal(NULL, _("Unknown string expansion opcode: %d (%#x)"),
2651 (int)pInstrCore->enmOpCode, (int)pInstrCore->enmOpCode);
2652 return NULL;
2653 }
2654 }
2655}
2656
2657
2658/**
2659 * Updates the string expansion statistics.
2660 *
2661 * @param pStats The statistics structure to update.
2662 * @param cchResult The result lenght.
2663 */
2664void kmk_cc_exp_stats_update(PKMKCCEXPSTATS pStats, uint32_t cchResult)
2665{
2666 /*
2667 * The average is simplified and not an exact average for every
2668 * expansion that has taken place.
2669 */
2670 pStats->cchAvg = (pStats->cchAvg * 7 + cchResult) / 8;
2671}
2672
2673
2674/**
2675 * Execute a string expansion subprogram, outputting to a new heap buffer.
2676 *
2677 * @returns Pointer to the output buffer (hand to free when done).
2678 * @param pSubprog The subprogram to execute.
2679 * @param pcchResult Where to return the size of the result. Optional.
2680 */
2681static char *kmk_exec_expand_subprog_to_tmp(PKMKCCEXPSUBPROG pSubprog, uint32_t *pcchResult)
2682{
2683 char *pchOldVarBuf;
2684 unsigned int cbOldVarBuf;
2685 char *pchDst;
2686 char *pszResult;
2687 uint32_t cchResult;
2688
2689 /*
2690 * Temporarily replace the variable buffer while executing the instruction
2691 * stream for this subprogram.
2692 */
2693 pchDst = install_variable_buffer_with_hint(&pchOldVarBuf, &cbOldVarBuf,
2694 pSubprog->Stats.cchAvg ? pSubprog->Stats.cchAvg + 32 : 256);
2695
2696 pchDst = kmk_exec_expand_instruction_stream_to_var_buf(pSubprog->pFirstInstr, pchDst);
2697
2698 /* Ensure that it's terminated. */
2699 pchDst = variable_buffer_output(pchDst, "\0", 1) - 1;
2700
2701 /* Grab the result buffer before restoring the previous one. */
2702 pszResult = variable_buffer;
2703 cchResult = (uint32_t)(pchDst - pszResult);
2704 if (pcchResult)
2705 *pcchResult = cchResult;
2706 kmk_cc_exp_stats_update(&pSubprog->Stats, cchResult);
2707
2708 variable_buffer = pchOldVarBuf;
2709 variable_buffer_length = cbOldVarBuf;
2710
2711 return pszResult;
2712}
2713
2714
2715/**
2716 * Execute a string expansion program, outputting to the current variable
2717 * buffer.
2718 *
2719 * @returns New variable buffer position.
2720 * @param pProg The program to execute.
2721 * @param pchDst The current varaible buffer position.
2722 */
2723static char *kmk_exec_expand_prog_to_var_buf(PKMKCCEXPPROG pProg, char *pchDst)
2724{
2725 uint32_t cchResult;
2726 uint32_t offStart = (uint32_t)(pchDst - variable_buffer);
2727
2728 if (pProg->Stats.cchAvg >= variable_buffer_length - offStart)
2729 pchDst = ensure_variable_buffer_space(pchDst, offStart + pProg->Stats.cchAvg + 32);
2730
2731 KMK_CC_ASSERT(pProg->cRefs > 0);
2732 pProg->cRefs++;
2733
2734 pchDst = kmk_exec_expand_instruction_stream_to_var_buf(pProg->pFirstInstr, pchDst);
2735
2736 pProg->cRefs--;
2737 KMK_CC_ASSERT(pProg->cRefs > 0);
2738
2739 cchResult = (uint32_t)(pchDst - variable_buffer);
2740 KMK_CC_ASSERT(cchResult >= offStart);
2741 cchResult -= offStart;
2742 kmk_cc_exp_stats_update(&pProg->Stats, cchResult);
2743 g_cVarForExpandExecs++;
2744
2745 return pchDst;
2746}
2747
2748
2749/**
2750 * Expands a variable into a variable buffer using its expandprog.
2751 *
2752 * @returns The new variable buffer position.
2753 * @param pVar Pointer to the variable. Must have a program.
2754 * @param pchDst Pointer to the current variable buffer position.
2755 */
2756char *kmk_exec_expand_to_var_buf(struct variable *pVar, char *pchDst)
2757{
2758 KMK_CC_ASSERT(pVar->expandprog);
2759 KMK_CC_ASSERT(pVar->expandprog->uInputHash == kmk_cc_debug_string_hash(0, pVar->value));
2760 return kmk_exec_expand_prog_to_var_buf(pVar->expandprog, pchDst);
2761}
2762
2763
2764
2765
2766
2767/*
2768 *
2769 * Makefile evaluation programs.
2770 * Makefile evaluation programs.
2771 * Makefile evaluation programs.
2772 *
2773 */
2774
2775static size_t kmk_cc_eval_detect_eol_style(char *pchFirst, char *pchSecond, const char *pszContent, size_t cchContent)
2776{
2777 /* Look for LF first. */
2778 const char *pszTmp = (const char *)memchr(pszContent, '\n', cchContent);
2779 if (pszTmp)
2780 {
2781 /* CRLF? */
2782 if (pszTmp != pszContent && pszTmp[-1] == '\r')
2783 {
2784 *pchFirst = '\r';
2785 *pchSecond = '\n';
2786 return 2;
2787 }
2788
2789 /* No, LF or LFCR. (pszContent is zero terminated, so no bounds checking necessary.) */
2790 *pchFirst = '\n';
2791 if (pszTmp[1] != '\r')
2792 {
2793 *pchSecond = 0;
2794 return 1;
2795 }
2796 *pchSecond = '\r';
2797 return 2;
2798 }
2799
2800 /* Probably no EOLs here. */
2801 if (memchr(pszContent, '\r', cchContent) == NULL)
2802 {
2803 *pchSecond = *pchFirst = 0;
2804 return 0;
2805 }
2806
2807 /* kind of unlikely */
2808 *pchFirst = '\r';
2809 *pchSecond = 0;
2810 return 1;
2811}
2812
2813
2814#if 0
2815/**
2816 * Checks whether we've got an EOL escape sequence or not.
2817 *
2818 * @returns non-zero if escaped EOL, 0 if not (i.e. actual EOL).
2819 * @param pszContent The string pointer @a offEol is relative to.
2820 * @param offEol The offset of the first EOL char.
2821 */
2822static unsigned kmk_cc_eval_is_eol_escape_seq(const char *pszContent, size_t offEol)
2823{
2824 /* The caller has already checked out two backslashes. */
2825 size_t offFirstBackslash = offEol;
2826 KMK_CC_ASSERT(offFirstBackslash >= 2);
2827 offFirstBackslash -= 2;
2828
2829 /* Find the first backslash. */
2830 while (offFirstBackslash > 0 && pszContent[offFirstBackslash - 1] == '\\')
2831 offFirstBackslash--;
2832
2833 /* Odd number -> escaped EOL; Even number -> real EOL; */
2834 return (offEol - offFirstBackslash) & 1;
2835}
2836#endif
2837
2838
2839
2840typedef enum kmk_cc_eval_token
2841{
2842 /** Invalid token . */
2843 kKmkCcEvalToken_Invalid = 0,
2844
2845 /** Assignment: '=' */
2846 kKmkCcEvalToken_AssignRecursive,
2847 /** Assignment: ':=' */
2848 kKmkCcEvalToken_AssignSimple,
2849 /** Assignment: '+=' */
2850 kKmkCcEvalToken_AssignAppend,
2851 /** Assignment: '<=' */
2852 kKmkCcEvalToken_AssignPrepend,
2853 /** Assignment: '?=' */
2854 kKmkCcEvalToken_AssignIfNew,
2855 /** Assignment: 'define' */
2856 kKmkCcEvalToken_define,
2857 /** Unassignment: 'undefine' */
2858 kKmkCcEvalToken_undefine,
2859
2860 /* Assignment modifier: 'local' */
2861 kKmkCcEvalToken_local,
2862 /* Assignment modifier: 'override' */
2863 kKmkCcEvalToken_override,
2864 /* Assignment modifier: 'private' (target variable not inh by deps) */
2865 kKmkCcEvalToken_private,
2866 /* Assignment modifier / other variable thing: 'export' */
2867 kKmkCcEvalToken_export,
2868 /* Other variable thing: 'unexport' */
2869 kKmkCcEvalToken_unexport,
2870
2871 kKmkCcEvalToken_ifdef,
2872 kKmkCcEvalToken_ifndef,
2873 kKmkCcEvalToken_ifeq,
2874 kKmkCcEvalToken_ifneq,
2875 kKmkCcEvalToken_if1of,
2876 kKmkCcEvalToken_ifn1of,
2877 kKmkCcEvalToken_if,
2878 kKmkCcEvalToken_else,
2879 kKmkCcEvalToken_endif,
2880
2881 kKmkCcEvalToken_include,
2882 kKmkCcEvalToken_include_silent,
2883 kKmkCcEvalToken_includedep,
2884 kKmkCcEvalToken_includedep_queue,
2885 kKmkCcEvalToken_includedep_flush,
2886
2887 kKmkCcEvalToken_colon,
2888 kKmkCcEvalToken_double_colon,
2889 kKmkCcEvalToken_plus,
2890 kKmkCcEvalToken_plus_maybe,
2891
2892 kKmkCcEvalToken_vpath,
2893
2894 /** Plain word. */
2895 kKmkCcEvalToken_WordPlain,
2896 /** Word that maybe in need of expanding. */
2897 kKmkCcEvalToken_WordWithDollar,
2898
2899 kKmkCcEvalToken_End
2900} KMKCCEVALTOKEN;
2901
2902/**
2903 * A tokenized word.
2904 */
2905typedef struct kmk_cc_eval_word
2906{
2907 /** The token word (lexeme). */
2908 const char *pszWord;
2909 /** The length of the word (lexeme). */
2910 uint32_t cchWord;
2911 /** The token classification. */
2912 KMKCCEVALTOKEN enmToken;
2913} KMKCCEVALWORD;
2914typedef KMKCCEVALWORD *PKMKCCEVALWORD;
2915
2916
2917/**
2918 * Escaped end-of-line sequence in the current line.
2919 */
2920typedef struct KMKCCEVALESCEOL
2921{
2922 /** Offset at which the EOL escape sequence starts for a non-command line. */
2923 size_t offEsc;
2924 /** Offset of the newline sequence. */
2925 size_t offEol;
2926} KMKCCEVALESCEOL;
2927typedef KMKCCEVALESCEOL *PKMKCCEVALESCEOL;
2928
2929
2930/**
2931 * String copy segment.
2932 */
2933typedef 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;
2941typedef KMKCCEVALSTRCPYSEG *PKMKCCEVALSTRCPYSEG;
2942typedef KMKCCEVALSTRCPYSEG const *PCKMKCCEVALSTRCPYSEG;
2943
2944
2945typedef struct KMKCCEVALCOMPILER
2946{
2947 /** Pointer to the KMKCCEVALPROG::pBlockTail member. */
2948 PKMKCCBLOCK *ppBlockTail;
2949
2950 /** @name Line parsing state.
2951 * @{ */
2952 /** Offset of newline escape sequences in the current line.
2953 * This is only applicable if cEscEols is not zero. */
2954 PKMKCCEVALESCEOL paEscEols;
2955 /** The number of number of paEscEols entries we've allocated. */
2956 unsigned cEscEolsAllocated;
2957 /** Number of escaped EOLs (line count - 1). */
2958 unsigned cEscEols;
2959 /** The paEscEols entry corresponding to the current parsing location.
2960 * Still to be seen how accurate this can be made to be. */
2961 unsigned iEscEol;
2962
2963 /** The current line number (for error handling / debugging). */
2964 unsigned iLine;
2965 /** The start offset of the current line. */
2966 size_t offLine;
2967 /** Length of the current line, sans the final EOL and comments. */
2968 size_t cchLine;
2969 /** Length of the current line, sans the final EOL but with comments. */
2970 size_t cchLineWithComments;
2971
2972 /** The first char in an EOL sequence.
2973 * We ASSUMES that this char won't appear in any other sequence in the file,
2974 * thus skipping matching any subsequent chars. */
2975 char chFirstEol;
2976 /** The second char in an EOL sequence, if applicable. */
2977 char chSecondEol;
2978
2979 /** The length of the EOL sequence. */
2980 size_t cchEolSeq;
2981 /** The minimum length of an esacped EOL sequence (cchEolSeq + 1). */
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;
2990 /** @} */
2991
2992
2993 /** @name Recipe state.
2994 * @{ */
2995 /** Set if we're working on a recipe. */
2996 PKMKCCEVALRECIPE pRecipe;
2997 /** Set for ignoring recipes without targets (Sun OS 4 Make). */
2998 uint8_t fNoTargetRecipe;
2999 /** The command prefix character. */
3000 char chCmdPrefix;
3001 /** @} */
3002
3003 /** @name Tokenzied words.
3004 * @{ */
3005 uint32_t cWords;
3006 uint32_t cWordsAllocated;
3007 PKMKCCEVALWORD paWords;
3008 /** @} */
3009
3010 /** @name Conditionals.
3011 * @{ */
3012 /** Current conditional stack depth. */
3013 unsigned cIfs;
3014 /** The conditional directive stack. */
3015 PKMKCCEVALIFCORE apIfs[KMK_CC_EVAL_MAX_IF_DEPTH];
3016 /** @} */
3017
3018 /** The program being compiled. */
3019 PKMKCCEVALPROG pEvalProg;
3020 /** Pointer to the content. */
3021 const char *pszContent;
3022 /** The amount of input to parse. */
3023 size_t cchContent;
3024} KMKCCEVALCOMPILER;
3025typedef KMKCCEVALCOMPILER *PKMKCCEVALCOMPILER;
3026
3027
3028static void kmk_cc_eval_init_compiler(PKMKCCEVALCOMPILER pCompiler, PKMKCCEVALPROG pEvalProg, unsigned iLine,
3029 const char *pszContent, size_t cchContent)
3030{
3031 pCompiler->ppBlockTail = &pEvalProg->pBlockTail;
3032
3033 pCompiler->pRecipe = NULL;
3034 pCompiler->fNoTargetRecipe = 0;
3035 pCompiler->chCmdPrefix = cmd_prefix;
3036
3037 pCompiler->cWordsAllocated = 0;
3038 pCompiler->paWords = NULL;
3039
3040 pCompiler->cEscEolsAllocated = 0;
3041 pCompiler->paEscEols = NULL;
3042 pCompiler->iLine = iLine;
3043
3044 pCompiler->cStrCopySegsAllocated = 0;
3045 pCompiler->paStrCopySegs = NULL;
3046
3047 pCompiler->cIfs = 0;
3048
3049 pCompiler->pEvalProg = pEvalProg;
3050 pCompiler->pszContent = pszContent;
3051 pCompiler->cchContent = cchContent;
3052
3053 /* Detect EOL style. */
3054 pCompiler->cchEolSeq = kmk_cc_eval_detect_eol_style(&pCompiler->chFirstEol, &pCompiler->chSecondEol,
3055 pszContent, cchContent);
3056 pCompiler->cchEscEolSeq = 1 + pCompiler->cchEolSeq;
3057}
3058
3059
3060static void kmk_cc_eval_delete_compiler(PKMKCCEVALCOMPILER pCompiler)
3061{
3062 if (pCompiler->paWords)
3063 free(pCompiler->paWords);
3064 if (pCompiler->paEscEols)
3065 free(pCompiler->paEscEols);
3066}
3067
3068static void kmk_cc_eval_fatal(PKMKCCEVALCOMPILER pCompiler, const char *pchWhere, const char *pszMsg, ...)
3069{
3070 va_list va;
3071 unsigned iLine = pCompiler->iLine;
3072
3073 log_working_directory(1);
3074
3075 /*
3076 * If we have a pointer location, use it to figure out the exact line and column.
3077 */
3078 if (pchWhere)
3079 {
3080 size_t offLine = pCompiler->offLine;
3081 size_t off = pchWhere - pCompiler->pszContent;
3082 unsigned i = 0;
3083 while ( i < pCompiler->cEscEols
3084 && off > pCompiler->paEscEols[i].offEol)
3085 {
3086 offLine = pCompiler->paEscEols[i].offEol + 1 + pCompiler->cchEolSeq;
3087 iLine++;
3088 i++;
3089 }
3090 KMK_CC_ASSERT(off <= pCompiler->cchContent);
3091
3092 if (pCompiler->pEvalProg->pszVarName)
3093 fprintf(stderr, "%s:%u:%u: *** fatal parsing error in %s: ",
3094 pCompiler->pEvalProg->pszFilename, iLine, (unsigned)(off - offLine), pCompiler->pEvalProg->pszVarName);
3095 else
3096 fprintf(stderr, "%s:%u:%u: *** fatal parsing error: ",
3097 pCompiler->pEvalProg->pszFilename, iLine, (unsigned)(off - offLine));
3098 }
3099 else if (pCompiler->pEvalProg->pszVarName)
3100 fprintf(stderr, "%s:%u: *** fatal parsing error in %s: ",
3101 pCompiler->pEvalProg->pszFilename, iLine, pCompiler->pEvalProg->pszVarName);
3102 else
3103 fprintf(stderr, "%s:%u: *** fatal parsing error: ",
3104 pCompiler->pEvalProg->pszFilename, iLine);
3105
3106 /*
3107 * Print the message and die.
3108 */
3109 va_start(va, pszMsg);
3110 vfprintf(stderr, pszMsg, va);
3111 va_end(va);
3112 fputs(". Stop.\n", stderr);
3113
3114 for (;;)
3115 die(2);
3116}
3117
3118
3119static void kmk_cc_eval_fatal_eol(PKMKCCEVALCOMPILER pCompiler, const char *pchEol, unsigned iLine, size_t offLine)
3120{
3121 pCompiler->iLine = iLine;
3122 pCompiler->offLine = offLine;
3123
3124 for (;;)
3125 kmk_cc_eval_fatal(pCompiler, pchEol, "Missing 2nd EOL character: found %#x instead of %#x\n",
3126 pchEol, pCompiler->chSecondEol);
3127}
3128
3129
3130/**
3131 * Compiles a string expansion subprogram.
3132 *
3133 * @param pCompiler The compiler state.
3134 * @param pszExpr The expression to compile.
3135 * @param cchExpr The length of the expression.
3136 * @param pSubprog The subprogram to compile.
3137 */
3138static void kmk_cc_eval_compile_string_exp_subprog(PKMKCCEVALCOMPILER pCompiler, const char *pszExpr, size_t cchExpr,
3139 PKMKCCEXPSUBPROG pSubprog)
3140{
3141 int rc = kmk_cc_exp_compile_subprog(pCompiler->ppBlockTail, pszExpr, cchExpr, pSubprog);
3142 if (rc == 0)
3143 return;
3144 kmk_cc_eval_fatal(pCompiler, NULL, "String expansion compile error");
3145}
3146
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 */
3157static 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
3175/** @name KMK_CC_WORD_COMP_CONST_XXX - Optimal(/insane) constant work matching.
3176 * @{
3177 */
3178#if (defined(KBUILD_ARCH_X86) || defined(KBUILD_ARCH_AMD64)) /* Unaligned access is reasonably cheap. */ \
3179 && !defined(GCC_ADDRESS_SANITIZER)
3180# define KMK_CC_WORD_COMP_CONST_2(a_pchLine, a_pszWord) \
3181 ( *(uint16_t const *)(a_pchLine) == *(uint16_t const *)(a_pszWord) )
3182# define KMK_CC_WORD_COMP_CONST_3(a_pchLine, a_pszWord) \
3183 ( *(uint16_t const *)(a_pchLine) == *(uint16_t const *)(a_pszWord) \
3184 && (a_pchLine)[2] == (a_pszWord)[2] )
3185# define KMK_CC_WORD_COMP_CONST_4(a_pchLine, a_pszWord) \
3186 ( *(uint32_t const *)(a_pchLine) == *(uint32_t const *)(a_pszWord) )
3187# define KMK_CC_WORD_COMP_CONST_5(a_pchLine, a_pszWord) \
3188 ( *(uint32_t const *)(a_pchLine) == *(uint32_t const *)(a_pszWord) \
3189 && (a_pchLine)[4] == (a_pszWord)[4] )
3190# define KMK_CC_WORD_COMP_CONST_6(a_pchLine, a_pszWord) \
3191 ( *(uint32_t const *)(a_pchLine) == *(uint32_t const *)(a_pszWord) \
3192 && ((uint16_t const *)(a_pchLine))[2] == ((uint32_t const *)(a_pszWord))[2] )
3193# define KMK_CC_WORD_COMP_CONST_7(a_pchLine, a_pszWord) \
3194 ( *(uint32_t const *)(a_pchLine) == *(uint32_t const *)(a_pszWord) \
3195 && ((uint16_t const *)(a_pchLine))[2] == ((uint32_t const *)(a_pszWord))[2] \
3196 && (a_pchLine)[6] == (a_pszWord)[6] )
3197# define KMK_CC_WORD_COMP_CONST_8(a_pchLine, a_pszWord) \
3198 ( *(uint64_t const *)(a_pchLine) == *(uint64_t const *)(a_pszWord) )
3199# define KMK_CC_WORD_COMP_CONST_10(a_pchLine, a_pszWord) \
3200 ( *(uint64_t const *)(a_pchLine) == *(uint64_t const *)(a_pszWord) \
3201 && ((uint16_t const *)(a_pchLine))[4] == ((uint16_t const *)(a_pszWord))[4] )
3202# define KMK_CC_WORD_COMP_CONST_16(a_pchLine, a_pszWord) \
3203 ( *(uint64_t const *)(a_pchLine) == *(uint64_t const *)(a_pszWord) \
3204 && ((uint64_t const *)(a_pchLine))[1] == ((uint64_t const *)(a_pszWord))[1] )
3205#else
3206# define KMK_CC_WORD_COMP_CONST_2(a_pchLine, a_pszWord) \
3207 ( (a_pchLine)[0] == (a_pszWord)[0] \
3208 && (a_pchLine)[1] == (a_pszWord)[1] )
3209# define KMK_CC_WORD_COMP_CONST_3(a_pchLine, a_pszWord) \
3210 ( (a_pchLine)[0] == (a_pszWord)[0] \
3211 && (a_pchLine)[1] == (a_pszWord)[1] \
3212 && (a_pchLine)[2] == (a_pszWord)[2] )
3213# define KMK_CC_WORD_COMP_CONST_4(a_pchLine, a_pszWord) \
3214 ( (a_pchLine)[0] == (a_pszWord)[0] \
3215 && (a_pchLine)[1] == (a_pszWord)[1] \
3216 && (a_pchLine)[2] == (a_pszWord)[2] \
3217 && (a_pchLine)[3] == (a_pszWord)[3] )
3218# define KMK_CC_WORD_COMP_CONST_5(a_pchLine, a_pszWord) \
3219 ( (a_pchLine)[0] == (a_pszWord)[0] \
3220 && (a_pchLine)[1] == (a_pszWord)[1] \
3221 && (a_pchLine)[2] == (a_pszWord)[2] \
3222 && (a_pchLine)[3] == (a_pszWord)[3] \
3223 && (a_pchLine)[4] == (a_pszWord)[4] )
3224# define KMK_CC_WORD_COMP_CONST_6(a_pchLine, a_pszWord) \
3225 ( (a_pchLine)[0] == (a_pszWord)[0] \
3226 && (a_pchLine)[1] == (a_pszWord)[1] \
3227 && (a_pchLine)[2] == (a_pszWord)[2] \
3228 && (a_pchLine)[3] == (a_pszWord)[3] \
3229 && (a_pchLine)[4] == (a_pszWord)[4] \
3230 && (a_pchLine)[5] == (a_pszWord)[5] )
3231# define KMK_CC_WORD_COMP_CONST_7(a_pchLine, a_pszWord) \
3232 ( (a_pchLine)[0] == (a_pszWord)[0] \
3233 && (a_pchLine)[1] == (a_pszWord)[1] \
3234 && (a_pchLine)[2] == (a_pszWord)[2] \
3235 && (a_pchLine)[3] == (a_pszWord)[3] \
3236 && (a_pchLine)[4] == (a_pszWord)[4] \
3237 && (a_pchLine)[5] == (a_pszWord)[5] \
3238 && (a_pchLine)[6] == (a_pszWord)[6] )
3239# define KMK_CC_WORD_COMP_CONST_8(a_pchLine, a_pszWord) \
3240 ( (a_pchLine)[0] == (a_pszWord)[0] \
3241 && (a_pchLine)[1] == (a_pszWord)[1] \
3242 && (a_pchLine)[2] == (a_pszWord)[2] \
3243 && (a_pchLine)[3] == (a_pszWord)[3] \
3244 && (a_pchLine)[4] == (a_pszWord)[4] \
3245 && (a_pchLine)[5] == (a_pszWord)[5] \
3246 && (a_pchLine)[6] == (a_pszWord)[6] \
3247 && (a_pchLine)[7] == (a_pszWord)[7] )
3248# define KMK_CC_WORD_COMP_CONST_10(a_pchLine, a_pszWord) \
3249 ( (a_pchLine)[0] == (a_pszWord)[0] \
3250 && (a_pchLine)[1] == (a_pszWord)[1] \
3251 && (a_pchLine)[2] == (a_pszWord)[2] \
3252 && (a_pchLine)[3] == (a_pszWord)[3] \
3253 && (a_pchLine)[4] == (a_pszWord)[4] \
3254 && (a_pchLine)[5] == (a_pszWord)[5] \
3255 && (a_pchLine)[6] == (a_pszWord)[6] \
3256 && (a_pchLine)[7] == (a_pszWord)[7] \
3257 && (a_pchLine)[8] == (a_pszWord)[8] \
3258 && (a_pchLine)[9] == (a_pszWord)[9] )
3259# define KMK_CC_WORD_COMP_CONST_16(a_pchLine, a_pszWord) \
3260 ( (a_pchLine)[0] == (a_pszWord)[0] \
3261 && (a_pchLine)[1] == (a_pszWord)[1] \
3262 && (a_pchLine)[2] == (a_pszWord)[2] \
3263 && (a_pchLine)[3] == (a_pszWord)[3] \
3264 && (a_pchLine)[4] == (a_pszWord)[4] \
3265 && (a_pchLine)[5] == (a_pszWord)[5] \
3266 && (a_pchLine)[6] == (a_pszWord)[6] \
3267 && (a_pchLine)[7] == (a_pszWord)[7] \
3268 && (a_pchLine)[8] == (a_pszWord)[8] \
3269 && (a_pchLine)[9] == (a_pszWord)[9] \
3270 && (a_pchLine)[10] == (a_pszWord)[10] \
3271 && (a_pchLine)[11] == (a_pszWord)[11] \
3272 && (a_pchLine)[12] == (a_pszWord)[12] \
3273 && (a_pchLine)[13] == (a_pszWord)[13] \
3274 && (a_pchLine)[14] == (a_pszWord)[14] \
3275 && (a_pchLine)[15] == (a_pszWord)[15])
3276#endif
3277/** See if a starting of a given length starts with a constant word. */
3278#define KMK_CC_WORD_COMP_IS_EOL(a_pCompiler, a_pchLine, a_cchLine) \
3279 ( (a_cchLine) == 0 \
3280 || KMK_CC_EVAL_IS_SPACE((a_pchLine)[0]) \
3281 || ((a_pchLine)[0] == '\\' && (a_pchLine)[1] == (a_pCompiler)->chFirstEol) ) \
3282
3283/** See if a starting of a given length starts with a constant word. */
3284#define KMK_CC_WORD_COMP_CONST(a_pCompiler, a_pchLine, a_cchLine, a_pszWord, a_cchWord) \
3285 ( (a_cchLine) >= (a_cchWord) \
3286 && ( (a_cchLine) == (a_cchWord) \
3287 || KMK_CC_EVAL_IS_SPACE((a_pchLine)[a_cchWord]) \
3288 || ((a_pchLine)[a_cchWord] == '\\' && (a_pchLine)[(a_cchWord) + 1] == (a_pCompiler)->chFirstEol) ) \
3289 && KMK_CC_WORD_COMP_CONST_##a_cchWord(a_pchLine, a_pszWord) )
3290/** @} */
3291
3292
3293/**
3294 * Checks if a_ch is a space after a word.
3295 *
3296 * Since there is always a terminating zero, the user can safely access a char
3297 * beyond @a a_cchLeft. However, that byte isn't necessarily a zero terminator
3298 * character, so we have to check @a a_cchLeft whether we're at the end of the
3299 * parsing input string.
3300 *
3301 * @returns true / false.
3302 * @param a_pCompiler The compiler instance data.
3303 * @param a_ch The character to inspect.
3304 * @param a_ch2 The character following it, in case of escaped EOL.
3305 * @param a_cchLeft The number of chars left to parse (from @a a_ch).
3306 */
3307#define KMK_CC_EVAL_IS_SPACE_AFTER_WORD(a_pCompiler, a_ch, a_ch2, a_cchLeft) \
3308 ( a_cchLeft == 0 \
3309 || KMK_CC_EVAL_IS_SPACE(a_ch) \
3310 || ((a_ch) == '\\' && (a_ch2) == (a_pCompiler)->chFirstEol) )
3311
3312/**
3313 * Used to skip spaces after a word.
3314 *
3315 * We ASSUME that the first char is a space or that we've reached the end of the
3316 * string (a_cchLeft == 0).
3317 *
3318 * @param a_pCompiler The compiler instance data.
3319 * @param a_pchWord The current input position, this will be moved to
3320 * the start of the next word or end of the input.
3321 * @param a_cchLeft The number of chars left to parse. This will be
3322 * updated.
3323 */
3324#define KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(a_pCompiler, a_pchWord, a_cchLeft) \
3325 do { \
3326 /* Skip the first char which is known to be a space, end of line or end of input. */ \
3327 if ((a_cchLeft) > 0) \
3328 { \
3329 char const chSkipBlanksFirst = *(a_pchWord); \
3330 KMK_CC_ASSERT(KMK_CC_EVAL_IS_SPACE_AFTER_WORD(a_pCompiler, chSkipBlanksFirst, (a_pchWord)[1], a_cchLeft)); \
3331 if (chSkipBlanksFirst != '\\') \
3332 { \
3333 (a_pchWord) += 1; \
3334 (a_cchLeft) -= 1; \
3335 \
3336 /* Another space or escaped EOL? Then there are probably more then, so call worker function. */ \
3337 if ((a_cchLeft) > 0) \
3338 { \
3339 char const chSkipBlanksSecond = *(a_pchWord); \
3340 if (KMK_CC_EVAL_IS_SPACE_OR_BACKSLASH(chSkipBlanksSecond)) \
3341 (a_pchWord) = kmk_cc_eval_skip_spaces_after_word_slow(a_pchWord, &(a_cchLeft), \
3342 chSkipBlanksSecond, a_pCompiler); \
3343 } \
3344 } \
3345 else /* escape sequences can be complicated. */ \
3346 (a_pchWord) = kmk_cc_eval_skip_spaces_after_word_slow(a_pchWord, &(a_cchLeft), \
3347 chSkipBlanksFirst, a_pCompiler); \
3348 } \
3349 } while (0)
3350
3351
3352//static int kmk_cc_eval_skip_esc_eol_slow(const char *pchWord, size_t cchLeft, PKMKCCEVALCOMPILER pCompiler,
3353// const char **ppchWord, size_t *pcchLeft)
3354//{
3355// KMK_CC_ASSERT(pchWord[0] == '\\');
3356// if (pCompiler->cEscEols)
3357// {
3358// size_t cchMin = 1 + pCompiler->chFirstEol;
3359// if (cchLeft >= cchMin)
3360// {
3361// /* The simple case, no extra backslashes. */
3362// if (pchWord[1] == pCompiler->chFirstEol)
3363// {
3364// *pcchLeft = cchLeft - cchMin;
3365// *pchWord = pchWord + cchMin;
3366// return 1;
3367// }
3368//
3369// /* The unlikly case, */
3370//
3371// }
3372// }
3373// return 0;
3374//}
3375
3376
3377/**
3378 * The slow path of KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD.
3379 *
3380 * This is called to handles escaped EOL sequences, as these can involve
3381 * multiple backslashes and therefore doesn't led themselves well to inlined
3382 * code.
3383 *
3384 * The other case this is used for is to handle more than once space, since it's
3385 * likely that when there are two there might be more. No point in inlining
3386 * that, better do some loop unrolling instead.
3387 *
3388 * @returns Points to the first non-space character or end of input.
3389 * @param pchWord The current position. There is some kind of char
3390 * @param pcchLeft Pointer to the cchLeft variable, this is both
3391 * input and output.
3392 * @param ch The current character.
3393 * @param pCompiler The compiler instance data.
3394 */
3395static const char *kmk_cc_eval_skip_spaces_after_word_slow(const char *pchWord, size_t *pcchLeft, char ch,
3396 PKMKCCEVALCOMPILER pCompiler)
3397{
3398 size_t cchLeft = *pcchLeft;
3399
3400 /*
3401 * Skip the pending space or EOL found by the caller. We need to
3402 * confirm the EOL.
3403 *
3404 * Note! We only need to care about simple backslash+EOL sequences here
3405 * since we're either at the end of a validated word, or we've already
3406 * skipped one space. In the former case, someone else has already
3407 * validated the escape esequence, in the latter case multiple
3408 * backslashes would indicate a new word that that we should return.
3409 */
3410 if (ch != '\\')
3411 {
3412 pchWord += 1;
3413 cchLeft -= 1;
3414 }
3415 else if ( cchLeft >= pCompiler->cchEscEolSeq
3416 && pchWord[1] == pCompiler->chFirstEol)
3417 {
3418 KMK_CC_ASSERT(pCompiler->cchEolSeq == 1 || pchWord[2] == pCompiler->chSecondEol);
3419 pchWord += pCompiler->cchEscEolSeq;
3420 cchLeft -= pCompiler->cchEscEolSeq;
3421 pCompiler->iEscEol++;
3422 }
3423 else
3424 return pchWord;
3425
3426 /*
3427 * Skip further spaces. We unrolls 4 loops here.
3428 * ASSUMES cchEscEolSeq is either 2 or 3!
3429 */
3430 KMK_CC_ASSERT(pCompiler->cchEscEolSeq == 2 || pCompiler->cchEscEolSeq == 3);
3431 while (cchLeft >= 4)
3432 {
3433 /* First char. */
3434 ch = pchWord[0];
3435 if (KMK_CC_EVAL_IS_SPACE(ch))
3436 { /* maybe likely */ }
3437 else if ( ch == '\\'
3438 && pchWord[1] == pCompiler->chFirstEol)
3439 {
3440 pchWord += pCompiler->cchEscEolSeq;
3441 cchLeft -= pCompiler->cchEscEolSeq;
3442 pCompiler->iEscEol++;
3443 continue;
3444 }
3445 else
3446 {
3447 *pcchLeft = cchLeft;
3448 return pchWord;
3449 }
3450
3451 /* Second char. */
3452 ch = pchWord[1];
3453 if (KMK_CC_EVAL_IS_SPACE(ch))
3454 { /* maybe likely */ }
3455 else if ( ch == '\\'
3456 && pchWord[2] == pCompiler->chFirstEol)
3457 {
3458 pchWord += 1 + pCompiler->cchEscEolSeq;
3459 cchLeft -= 1 + pCompiler->cchEscEolSeq;
3460 pCompiler->iEscEol++;
3461 continue;
3462 }
3463 else
3464 {
3465 *pcchLeft = cchLeft - 1;
3466 return pchWord + 1;
3467 }
3468
3469 /* Third char. */
3470 ch = pchWord[2];
3471 if (KMK_CC_EVAL_IS_SPACE(ch))
3472 { /* maybe likely */ }
3473 else if ( ch == '\\'
3474 && pchWord[3] == pCompiler->chFirstEol
3475 && cchLeft >= 2 + pCompiler->cchEscEolSeq)
3476 {
3477 pchWord += 2 + pCompiler->cchEscEolSeq;
3478 cchLeft -= 2 + pCompiler->cchEscEolSeq;
3479 pCompiler->iEscEol++;
3480 continue;
3481 }
3482 else
3483 {
3484 *pcchLeft = cchLeft - 2;
3485 return pchWord + 2;
3486 }
3487
3488 /* Third char. */
3489 ch = pchWord[3];
3490 if (KMK_CC_EVAL_IS_SPACE(ch))
3491 {
3492 pchWord += 4;
3493 cchLeft -= 4;
3494 }
3495 else if ( ch == '\\'
3496 && cchLeft >= 3 + pCompiler->cchEscEolSeq
3497 && pchWord[4] == pCompiler->chFirstEol)
3498 {
3499 pchWord += 3 + pCompiler->cchEscEolSeq;
3500 cchLeft -= 3 + pCompiler->cchEscEolSeq;
3501 pCompiler->iEscEol++;
3502 }
3503 else
3504 {
3505 *pcchLeft = cchLeft - 3;
3506 return pchWord + 3;
3507 }
3508 }
3509
3510 /*
3511 * Simple loop for the final three chars.
3512 */
3513 while (cchLeft > 0)
3514 {
3515 /* First char. */
3516 ch = *pchWord;
3517 if (KMK_CC_EVAL_IS_SPACE(ch))
3518 {
3519 pchWord += 1;
3520 cchLeft -= 1;
3521 }
3522 else if ( ch == '\\'
3523 && cchLeft > pCompiler->cchEolSeq
3524 && pchWord[1] == pCompiler->chFirstEol)
3525 {
3526 pchWord += pCompiler->cchEscEolSeq;
3527 cchLeft -= pCompiler->cchEscEolSeq;
3528 pCompiler->iEscEol++;
3529 }
3530 else
3531 break;
3532 }
3533
3534 *pcchLeft = cchLeft;
3535 return pchWord;
3536}
3537
3538
3539#if 0
3540/**
3541 * Used to shed trailing spaces in a string by decrementing @ a_cchLeft.
3542 *
3543 * @param a_pCompiler The compiler instance data.
3544 * @param a_pchWord The current input position, this will not be
3545 * changed.
3546 * @param a_cchLeft The number of chars left to parse. This will be
3547 * updated if there are trailing spaces.
3548 */
3549#define KMK_CC_EVAL_SHED_TRAILING_SPACES(a_pCompiler, a_pchWord, a_cchLeft) \
3550 do { \
3551 if ((a_cchLeft) > 0) \
3552 { \
3553 char const chShedTrailing1 = (a_pchWord)[(a_cchLeft) - 1]; \
3554 if (KMK_CC_EVAL_IS_SPACE(chShedTrailing1)) \
3555 { \
3556 /* If there are two or more, or any of these are potential EOL chars, call worker. */ \
3557 if (!KMK_CC_EVAL_IS_EOL_CANDIDATE(chShedTrailing1)) \
3558 { \
3559 (a_cchLeft) -= 1; \
3560 if ((a_cchLeft) > 0) \
3561 { \
3562 char const chShedTrailing2 = (a_pchWord)[(a_cchLeft) - 1]; \
3563 if (KMK_CC_EVAL_IS_SPACE(chShedTrailing)) \
3564 (a_cchLeft) = kmk_cc_eval_shed_trailing_spaces_slow(a_pchWord, (a_cchLeft), \
3565 chShedTrailing2, a_pCompiler); \
3566 } \
3567 } \
3568 else \
3569 (a_cchWord) = kmk_cc_eval_shed_trailing_spaces_slow(a_pchWord, (a_cchLeft), \
3570 chShedTrailing1, a_pCompiler); \
3571 } \
3572 } \
3573 } while (0)
3574
3575
3576
3577/**
3578 * The slow path of KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD.
3579 *
3580 * It's called when a space or backslash is encountered as the 2nd character.
3581 * A second space is likely to be followed by more spaces, while an escaped
3582 * newline (if it checks out) is very likely to be followed by more spaces or
3583 * tabs before we get to anything worthwhile. Also, checking for an esacped
3584 * end-of-line character is a bit tedious. (It could be worse, though, as we
3585 * know that any EOL sequence inside the text area we're currently working on
3586 * must be escaped.)
3587 *
3588 * @returns Points to the first non-space character or end of input.
3589 * @param pchWord The current position. There is some kind of char
3590 * @param cchLeft The number of chars left to parse at @a pchWord.
3591 * @param ch The current tail character.
3592 * @param pCompiler The compiler instance data.
3593 */
3594static size_t kmk_cc_eval_shed_trailing_spaces_slow(const char *pchWord, size_t cchLeft, char ch,
3595 PKMKCCEVALCOMPILER pCompiler)
3596{
3597 for (;;)
3598 {
3599 if (KMK_CC_EVAL_IS_EOL_CANDIDATE(chShedTrailing1))
3600 {
3601
3602 }
3603
3604 }
3605}
3606#endif
3607
3608
3609/**
3610 * Skips to the end of a variable name.
3611 *
3612 * This may advance pCompiler->iEscEol.
3613 *
3614 * @returns Pointer to the first char after the variable name.
3615 * @param pCompiler The compiler state.
3616 * @param pchWord The current position. Must be at the start of the
3617 * variable name.
3618 * @param cchLeft The number of chars left to parse in the current line.
3619 * @param pcchLeft The to store the updated count of characters left to
3620 * parse.
3621 * @param pfPlain Where to store the plain variable name indicator.
3622 * Returns 0 if plain, and 1 if there are variable
3623 * references in it.
3624 */
3625static const char *kmk_cc_eval_skip_var_name(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft,
3626 size_t *pcchLeft, int *pfPlain)
3627{
3628 const char * const pszContent = pCompiler->pszContent;
3629 size_t off = pchWord - pszContent;
3630 size_t const offLineEnd = off + cchLeft;
3631 int fPlain = 1;
3632 unsigned iEscEol = pCompiler->iEscEol;
3633
3634 /* Check our expectations. */
3635 KMK_CC_ASSERT(cchLeft);
3636 KMK_CC_ASSERT(!KMK_CC_EVAL_IS_SPACE(*pchWord));
3637 KMK_CC_ASSERT(iEscEol <= pCompiler->cEscEols);
3638 KMK_CC_ASSERT( iEscEol >= pCompiler->cEscEols
3639 || off < pCompiler->paEscEols[iEscEol].offEol);
3640 KMK_CC_ASSERT(off >= (iEscEol == 0 ? pCompiler->offLine : pCompiler->paEscEols[iEscEol - 1].offEol + pCompiler->cchEolSeq));
3641
3642 /*
3643 * The outer loop parses plain text. Variable expansion ($) is handled
3644 * by an inner loop.
3645 */
3646 while (off < offLineEnd)
3647 {
3648 char ch = pszContent[off];
3649 if (!KMK_CC_EVAL_IS_SPACE_OR_VAR_OR_RECIPE(ch))
3650 off++;
3651 else
3652 {
3653 if (KMK_CC_EVAL_IS_SPACE(ch))
3654 break;
3655
3656 if (ch == '$')
3657 {
3658 off++;
3659 if (off < offLineEnd)
3660 {
3661 char const chOpen = pszContent[off];
3662 if (chOpen == '(' || chOpen == '{')
3663 {
3664 /*
3665 * Got a $(VAR) or ${VAR} to deal with here. This may
3666 * include nested variable references and span multiple
3667 * lines (at least for function calls).
3668 *
3669 * We scan forward till we've found the corresponding
3670 * closing parenthesis, considering any open parentheses
3671 * of the same kind as worth counting, even if there are
3672 * no dollar preceeding them, just like GNU make does.
3673 */
3674 size_t const offStart = off - 1;
3675 char const chClose = chOpen == '(' ? ')' : '}';
3676 unsigned cOpen = 1;
3677 for (;;)
3678 {
3679 if (off < offLineEnd)
3680 {
3681 ch = pszContent[off];
3682 if (!(KMK_CC_EVAL_IS_PAREN_OR_SLASH(ch)))
3683 off++;
3684 else
3685 {
3686 off++;
3687 if (ch == chClose)
3688 {
3689 if (--cOpen == 0)
3690 break;
3691 }
3692 else if (ch == chOpen)
3693 cOpen++;
3694 else if ( ch == '\\'
3695 && iEscEol < pCompiler->cEscEols
3696 && off == pCompiler->paEscEols[iEscEol].offEsc)
3697 {
3698 off = pCompiler->paEscEols[iEscEol].offEsc + pCompiler->cchEolSeq;
3699 iEscEol++;
3700 pCompiler->iEscEol = iEscEol;
3701 }
3702 }
3703 }
3704 else if (cOpen == 1)
3705 kmk_cc_eval_fatal(pCompiler, &pszContent[offStart],
3706 "Variable reference is missing '%c'", chClose);
3707 else
3708 kmk_cc_eval_fatal(pCompiler, &pszContent[offStart],
3709 "%u variable references are missing '%c'", cOpen, chClose);
3710 }
3711 }
3712 /* Single char variable name. */
3713 else if (!KMK_CC_EVAL_IS_SPACE(chOpen))
3714 { /* likely */ }
3715 else
3716 kmk_cc_eval_fatal(pCompiler, &pszContent[off], "Expected variable name after '$', not end of line");
3717 }
3718 else
3719 kmk_cc_eval_fatal(pCompiler, &pszContent[off], "Expected variable name after '$', not end of line");
3720 fPlain = 0;
3721 }
3722 /* Deal with potential escaped EOL. */
3723 else if ( ch != '\\'
3724 || iEscEol >= pCompiler->cEscEols
3725 || off != pCompiler->paEscEols[iEscEol].offEsc )
3726 off++;
3727 else
3728 break;
3729 }
3730 }
3731
3732 *pcchLeft = offLineEnd - off;
3733 *pfPlain = fPlain;
3734 return &pszContent[off];
3735}
3736
3737
3738#if 0 /* unused atm */
3739/**
3740 * Prepares for copying a command line.
3741 *
3742 * The current version of this code will not modify any of the paEscEols
3743 * entries, unlike our kmk_cc_eval_prep_normal_line sibling function.
3744 *
3745 * @returns The number of chars that will be copied by
3746 * kmk_cc_eval_copy_prepped_command_line().
3747 * @param pCompiler The compiler instance data.
3748 * @param pchLeft Pointer to the first char to copy from the current line.
3749 * This does not have to the start of a word.
3750 * @param cchLeft The number of chars left on the current line starting at
3751 * @a pchLeft.
3752 */
3753static size_t kmk_cc_eval_prep_command_line(PKMKCCEVALCOMPILER pCompiler, const char * const pchLeft, size_t cchLeft)
3754{
3755 size_t cchRet;
3756 unsigned iEscEol = pCompiler->iEscEol;
3757 unsigned const cEscEols = pCompiler->cEscEols;
3758
3759 KMK_CC_ASSERT(cchLeft > 0);
3760 KMK_CC_ASSERT(iEscEol <= cEscEols);
3761
3762 if (iEscEol >= cEscEols)
3763 {
3764 /*
3765 * No escaped EOLs left, dead simple.
3766 */
3767 cchRet = cchLeft;
3768 }
3769 else
3770 {
3771 /*
3772 * Compared to the normal prepping of a line, this is actually
3773 * really simple. We need to account for two kind of conversions:
3774 * - One leading tab is skipped after escaped EOL.
3775 * - Convert EOL to LF.
3776 */
3777 const char * const pszContent = pCompiler->pszContent;
3778 size_t const cchEolSeq = pCompiler->cchEolSeq;
3779
3780#ifdef KMK_CC_STRICT
3781 size_t const offLeft = pchLeft - pszContent;
3782 KMK_CC_ASSERT(offLeft + cchLeft <= pCompiler->offLine + pCompiler->cchLine);
3783 KMK_CC_ASSERT(offLeft + cchLeft <= pCompiler->cchContent);
3784 KMK_CC_ASSERT(offLeft < pCompiler->paEscEols[iEscEol].offEsc);
3785 KMK_CC_ASSERT(offLeft >= (iEscEol ? pCompiler->paEscEols[cEscEols - 1].offEol + pCompiler->cchEolSeq : pCompiler->offLine));
3786#endif
3787
3788 cchRet = cchLeft;
3789 if (cchEolSeq > 1)
3790 cchRet -= (cchEolSeq - 1) * cEscEols;
3791 do
3792 {
3793 if (pszContent[pCompiler->paEscEols[cchEolSeq].offEol])
3794 cchRet--;
3795 iEscEol++;
3796 } while (iEscEol < cEscEols);
3797 }
3798 return cchRet;
3799}
3800
3801
3802/**
3803 * Copies a command line to the buffer @a pszDst points to.
3804 *
3805 * Must only be used immediately after kmk_cc_eval_prep_command_line().
3806 *
3807 * @returns
3808 * @param pCompiler The compiler instance data.
3809 * @param pchLeft Pointer to the first char to copy from the current line.
3810 * This does not have to the start of a word.
3811 * @param cchPrepped The return value of kmk_cc_eval_prep_command_line().
3812 * @param pszDst The destination buffer, must be at least @a cchPrepped
3813 * plus one (terminator) char big.
3814 */
3815static void kmk_cc_eval_copy_prepped_command_line(PKMKCCEVALCOMPILER pCompiler, const char *pchLeft,
3816 size_t cchPrepped, char *pszDst)
3817{
3818 unsigned iEscEol = pCompiler->iEscEol;
3819 unsigned const cEscEols = pCompiler->cEscEols;
3820 if (iEscEol >= cEscEols)
3821 {
3822 /* Single line. */
3823 memcpy(pszDst, pchLeft, cchPrepped);
3824 pszDst[cchPrepped] = '\0';
3825 }
3826 else
3827 {
3828 /* Multiple lines with normalized EOL and maybe one stripped leading TAB. */
3829 char * const pszDstStart = pszDst;
3830 const char * const pszContent = pCompiler->pszContent;
3831 size_t const cchEolSeq = pCompiler->cchEolSeq;
3832 size_t offLeft = pchLeft - pCompiler->pszContent;
3833 size_t cchCopy;
3834
3835 do
3836 {
3837 size_t offEol = pCompiler->paEscEols[iEscEol].offEsc;
3838 cchCopy = offEol - offLeft;
3839 KMK_CC_ASSERT(offEol >= offLeft);
3840
3841 memcpy(pszDst, &pszContent[offLeft], cchCopy);
3842 pszDst += cchCopy;
3843 *pszDst += '\n';
3844
3845 offLeft = offEol + cchEolSeq;
3846 if (pszContent[offLeft] == '\t')
3847 offLeft++;
3848 } while (iEscEol < cEscEols);
3849
3850 cchCopy = cchPrepped - (pszDst - pszDstStart);
3851 KMK_CC_ASSERT(cchCopy <= cchPrepped);
3852 memcpy(pszDst, &pszContent[offLeft], cchCopy);
3853 pszDst += cchCopy;
3854
3855 *pszDst = '\0';
3856 KMK_CC_ASSERT(pszDst == &pszDstStart[cchPrepped]);
3857 }
3858}
3859#endif /* unused atm */
3860
3861
3862/**
3863 * Gather string from segments and optional space insertion trick.
3864 *
3865 * @param pszDst The destination buffer.
3866 * @param paSegs The source segments.
3867 * @param cSegs The number of segments.
3868 * @param cchDstPrepped The size of pszDst, excluding the terminator.
3869 */
3870static void kmk_cc_eval_strcpyv(char *pszDst, PCKMKCCEVALSTRCPYSEG paSegs, unsigned cSegs, size_t cchDstPrepped)
3871{
3872 const char *pszDstStart = pszDst;
3873 unsigned iSeg = 0;
3874 while (iSeg < cSegs)
3875 {
3876 size_t cchToCopy;
3877 if (paSegs[iSeg].cchSrcAndPrependSpace >= 0)
3878 cchToCopy = paSegs[iSeg].cchSrcAndPrependSpace;
3879 else
3880 {
3881 cchToCopy = -paSegs[iSeg].cchSrcAndPrependSpace;
3882 *pszDst++ = ' ';
3883 }
3884
3885 memcpy(pszDst, paSegs[iSeg].pchSrc, cchToCopy);
3886 pszDst += cchToCopy;
3887
3888 iSeg++;
3889 }
3890 *pszDst = '\0';
3891 KMK_CC_ASSERT(pszDst == &pszDstStart[cchDstPrepped]); K_NOREF(pszDstStart); K_NOREF(cchDstPrepped);
3892}
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 */
3904static 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 */
3919static 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
3978/**
3979 * Helper for ensuring that we've got sufficient number of string copy segments.
3980 */
3981#define KMK_CC_EVAL_ENSURE_STRCOPY_SEGS(a_pCompiler, a_cRequiredSegs) \
3982 do { \
3983 if ((a_cRequiredSegs) < (a_pCompiler)->cStrCopySegsAllocated) \
3984 { /* likely */ } \
3985 else \
3986 { \
3987 unsigned cEnsureSegs = ((a_cRequiredSegs) + 3 /*15*/) & ~(unsigned)3/*15*/; \
3988 KMK_CC_ASSERT((a_cRequiredSegs) < 0x8000); \
3989 (a_pCompiler)->paStrCopySegs = (PKMKCCEVALSTRCPYSEG)xmalloc(cEnsureSegs * sizeof((a_pCompiler)->paStrCopySegs)[0]); \
3990 } \
3991 } while (0)
3992
3993
3994/**
3995 * Prepares for copying a normal line, extended version.
3996 *
3997 * This does not assume that we start on a word, it can handle any starting
3998 * character. It can also prepare partial copies.
3999 *
4000 * In addition to the returned information, this will store instruction in
4001 * paEscEols for the following kmk_cc_eval_strcpyv() call.
4002 *
4003 * This will advance pCompiler->iEscEol, so that it's possible to use the common
4004 * macros and helpers for parsing what comes afterwards.
4005 *
4006 * @returns The number of chars that will be copied by kmk_cc_eval_strcpyv().
4007 * @param pCompiler The compiler instance data.
4008 * @param pchWord Pointer to the first char to copy from the
4009 * current line. This must be the start of a
4010 * word.
4011 * @param cchLeft The number of chars left on the current line
4012 * starting at @a pchWord.
4013 */
4014static size_t kmk_cc_eval_prep_normal_line_ex(PKMKCCEVALCOMPILER pCompiler, const char * const pchWord, size_t cchLeft)
4015{
4016 size_t cchRet;
4017 unsigned iEscEol = pCompiler->iEscEol;
4018 unsigned const cEscEols = pCompiler->cEscEols;
4019
4020 KMK_CC_ASSERT(iEscEol <= cEscEols);
4021
4022 if (cchLeft > 0)
4023 {
4024 /*
4025 * If there are no escaped EOLs left, just copy exactly
4026 * what was passed in.
4027 */
4028 if (iEscEol >= cEscEols)
4029 {
4030 KMK_CC_EVAL_ENSURE_STRCOPY_SEGS(pCompiler, 1);
4031 pCompiler->cStrCopySegs = 1;
4032 pCompiler->paStrCopySegs[0].pchSrc = pchWord;
4033 pCompiler->paStrCopySegs[0].cchSrcAndPrependSpace = cchRet = cchLeft;
4034 }
4035 /*
4036 * Ok, we have to deal with escaped EOLs and do the proper
4037 * replacement of escaped newlines with space. The deal is that we
4038 * collaps all whitespace before and after one or more newlines into a
4039 * single space. (FreeBSD make does this differently, by the by.)
4040 */
4041 else
4042 {
4043 const char * const pszContent = pCompiler->pszContent;
4044 size_t offWord = pchWord - pCompiler->pszContent;
4045 size_t const offLineEnd = offWord + cchLeft; /* Note! Not necessarily end of line.*/
4046 size_t offEsc;
4047 size_t fPendingSpace = 0;
4048 unsigned cSegs = 0;
4049 size_t cchSeg;
4050
4051 /* Go nuts checking our preconditions here. */
4052 KMK_CC_ASSERT(offWord >= pCompiler->offLine);
4053 KMK_CC_ASSERT(offWord + cchLeft <= pCompiler->offLine + pCompiler->cchLine);
4054 KMK_CC_ASSERT(offWord + cchLeft <= pCompiler->cchContent);
4055 KMK_CC_ASSERT(offWord <= pCompiler->paEscEols[iEscEol].offEsc);
4056 KMK_CC_ASSERT(offWord >= (iEscEol ? pCompiler->paEscEols[cEscEols - 1].offEol + pCompiler->cchEolSeq
4057 : pCompiler->offLine));
4058 KMK_CC_ASSERT(offWord < offLineEnd);
4059
4060 /* Make sure we've got more than enough segments to fill in. */
4061 KMK_CC_EVAL_ENSURE_STRCOPY_SEGS(pCompiler, cEscEols - iEscEol + 2);
4062
4063 /*
4064 * All but the last line.
4065 */
4066 cchRet = 0;
4067 do
4068 {
4069 KMK_CC_ASSERT(offWord < offLineEnd);
4070 offEsc = pCompiler->paEscEols[iEscEol].offEsc;
4071 if (offWord < offEsc)
4072 {
4073 /* Strip trailing spaces. */
4074 while (offEsc > offWord && KMK_CC_EVAL_IS_SPACE(pszContent[offEsc - 1]))
4075 offEsc--;
4076 cchSeg = offEsc - offWord;
4077 if (cchSeg)
4078 {
4079 /* Add segment. */
4080 pCompiler->paStrCopySegs[cSegs].pchSrc = &pszContent[offWord];
4081 if (offEsc < offLineEnd)
4082 {
4083 pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = fPendingSpace
4084 ? -(ssize_t)cchSeg : (ssize_t)cchSeg;
4085 cchRet += cchSeg + fPendingSpace;
4086 cSegs += 1;
4087 fPendingSpace = 1;
4088 }
4089 else
4090 {
4091 cchSeg = offLineEnd - offWord;
4092 pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = fPendingSpace
4093 ? -(ssize_t)cchSeg : (ssize_t)cchSeg;
4094 pCompiler->cStrCopySegs = cSegs + 1;
4095 pCompiler->iEscEol = iEscEol;
4096 return cchRet + cchSeg + fPendingSpace;
4097 }
4098 }
4099 }
4100 else
4101 KMK_CC_ASSERT(offWord == offEsc);
4102
4103 /* Next line. */
4104 offWord = pCompiler->paEscEols[iEscEol].offEol + pCompiler->cchEolSeq;
4105 iEscEol++;
4106
4107 /* Strip leading spaces. */
4108 while (offWord < offLineEnd && KMK_CC_EVAL_IS_SPACE(pszContent[offWord]))
4109 offWord++;
4110 if (offWord >= offLineEnd)
4111 {
4112 pCompiler->cStrCopySegs = cSegs;
4113 pCompiler->iEscEol = iEscEol;
4114 return cchRet;
4115 }
4116 } while (iEscEol < cEscEols);
4117
4118 /*
4119 * The last line.
4120 */
4121 cchSeg = offLineEnd - offWord;
4122 cchRet += cchSeg;
4123 pCompiler->paStrCopySegs[cSegs].pchSrc = &pszContent[offWord];
4124 pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = fPendingSpace
4125 ? -(ssize_t)cchSeg : (ssize_t)cchSeg;
4126 pCompiler->cStrCopySegs = cSegs + 1;
4127 pCompiler->iEscEol = iEscEol;
4128 }
4129 }
4130 /*
4131 * Odd case: Nothing to copy.
4132 */
4133 else
4134 {
4135 cchRet = 0;
4136 pCompiler->cStrCopySegs = 0;
4137 }
4138 return cchRet;
4139}
4140
4141
4142/**
4143 * Prepares for copying a normal line, from the given position all the way to
4144 * the end.
4145 *
4146 * In addition to the returned information, this will store instruction in
4147 * paStrCopySegs and cSTrCopySeg for the following kmk_cc_eval_strcpyv() call.
4148 *
4149 * @returns The number of chars that will be copied by kmk_cc_eval_strcpyv().
4150 * @param pCompiler The compiler instance data.
4151 * @param pchWord Pointer to the first char to copy from the
4152 * current line. This must be the start of a
4153 * word.
4154 * @param cchLeft The number of chars left on the current line
4155 * starting at @a pchWord.
4156 * @param fStripTrailingSpaces Whether to strip trailing spaces.
4157 */
4158static size_t kmk_cc_eval_prep_normal_line(PKMKCCEVALCOMPILER pCompiler, const char * const pchWord, size_t cchLeft,
4159 int fStripTrailingSpaces)
4160{
4161 size_t cchRet;
4162 unsigned iEscEol = pCompiler->iEscEol;
4163 unsigned const cEscEols = pCompiler->cEscEols;
4164
4165 KMK_CC_ASSERT(cchLeft > 0);
4166 KMK_CC_ASSERT(!KMK_CC_EVAL_IS_SPACE(*pchWord)); /* The fact that we're standing at a word, is exploited below. */
4167 KMK_CC_ASSERT(iEscEol <= cEscEols);
4168
4169 /*
4170 * If there are no escaped EOLs left, just copy what was specified,
4171 * optionally sans any trailing spaces.
4172 */
4173 if (iEscEol >= cEscEols)
4174 {
4175 cchRet = cchLeft;
4176 if (fStripTrailingSpaces)
4177 while (cchRet > 0 && KMK_CC_IS_SPACE_CH(pchWord[cchRet - 1]))
4178 cchRet--;
4179
4180 KMK_CC_EVAL_ENSURE_STRCOPY_SEGS(pCompiler, 1);
4181 pCompiler->cStrCopySegs = 1;
4182 pCompiler->paStrCopySegs[0].pchSrc = pchWord;
4183 pCompiler->paStrCopySegs[0].cchSrcAndPrependSpace = cchRet;
4184 }
4185 /*
4186 * Ok, we have to deal with escaped EOLs and do the proper
4187 * replacement of escaped newlines with space. The deal is that we
4188 * collaps all whitespace before and after one or more newlines into a
4189 * single space. (FreeBSD make does this differently, by the by.)
4190 */
4191 else
4192 {
4193 const char *pszContent = pCompiler->pszContent;
4194 size_t offWord = pchWord - pCompiler->pszContent;
4195 size_t offEsc;
4196 size_t fPendingSpace;
4197 size_t cchSeg;
4198 unsigned cSegs = 0;
4199
4200 /* Go nuts checking our preconditions here. */
4201 KMK_CC_ASSERT(offWord >= pCompiler->offLine);
4202 KMK_CC_ASSERT(offWord + cchLeft <= pCompiler->offLine + pCompiler->cchLine);
4203 KMK_CC_ASSERT(offWord + cchLeft <= pCompiler->cchContent);
4204 KMK_CC_ASSERT(offWord < pCompiler->paEscEols[iEscEol].offEsc);
4205 KMK_CC_ASSERT(offWord >= (iEscEol ? pCompiler->paEscEols[cEscEols - 1].offEol + pCompiler->cchEolSeq : pCompiler->offLine));
4206
4207 /* Make sure we've got more than enough segments to fill in. */
4208 KMK_CC_EVAL_ENSURE_STRCOPY_SEGS(pCompiler, cEscEols - iEscEol + 2);
4209
4210 /*
4211 * First line - We're at the start of a word, so no left stripping needed.
4212 */
4213 offEsc = pCompiler->paEscEols[iEscEol].offEsc;
4214 KMK_CC_ASSERT(offEsc > offWord);
4215 while (KMK_CC_EVAL_IS_SPACE(pszContent[offEsc - 1]))
4216 offEsc--;
4217 KMK_CC_ASSERT(offEsc > offWord);
4218
4219 fPendingSpace = 1;
4220 cchRet = offEsc - offWord;
4221 pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = cchRet;
4222 pCompiler->paStrCopySegs[cSegs].pchSrc = pchWord;
4223
4224 offWord = pCompiler->paEscEols[iEscEol].offEol + pCompiler->cchEolSeq;
4225 iEscEol++;
4226
4227 /*
4228 * All but the last line.
4229 */
4230 while (iEscEol < cEscEols)
4231 {
4232 offEsc = pCompiler->paEscEols[iEscEol].offEsc;
4233
4234 /* Strip leading spaces. */
4235 while (offWord < offEsc && KMK_CC_EVAL_IS_SPACE(pszContent[offWord]))
4236 offWord++;
4237
4238 if (offWord < offEsc)
4239 {
4240 /* Strip trailing spaces. */
4241 while (KMK_CC_EVAL_IS_SPACE(pszContent[offEsc - 1]))
4242 offEsc--;
4243 cchSeg = offEsc - offWord;
4244 pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = fPendingSpace ? -(ssize_t)cchSeg : (ssize_t)cchSeg;
4245 cchRet += cchSeg + fPendingSpace;
4246 pCompiler->paStrCopySegs[cSegs].pchSrc = &pszContent[offWord];
4247 cSegs += 1;
4248 fPendingSpace = 1;
4249 }
4250
4251 /* Next. */
4252 offWord = pCompiler->paEscEols[iEscEol].offEol + pCompiler->cchEolSeq;
4253 iEscEol++;
4254 }
4255
4256 /*
4257 * Final line. We must calculate the end of line offset our selves here.
4258 */
4259 offEsc = &pchWord[cchLeft] - pszContent;
4260 while (offWord < offEsc && KMK_CC_EVAL_IS_SPACE(pszContent[offWord]))
4261 offWord++;
4262
4263 if (offWord < offEsc)
4264 {
4265 if (fStripTrailingSpaces)
4266 while (KMK_CC_EVAL_IS_SPACE(pszContent[offEsc - 1]))
4267 offEsc--;
4268 cchSeg = offEsc - offWord;
4269 pCompiler->paStrCopySegs[cSegs].cchSrcAndPrependSpace = fPendingSpace ? -(ssize_t)cchSeg : (ssize_t)cchSeg;
4270 cchRet += cchSeg + fPendingSpace;
4271 pCompiler->paStrCopySegs[cSegs].pchSrc = &pszContent[offWord];
4272 cSegs += 1;
4273 }
4274
4275 pCompiler->cStrCopySegs = cSegs;
4276 }
4277 return cchRet;
4278}
4279
4280
4281/**
4282 * Common worker for all kmk_cc_eval_do_if*() functions.
4283 *
4284 * @param pCompiler The compiler state.
4285 * @param pIfCore The new IF statement.
4286 * @param fInElse Set if this is an 'else if' (rather than just 'if').
4287 */
4288static void kmk_cc_eval_do_if_core(PKMKCCEVALCOMPILER pCompiler, PKMKCCEVALIFCORE pIfCore, int fInElse)
4289{
4290 unsigned iIf = pCompiler->cIfs;
4291 if (!fInElse)
4292 {
4293 /* Push an IF statement. */
4294 if (iIf < KMK_CC_EVAL_MAX_IF_DEPTH)
4295 {
4296 pCompiler->cIfs = iIf + 1;
4297 pCompiler->apIfs[iIf] = pIfCore;
4298 pIfCore->pPrevCond = NULL;
4299 }
4300 else
4301 kmk_cc_eval_fatal(pCompiler, NULL, "Too deep IF nesting");
4302 }
4303 else if (iIf > 0)
4304 {
4305 /* Link an IF statement. */
4306 iIf--;
4307 pIfCore->pPrevCond = pCompiler->apIfs[iIf];
4308 pCompiler->apIfs[iIf] = pIfCore;
4309 }
4310 else
4311 kmk_cc_eval_fatal(pCompiler, NULL, "'else if' without 'if'");
4312 pIfCore->pNextTrue = (PKMKCCEVALCORE)kmk_cc_block_get_next_ptr(*pCompiler->ppBlockTail);
4313 pIfCore->pNextFalse = NULL; /* This is set by else or endif. */
4314 pIfCore->pTrueEndJump = NULL; /* This is set by else or endif. */
4315}
4316
4317
4318/**
4319 * Deals with 'if expr' and 'else if expr' statements.
4320 *
4321 * @returns 1 to indicate we've handled a keyword (see
4322 * kmk_cc_eval_try_handle_keyword).
4323 * @param pCompiler The compiler state.
4324 * @param pchWord First char after 'if'.
4325 * @param cchLeft The number of chars left to parse on this line.
4326 * @param fInElse Set if this is an 'else if' (rather than just 'if').
4327 */
4328static int kmk_cc_eval_do_if(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, int fInElse)
4329{
4330 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
4331 if (cchLeft)
4332 {
4333 size_t cchExpr = kmk_cc_eval_prep_normal_line(pCompiler, pchWord, cchLeft, 1 /*fStripTrailingSpaces*/);
4334 PKMKCCEVALIFEXPR pInstr = (PKMKCCEVALIFEXPR)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail,
4335 KMKCCEVALIFEXPR_SIZE(cchExpr));
4336 kmk_cc_eval_strcpyv(pInstr->szExpr, pCompiler->paStrCopySegs, pCompiler->cStrCopySegs, cchExpr);
4337 pInstr->cchExpr = cchExpr;
4338 pInstr->IfCore.Core.enmOpCode = kKmkCcEvalInstr_if;
4339 pInstr->IfCore.Core.iLine = pCompiler->iLine;
4340 kmk_cc_eval_do_if_core(pCompiler, &pInstr->IfCore, fInElse);
4341 }
4342 else
4343 kmk_cc_eval_fatal(pCompiler, pchWord, "Expected expression after 'if' directive");
4344 return 1;
4345}
4346
4347
4348/**
4349 * Deals with 'ifdef var', 'ifndef var', 'else ifdef var' and 'else ifndef var'
4350 * statements.
4351 *
4352 * @returns 1 to indicate we've handled a keyword (see
4353 * kmk_cc_eval_try_handle_keyword).
4354 * @param pCompiler The compiler state.
4355 * @param pchWord First char after 'if[n]def'.
4356 * @param cchLeft The number of chars left to parse on this line.
4357 * @param fInElse Set if this is an 'else if' (rather than just 'if').
4358 * @param fPositiveStmt Set if 'ifdef', clear if 'ifndef'.
4359 */
4360static int kmk_cc_eval_do_ifdef(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, int fInElse, int fPositiveStmt)
4361{
4362 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
4363 if (cchLeft)
4364 {
4365 /*
4366 * Skip to the end of the variable name.
4367 */
4368 unsigned const iSavedEscEol = pCompiler->iEscEol;
4369 const char * const pchVarNm = pchWord;
4370 int fPlain;
4371 pchWord = kmk_cc_eval_skip_var_name(pCompiler, pchWord, cchLeft, &cchLeft, &fPlain);
4372 KMK_CC_ASSERT(pCompiler->iEscEol == iSavedEscEol || !fPlain);
4373 if (fPlain)
4374 {
4375 size_t const cchVarNm = pchWord - pchVarNm;
4376 PKMKCCEVALIFDEFPLAIN pInstr;
4377 pInstr = (PKMKCCEVALIFDEFPLAIN)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr));
4378 pInstr->IfCore.Core.enmOpCode = fPositiveStmt ? kKmkCcEvalInstr_ifdef_plain : kKmkCcEvalInstr_ifndef_plain;
4379 pInstr->IfCore.Core.iLine = pCompiler->iLine;
4380 pInstr->pszName = strcache2_add(&variable_strcache, pchVarNm, cchVarNm);
4381 kmk_cc_eval_do_if_core(pCompiler, &pInstr->IfCore, fInElse);
4382 }
4383 else
4384 {
4385 PKMKCCEVALIFDEFDYNAMIC pInstr;
4386 size_t const cchVarNm = pchWord - pchVarNm;
4387 size_t cchCopy;
4388 char *pszCopy;
4389 pCompiler->iEscEol = iSavedEscEol;
4390 cchCopy = kmk_cc_eval_prep_normal_line(pCompiler, pchVarNm, cchVarNm, 0 /*fStripTrailingSpaces*/);
4391
4392 pInstr = (PKMKCCEVALIFDEFDYNAMIC)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr));
4393
4394 /** @todo Make the subprogram embed necessary strings. */
4395 pszCopy = kmk_cc_eval_strdup_prepped(pCompiler, cchCopy);
4396 kmk_cc_block_realign(pCompiler->ppBlockTail);
4397
4398 pInstr->IfCore.Core.enmOpCode = fPositiveStmt ? kKmkCcEvalInstr_ifdef_dynamic : kKmkCcEvalInstr_ifndef_dynamic;
4399 pInstr->IfCore.Core.iLine = pCompiler->iLine;
4400 kmk_cc_eval_compile_string_exp_subprog(pCompiler, pszCopy, cchCopy, &pInstr->NameSubprog);
4401
4402 kmk_cc_eval_do_if_core(pCompiler, &pInstr->IfCore, fInElse);
4403 }
4404
4405 /*
4406 * Make sure there is nothing following the variable name.
4407 */
4408 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
4409 if (cchLeft)
4410 kmk_cc_eval_fatal(pCompiler, pchWord, "Bogus stuff after 'if%sdef' variable name", fPositiveStmt ? "" : "n");
4411 }
4412 else
4413 kmk_cc_eval_fatal(pCompiler, pchWord, "Expected expression after 'if' directive");
4414 return 1;
4415}
4416
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 */
4431static int kmk_cc_eval_do_ifeq(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, int fInElse, int fPositiveStmt)
4432{
4433 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
4434 if (cchLeft)
4435 {
4436 /*
4437 * There are two forms:
4438 *
4439 * ifeq (string1, string2)
4440 * ifeq "string1" 'string2'
4441 *
4442 */
4443 const char * const pchEnd = &pchWord[cchLeft];
4444 PKMKCCEVALIFEQ pInstr = (PKMKCCEVALIFEQ)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr));
4445
4446 struct
4447 {
4448 char *pszCopy;
4449 size_t cchCopy;
4450 int fPlain;
4451 } Left, Right;
4452
4453 char ch = *pchWord;
4454 if (ch == '(')
4455 {
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 */
4463
4464 /* Skip the parenthesis. */
4465 pchWord++;
4466 cchLeft--;
4467
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;
4535 }
4536 else if (ch == '"' || ch == '\'')
4537 {
4538 const char *pchTmp;
4539
4540 /*
4541 * Quoted left side.
4542 */
4543 /* Skip leading quote. */
4544 pchWord++;
4545 cchLeft--;
4546
4547 /* Locate the end quote. */
4548 pchTmp = (const char *)memchr(pchWord, ch, cchLeft);
4549 if (pchTmp) { /* likely */ }
4550 else kmk_cc_eval_fatal(pCompiler, pchWord - 1, "Unbalanced quote in first if%seq string", fPositiveStmt ? "" : "n");
4551
4552 Left.cchCopy = kmk_cc_eval_prep_normal_line_ex(pCompiler, pchWord, pchTmp - pchWord);
4553 Left.pszCopy = kmk_cc_eval_strdup_prepped(pCompiler, Left.cchCopy);
4554 Left.fPlain = memchr(Left.pszCopy, '$', Left.cchCopy) == NULL;
4555
4556 /* skip end quote */
4557 pchWord = pchTmp + 1;
4558 cchLeft = pchEnd - pchWord;
4559
4560 /* Skip anything inbetween the left and right hand side (not mandatory). */
4561 if ( cchLeft /** @todo replace with straight 'isspace' that takes escaped EOLs into account. */
4562 && KMK_CC_EVAL_IS_SPACE_AFTER_WORD(pCompiler, pchWord[0], pchWord[1], cchLeft))
4563 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
4564
4565 /*
4566 * Quoted right side.
4567 */
4568 if ( cchLeft > 0
4569 && ( (ch = *pchWord) != '"' || ch == '\'') )
4570 {
4571 /* Skip leading quote. */
4572 pchWord++;
4573 cchLeft--;
4574
4575 /* Locate the end quote. */
4576 pchTmp = (const char *)memchr(pchWord, ch, cchLeft);
4577 if (pchTmp) { /* likely */ }
4578 else kmk_cc_eval_fatal(pCompiler, pchWord - 1, "Unbalanced quote in second if%seq string", fPositiveStmt ? "" : "n");
4579
4580 Right.cchCopy = kmk_cc_eval_prep_normal_line_ex(pCompiler, pchWord, pchTmp - pchWord);
4581 Right.pszCopy = kmk_cc_eval_strdup_prepped(pCompiler, Right.cchCopy);
4582 Right.fPlain = memchr(Right.pszCopy, '$', Right.cchCopy) == NULL;
4583
4584 /* skip end quote */
4585 pchWord = pchTmp + 1;
4586 cchLeft = pchEnd - pchWord;
4587 }
4588 else
4589 kmk_cc_eval_fatal(pCompiler, pchWord, "Expected a second quoted string for 'if%seq'",
4590 fPositiveStmt ? "" : "n");
4591 }
4592 else
4593 kmk_cc_eval_fatal(pCompiler, pchWord, "Expected parentheses or quoted string after 'if%seq'",
4594 fPositiveStmt ? "" : "n");
4595 kmk_cc_block_realign(pCompiler->ppBlockTail);
4596
4597 /*
4598 * Initialize the instruction.
4599 */
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);
4605
4606 /*
4607 * Make sure there is nothing following the variable name.
4608 */
4609 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
4610 if (cchLeft)
4611 kmk_cc_eval_fatal(pCompiler, pchWord, "Bogus stuff after 'if%sdef' variable name", fPositiveStmt ? "" : "n");
4612 }
4613 else
4614 kmk_cc_eval_fatal(pCompiler, pchWord, "Expected expression after 'if' directive");
4615 return 1;
4616}
4617
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 */
4631static int kmk_cc_eval_do_if1of(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, int fInElse, int fPositiveStmt)
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");
4756 return 1;
4757}
4758
4759
4760/**
4761 * Deals with 'else' and 'else ifxxx' statements.
4762 *
4763 * @returns 1 to indicate we've handled a keyword (see
4764 * kmk_cc_eval_try_handle_keyword).
4765 * @param pCompiler The compiler state.
4766 * @param pchWord First char after 'define'.
4767 * @param cchLeft The number of chars left to parse on this line.
4768 */
4769static int kmk_cc_eval_do_else(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft)
4770{
4771 /*
4772 * There must be an 'if' on the stack.
4773 */
4774 unsigned iIf = pCompiler->cIfs;
4775 if (iIf > 0)
4776 {
4777 PKMKCCEVALIFCORE pIfCore = pCompiler->apIfs[--iIf];
4778 if (!pIfCore->pTrueEndJump)
4779 {
4780 /* Emit a jump instruction that will take us from the 'True' block to the 'endif'. */
4781 PKMKCCEVALJUMP pInstr = (PKMKCCEVALJUMP)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr));
4782 pInstr->Core.enmOpCode = kKmkCcEvalInstr_jump;
4783 pInstr->Core.iLine = pCompiler->iLine;
4784 pInstr->pNext = NULL;
4785 pIfCore->pTrueEndJump = pInstr;
4786
4787 /* The next instruction is the first in the 'False' block of the current 'if'.
4788 Should this be an 'else if', this will be the 'if' instruction emitted below. */
4789 pIfCore->pNextFalse = (PKMKCCEVALCORE)kmk_cc_block_get_next_ptr(*pCompiler->ppBlockTail);
4790 }
4791 else if (iIf == 0)
4792 kmk_cc_eval_fatal(pCompiler, pchWord, "2nd 'else' for 'if' at line %u", pIfCore->Core.iLine);
4793 else
4794 kmk_cc_eval_fatal(pCompiler, pchWord, "2nd 'else' in a row - missing 'endif' for 'if' at line %u?",
4795 pIfCore->Core.iLine);
4796 }
4797 else
4798 kmk_cc_eval_fatal(pCompiler, pchWord, "'else' without 'if'");
4799
4800 /*
4801 * Check for 'else ifxxx'. There can be nothing else following an else.
4802 */
4803 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
4804 if (cchLeft)
4805 {
4806 if ( cchLeft > 2
4807 && KMK_CC_WORD_COMP_CONST_2(pchWord, "if"))
4808 {
4809 pchWord += 2;
4810 cchLeft -= 2;
4811
4812 if (KMK_CC_WORD_COMP_IS_EOL(pCompiler, pchWord, cchLeft))
4813 return kmk_cc_eval_do_if(pCompiler, pchWord, cchLeft, 1 /* in else */);
4814
4815 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "eq", 2))
4816 return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 2, cchLeft - 2, 1 /* in else */, 1 /* positive */);
4817
4818 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "def", 3))
4819 return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 3, cchLeft - 3, 1 /* in else */, 1 /* positive */);
4820
4821 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "neq", 3))
4822 return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 3, cchLeft - 3, 1 /* in else */, 0 /* positive */);
4823
4824 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "1of", 3))
4825 return kmk_cc_eval_do_if1of(pCompiler, pchWord + 3, cchLeft - 3, 1 /* in else */, 1 /* positive */);
4826
4827 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "ndef", 4))
4828 return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 4, cchLeft - 4, 1 /* in else */, 0 /* positive */);
4829
4830 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "n1of", 4))
4831 return kmk_cc_eval_do_if1of(pCompiler, pchWord + 4, cchLeft - 4, 1 /* in else */, 0 /* positive */);
4832
4833 pchWord -= 2;
4834 cchLeft += 2;
4835 }
4836 kmk_cc_eval_fatal(pCompiler, pchWord, "Bogus stuff after 'else'");
4837 }
4838
4839 return 1;
4840}
4841
4842
4843/**
4844 * Deals with the 'endif' statement.
4845 *
4846 * @returns 1 to indicate we've handled a keyword (see
4847 * kmk_cc_eval_try_handle_keyword).
4848 * @param pCompiler The compiler state.
4849 * @param pchWord First char after 'define'.
4850 * @param cchLeft The number of chars left to parse on this line.
4851 */
4852static int kmk_cc_eval_do_endif(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft)
4853{
4854 /*
4855 * There must be an 'if' on the stack. We'll POP it.
4856 */
4857 unsigned iIf = pCompiler->cIfs;
4858 if (iIf > 0)
4859 {
4860 PKMKCCEVALCORE pNextInstr;
4861 PKMKCCEVALIFCORE pIfCore = pCompiler->apIfs[--iIf];
4862 pCompiler->cIfs = iIf; /* POP! */
4863
4864 /* Update the jump targets for all IFs at this level. */
4865 pNextInstr = (PKMKCCEVALCORE)kmk_cc_block_get_next_ptr(*pCompiler->ppBlockTail);
4866 do
4867 {
4868 if (pIfCore->pTrueEndJump)
4869 {
4870 /* Make the true block jump here, to the 'endif'. The false block is already here. */
4871 pIfCore->pTrueEndJump->pNext = pNextInstr;
4872 KMK_CC_ASSERT(pIfCore->pNextFalse);
4873 }
4874 else
4875 {
4876 /* No 'else'. The false-case jump here, to the 'endif'. */
4877 KMK_CC_ASSERT(!pIfCore->pNextFalse);
4878 pIfCore->pNextFalse = pNextInstr;
4879 }
4880
4881 pIfCore = pIfCore->pPrevCond;
4882 } while (pIfCore);
4883 }
4884 else
4885 kmk_cc_eval_fatal(pCompiler, pchWord, "'endif' without 'if'");
4886
4887 /*
4888 * There shouldn't be anything trailing an 'endif'.
4889 */
4890 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
4891 if (!cchLeft) { /* likely */ }
4892 else kmk_cc_eval_fatal(pCompiler, pchWord, "Bogus stuff after 'else'");
4893
4894 return 1;
4895}
4896
4897
4898static int kmk_cc_eval_do_include(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, KMKCCEVALINSTR enmInst)
4899{
4900 return 1;
4901}
4902
4903
4904static int kmk_cc_eval_do_vpath(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft)
4905{
4906 return 1;
4907}
4908
4909
4910static void kmk_cc_eval_handle_command(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft)
4911{
4912
4913}
4914
4915
4916static void kmk_cc_eval_handle_recipe(PKMKCCEVALCOMPILER pCompiler, const char *pszEqual, const char *pchWord, size_t cchLeft)
4917{
4918
4919}
4920
4921
4922/**
4923 * Parses a 'undefine variable [..]' expression.
4924 *
4925 * A 'undefine' directive is final, any qualifiers must preceed it. So, we just
4926 * have to extract the variable names now.
4927 *
4928 * @returns 1 to indicate we've handled a keyword (see
4929 * kmk_cc_eval_try_handle_keyword).
4930 * @param pCompiler The compiler state.
4931 * @param pchWord First char after 'define'.
4932 * @param cchLeft The number of chars left to parse on this line.
4933 * @param fQualifiers The qualifiers.
4934 */
4935static int kmk_cc_eval_do_var_undefine(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft,
4936 unsigned fQualifiers)
4937{
4938
4939 return 1;
4940}
4941
4942
4943/**
4944 * Parses a 'define variable' expression.
4945 *
4946 * A 'define' directive is final, any qualifiers must preceed it. So, we just
4947 * have to extract the variable name now, well and find the corresponding
4948 * 'endef'.
4949 *
4950 * @returns 1 to indicate we've handled a keyword (see
4951 * kmk_cc_eval_try_handle_keyword).
4952 * @param pCompiler The compiler state.
4953 * @param pchWord First char after 'define'.
4954 * @param cchLeft The number of chars left to parse on this line.
4955 * @param fQualifiers The qualifiers.
4956 */
4957static int kmk_cc_eval_do_var_define(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, unsigned fQualifiers)
4958{
4959
4960 return 1;
4961}
4962
4963
4964static int kmk_cc_eval_try_handle_assignment(PKMKCCEVALCOMPILER pCompiler, const char *pchTmp,
4965 const char *pchWord, size_t cchLeft, unsigned fQualifiers)
4966{
4967 return 0;
4968}
4969
4970
4971/**
4972 * Parses a 'local [override] variable = value' expression.
4973 *
4974 * The 'local' directive must be first and it does not permit any qualifiers at
4975 * the moment. Should any be added later, they will have to come after 'local'.
4976 *
4977 * @returns 1 to indicate we've handled a keyword (see
4978 * kmk_cc_eval_try_handle_keyword).
4979 * @param pCompiler The compiler state.
4980 * @param pchWord First char after 'define'.
4981 * @param cchLeft The number of chars left to parse on this line.
4982 * @param fQualifiers The qualifiers.
4983 */
4984static int kmk_cc_eval_do_var_local(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft)
4985{
4986
4987 return 1;
4988}
4989
4990
4991/**
4992 * Parses 'export [variable]' and 'export [qualifiers] variable = value'
4993 * expressions.
4994 *
4995 * When we find the 'export' directive at the start of a line, we need to
4996 * continue parsing with till we can tell the difference between the two forms.
4997 *
4998 * @returns 1 to indicate we've handled a keyword (see
4999 * kmk_cc_eval_try_handle_keyword).
5000 * @param pCompiler The compiler state.
5001 * @param pchWord First char after 'define'.
5002 * @param cchLeft The number of chars left to parse on this line.
5003 * @param fQualifiers The qualifiers.
5004 */
5005static int kmk_cc_eval_handle_var_export(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, unsigned fQualifiers)
5006{
5007
5008 return 1;
5009}
5010
5011
5012/**
5013 * We've found one variable qualification keyword, now continue parsing and see
5014 * if this is some kind of variable assignment expression or not.
5015 *
5016 * @returns 1 if variable assignment, 0 if not.
5017 * @param pCompiler The compiler state.
5018 * @param pchWord First char after the first qualifier.
5019 * @param cchLeft The number of chars left to parse on this line.
5020 * @param fQualifiers The qualifier.
5021 */
5022static int kmk_cc_eval_try_handle_var_with_keywords(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft,
5023 unsigned fQualifiers)
5024{
5025 for (;;)
5026 {
5027 KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
5028 if (cchLeft)
5029 {
5030 char ch = *pchWord;
5031 if (KMK_CC_EVAL_IS_1ST_IN_VARIABLE_KEYWORD(ch))
5032 {
5033 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "define", 6)) /* final */
5034 return kmk_cc_eval_do_var_define(pCompiler, pchWord + 6, cchLeft - 6, fQualifiers);
5035
5036 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "export", 6)) /* special */
5037 return kmk_cc_eval_handle_var_export(pCompiler, pchWord + 6, cchLeft - 6, fQualifiers);
5038
5039 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "undefine", 8)) /* final */
5040 return kmk_cc_eval_do_var_undefine(pCompiler, pchWord + 6, cchLeft - 6, fQualifiers);
5041
5042 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "override", 8))
5043 {
5044 /** @todo warn if repeated. */
5045 fQualifiers |= KMK_CC_EVAL_QUALIFIER_OVERRIDE;
5046 pchWord += 8;
5047 cchLeft -= 8;
5048 continue;
5049 }
5050
5051 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "private", 7))
5052 {
5053 /** @todo warn if repeated. */
5054 fQualifiers |= KMK_CC_EVAL_QUALIFIER_PRIVATE;
5055 pchWord += 7;
5056 cchLeft -= 7;
5057 continue;
5058 }
5059 }
5060
5061 /*
5062 * Not a keyword, likely variable name followed by an assignment
5063 * operator and a value. Do a rough check for the assignment operator
5064 * and join paths with the unqualified assignment handling code.
5065 */
5066 {
5067 const char *pchEqual = (const char *)memchr(pchWord, '=', cchLeft);
5068 if (pchEqual)
5069 return kmk_cc_eval_try_handle_assignment(pCompiler, pchEqual, pchWord, cchLeft, fQualifiers);
5070 }
5071 return 0;
5072 }
5073 else
5074 kmk_cc_eval_fatal(pCompiler, NULL,
5075 "Expected assignment operator or variable directive after variable qualifier(s)\n");
5076 }
5077}
5078
5079
5080/**
5081 * When entering this function we know that the first two character in the first
5082 * word both independently occurs in keywords.
5083 *
5084 * @returns 1 if make directive or qualified variable assignment, 0 if neither.
5085 * @param pCompiler The compiler state.
5086 * @param ch The first char.
5087 * @param pchWord Pointer to the first word.
5088 * @param cchLeft Number of characters left to parse starting at
5089 * @a cchLeft.
5090 */
5091int kmk_cc_eval_try_handle_keyword(PKMKCCEVALCOMPILER pCompiler, char ch, const char *pchWord, size_t cchLeft)
5092{
5093 unsigned iSavedEscEol = pCompiler->iEscEol;
5094
5095 KMK_CC_ASSERT(cchLeft >= 2);
5096 KMK_CC_ASSERT(ch == pchWord[0]);
5097 KMK_CC_ASSERT(KMK_CC_EVAL_IS_1ST_IN_KEYWORD(pchWord[0]));
5098 KMK_CC_ASSERT(KMK_CC_EVAL_IS_2ND_IN_KEYWORD(pchWord[1]));
5099
5100 /*
5101 * If it's potentially a variable related keyword, check that out first.
5102 */
5103 if (KMK_CC_EVAL_IS_1ST_IN_VARIABLE_KEYWORD(ch))
5104 {
5105 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "local", 5))
5106 return kmk_cc_eval_do_var_local(pCompiler, pchWord + 5, cchLeft - 5);
5107 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "define", 6))
5108 return kmk_cc_eval_do_var_define(pCompiler, pchWord + 6, cchLeft - 6, 0);
5109 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "export", 6))
5110 return kmk_cc_eval_handle_var_export(pCompiler, pchWord + 6, cchLeft - 6, 0);
5111 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "undefine", 8))
5112 return kmk_cc_eval_do_var_undefine(pCompiler, pchWord + 8, cchLeft - 8, 0);
5113 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "override", 8))
5114 {
5115 if (kmk_cc_eval_try_handle_var_with_keywords(pCompiler, pchWord + 8, cchLeft - 8, KMK_CC_EVAL_QUALIFIER_OVERRIDE))
5116 return 1;
5117 pCompiler->iEscEol = iSavedEscEol;
5118 }
5119 else if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "private", 7))
5120 {
5121 if (kmk_cc_eval_try_handle_var_with_keywords(pCompiler, pchWord + 7, cchLeft - 7, KMK_CC_EVAL_QUALIFIER_PRIVATE))
5122 return 1;
5123 pCompiler->iEscEol = iSavedEscEol;
5124 }
5125 }
5126
5127 /*
5128 * Check out the other keywords.
5129 */
5130 if (ch == 'i') /* Lots of directives starting with 'i'. */
5131 {
5132 char ch2 = pchWord[1];
5133 pchWord += 2;
5134 cchLeft -= 2;
5135
5136 /* 'if...' */
5137 if (ch2 == 'f')
5138 {
5139 if (KMK_CC_WORD_COMP_IS_EOL(pCompiler, pchWord, cchLeft))
5140 return kmk_cc_eval_do_if(pCompiler, pchWord, cchLeft, 0 /* in else */);
5141
5142 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "eq", 2))
5143 return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 2, cchLeft - 2, 0 /* in else */, 1 /* positive */);
5144
5145 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "def", 3))
5146 return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 3, cchLeft - 3, 0 /* in else */, 1 /* positive */);
5147
5148 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "neq", 3))
5149 return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 3, cchLeft - 3, 0 /* in else */, 0 /* positive */);
5150
5151 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "1of", 3))
5152 return kmk_cc_eval_do_if1of(pCompiler, pchWord + 3, cchLeft - 3, 0 /* in else */, 1 /* positive */);
5153
5154 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "ndef", 4))
5155 return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 4, cchLeft - 4, 0 /* in else */, 0 /* positive */);
5156
5157 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "n1of", 4))
5158 return kmk_cc_eval_do_if1of(pCompiler, pchWord + 4, cchLeft - 4, 0 /* in else */, 0 /* positive */);
5159 }
5160 /* include... */
5161 else if (ch2 == 'n' && cchLeft >= 5 && KMK_CC_WORD_COMP_CONST_5(pchWord, "clude") ) /* 'in...' */
5162 {
5163 pchWord += 5;
5164 cchLeft -= 5;
5165 if (KMK_CC_WORD_COMP_IS_EOL(pCompiler, pchWord, cchLeft))
5166 return kmk_cc_eval_do_include(pCompiler, pchWord, cchLeft, kKmkCcEvalInstr_include);
5167 if (cchLeft >= 3 && KMK_CC_WORD_COMP_CONST_3(pchWord, "dep"))
5168 {
5169 pchWord += 3;
5170 cchLeft -= 3;
5171 if (KMK_CC_WORD_COMP_IS_EOL(pCompiler, pchWord, cchLeft))
5172 return kmk_cc_eval_do_include(pCompiler, pchWord, cchLeft, kKmkCcEvalInstr_includedep);
5173 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "-queue", 6))
5174 return kmk_cc_eval_do_include(pCompiler, pchWord + 6, cchLeft - 6, kKmkCcEvalInstr_includedep_queue);
5175 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "-flush", 6))
5176 return kmk_cc_eval_do_include(pCompiler, pchWord + 6, cchLeft - 6, kKmkCcEvalInstr_includedep_flush);
5177 }
5178 }
5179 }
5180 else if (ch == 'e') /* A few directives starts with 'e'. */
5181 {
5182 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "else", 4))
5183 return kmk_cc_eval_do_else(pCompiler, pchWord + 4, cchLeft - 4);
5184 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "endif", 5))
5185 return kmk_cc_eval_do_endif(pCompiler, pchWord + 5, cchLeft - 5);
5186 /* export and endef are handled elsewhere, though stray endef's may end up here... */
5187 KMK_CC_ASSERT(!KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "export", 6));
5188
5189 }
5190 else /* the rest. */
5191 {
5192 if ( KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "sinclude", 8)
5193 || KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "-include", 8))
5194 return kmk_cc_eval_do_include(pCompiler, pchWord + 8, cchLeft - 8, kKmkCcEvalInstr_include_silent);
5195 if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "vpath", 5))
5196 return kmk_cc_eval_do_vpath(pCompiler, pchWord + 5, cchLeft - 5);
5197
5198 KMK_CC_ASSERT(!KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "local", 5));
5199 KMK_CC_ASSERT(!KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "define", 6));
5200 KMK_CC_ASSERT(!KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "private", 7));
5201 KMK_CC_ASSERT(!KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "override", 8));
5202 KMK_CC_ASSERT(!KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "unexport", 8));
5203 KMK_CC_ASSERT(!KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "undefine", 8));
5204 }
5205
5206 pCompiler->iEscEol = iSavedEscEol;
5207 return 0;
5208}
5209
5210
5211
5212
5213static int kmk_cc_eval_compile_worker(PKMKCCEVALPROG pEvalProg, const char *pszContent, size_t cchContent, unsigned iLine)
5214{
5215 const char *pchTmp;
5216
5217 /*
5218 * Compiler state.
5219 */
5220 KMKCCEVALCOMPILER Compiler;
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));
5223
5224 {
5225 /*
5226 * Line state.
5227 */
5228 size_t cchLine; /* The length of the current line (w/o comments). */
5229 size_t offNext = 0; /* The offset of the next line. */
5230 size_t off = 0; /* The offset into pszContent of the current line. */
5231
5232 /* Try for some register/whatever optimzations. */
5233 int const chFirstEol = Compiler.chFirstEol;
5234 size_t const cchEolSeq = Compiler.cchEolSeq;
5235
5236 /*
5237 * Process input lines.
5238 *
5239 * The code here concerns itself with getting the next line in an efficient
5240 * manner, very basic classification and trying out corresponding handlers.
5241 * The real work is done in the handlers.
5242 */
5243 while (offNext < cchContent)
5244 {
5245 size_t offFirstWord;
5246
5247 /*
5248 * Find the end of the next line.
5249 */
5250 KMK_CC_ASSERT(off == offNext);
5251
5252 /* Simple case: No escaped EOL, nor the end of the input. */
5253 pchTmp = (const char *)memchr(&pszContent[offNext], chFirstEol, cchContent - offNext);
5254 if ( pchTmp
5255 && ( &pszContent[offNext] == pchTmp
5256 || pchTmp[-1] != '\\') )
5257 {
5258 if ( cchEolSeq == 1
5259 || pchTmp[1] == Compiler.chSecondEol)
5260 {
5261 /* Frequent: Blank line. */
5262 if (&pszContent[offNext] == pchTmp)
5263 {
5264 KMK_CC_EVAL_DPRINTF(("#%03u: <empty>\n", Compiler.iLine));
5265 Compiler.iLine++;
5266 off = offNext += cchEolSeq;
5267 continue;
5268 }
5269 if (pszContent[offNext] == '#')
5270 {
5271 KMK_CC_EVAL_DPRINTF(("#%03u: <comment>\n", Compiler.iLine));
5272 Compiler.iLine++;
5273 offNext = pchTmp - pszContent;
5274 off = offNext += cchEolSeq;
5275 continue;
5276 }
5277
5278 offNext = pchTmp - pszContent;
5279 cchLine = offNext - off;
5280
5281 offFirstWord = off;
5282 while (offFirstWord < offNext && KMK_CC_EVAL_IS_SPACE(pszContent[offFirstWord]))
5283 offFirstWord++;
5284
5285 offNext += cchEolSeq;
5286 Compiler.cEscEols = 0;
5287 Compiler.iEscEol = 0;
5288 }
5289 else
5290 kmk_cc_eval_fatal_eol(&Compiler, pchTmp, Compiler.iLine, off);
5291 }
5292 /* The complicated, less common cases. */
5293 else
5294 {
5295 Compiler.cEscEols = 0;
5296 Compiler.iEscEol = 0;
5297 offFirstWord = offNext;
5298 for (;;)
5299 {
5300 if (offFirstWord == offNext)
5301 {
5302 size_t offEol = off + cchLine;
5303 while (offFirstWord < offEol && KMK_CC_EVAL_IS_SPACE(pszContent[offFirstWord]))
5304 offFirstWord++;
5305 }
5306
5307 if (pchTmp)
5308 {
5309 if ( cchEolSeq == 1
5310 || pchTmp[1] == Compiler.chSecondEol)
5311 {
5312 size_t offEsc;
5313 if (offFirstWord != offNext)
5314 offNext = pchTmp - pszContent;
5315 else
5316 {
5317 offNext = pchTmp - pszContent;
5318 while (offFirstWord < offNext && KMK_CC_EVAL_IS_SPACE(pszContent[offFirstWord]))
5319 offFirstWord++;
5320 }
5321
5322
5323 /* Is it an escape sequence? */
5324 if ( !offNext
5325 || pchTmp[-1] != '\\')
5326 {
5327 cchLine = offNext - off;
5328 offNext += cchEolSeq;
5329 break;
5330 }
5331 if (offNext < 2 || pchTmp[-2] != '\\')
5332 offEsc = offNext - 1;
5333 else
5334 {
5335 /* Count how many backslashes there are. Must be odd number to be an escape
5336 sequence. Normally we keep half of them, except for command lines. */
5337 size_t cSlashes = 2;
5338 while (offNext >= cSlashes && pchTmp[0 - cSlashes] == '\\')
5339 cSlashes--;
5340 if (!(cSlashes & 1))
5341 {
5342 cchLine = offNext - off;
5343 offNext += cchEolSeq;
5344 break;
5345 }
5346 offEsc = offNext - (cSlashes >> 1);
5347 }
5348
5349 /* Record it. */
5350 if (Compiler.cEscEols < Compiler.cEscEolsAllocated) { /* likely */ }
5351 else
5352 {
5353 KMK_CC_ASSERT(Compiler.cEscEols == Compiler.cEscEolsAllocated);
5354 Compiler.cEscEolsAllocated = Compiler.cEscEolsAllocated
5355 ? Compiler.cEscEolsAllocated * 2 : 2;
5356 Compiler.paEscEols = (PKMKCCEVALESCEOL)xrealloc(Compiler.paEscEols,
5357 Compiler.cEscEolsAllocated
5358 * sizeof(Compiler.paEscEols[0]));
5359 }
5360 Compiler.paEscEols[Compiler.cEscEols].offEsc = offEsc;
5361 Compiler.paEscEols[Compiler.cEscEols].offEol = offNext;
5362 Compiler.cEscEols++;
5363
5364 /* Advance. */
5365 offNext += cchEolSeq;
5366 if (offFirstWord == offEsc)
5367 {
5368 offFirstWord = offNext;
5369 Compiler.iEscEol++;
5370 }
5371 }
5372 else
5373 kmk_cc_eval_fatal_eol(&Compiler, pchTmp, Compiler.iLine, off);
5374 }
5375 else
5376 {
5377 /* End of input. Happens only once per compilation, nothing to optimize for. */
5378 if (offFirstWord == offNext)
5379 while (offFirstWord < cchContent && KMK_CC_EVAL_IS_SPACE(pszContent[offFirstWord]))
5380 offFirstWord++;
5381 offNext = cchContent;
5382 cchLine = cchContent - off;
5383 break;
5384 }
5385 pchTmp = (const char *)memchr(&pszContent[offNext], chFirstEol, cchContent - offNext);
5386 }
5387 }
5388 KMK_CC_ASSERT(offNext <= cchContent);
5389 KMK_CC_ASSERT(offNext >= off + cchLine);
5390 KMK_CC_ASSERT(off + cchLine <= cchContent && cchLine <= cchContent);
5391 KMK_CC_ASSERT(offFirstWord <= off + cchLine);
5392 KMK_CC_ASSERT(offFirstWord >= off);
5393 KMK_CC_ASSERT(pszContent[offFirstWord] != ' ' && pszContent[offFirstWord] != '\t');
5394
5395 KMK_CC_EVAL_DPRINTF(("#%03u: %*.*s\n", Compiler.iLine, (int)cchLine, (int)cchLine, &pszContent[off]));
5396
5397 /*
5398 * Skip blank lines.
5399 */
5400 if (offFirstWord < off + cchLine)
5401 {
5402 /*
5403 * Command? Ignore command prefix if no open recipe (SunOS 4 behavior).
5404 */
5405 if ( pszContent[off] == Compiler.chCmdPrefix
5406 && (Compiler.pRecipe || Compiler.fNoTargetRecipe))
5407 {
5408 if (!Compiler.fNoTargetRecipe)
5409 kmk_cc_eval_handle_command(&Compiler, &pszContent[off], cchLine);
5410 }
5411 /*
5412 * Since it's not a command line, we can now skip comment lines
5413 * even with a tab indentation. If it's not a comment line, we
5414 * tentatively strip any trailing comment.
5415 */
5416 else if (pszContent[offFirstWord] != '#')
5417 {
5418 const char *pchWord = &pszContent[offFirstWord];
5419 size_t cchLeft = off + cchLine - offFirstWord;
5420 char ch;
5421
5422 Compiler.cchLineWithComments = cchLine;
5423 pchTmp = (const char *)memchr(pchWord, '#', cchLeft);
5424 if (pchTmp)
5425 {
5426 cchLeft = pchTmp - pchWord;
5427 cchLine = pchTmp - &pszContent[off];
5428 }
5429 Compiler.cchLine = cchLine;
5430 Compiler.offLine = off;
5431
5432 /*
5433 * If not a directive or variable qualifier, it's either a variable
5434 * assignment or a recipe.
5435 */
5436 ch = *pchWord;
5437 if ( !KMK_CC_EVAL_IS_1ST_IN_KEYWORD(ch)
5438 || !KMK_CC_EVAL_IS_2ND_IN_KEYWORD(pchWord[1])
5439 || !kmk_cc_eval_try_handle_keyword(&Compiler, ch, pchWord, cchLeft) )
5440 {
5441 pchTmp = (const char *)memchr(pchWord, '=', cchLeft);
5442 if ( !pchTmp
5443 || !kmk_cc_eval_try_handle_assignment(&Compiler, pchTmp, pchWord, cchLeft, 0) )
5444 kmk_cc_eval_handle_recipe(&Compiler, pchTmp, pchWord, cchLeft);
5445 }
5446 /* else: handled a keyword expression */
5447 }
5448 }
5449
5450 /*
5451 * Advance to the next line.
5452 */
5453 off = offNext;
5454 Compiler.iLine += Compiler.cEscEols + 1;
5455 }
5456 }
5457
5458 /*
5459 * Check whether
5460 */
5461
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));
5464 return 0;
5465}
5466
5467
5468
5469static PKMKCCEVALPROG kmk_cc_eval_compile(const char *pszContent, size_t cchContent,
5470 const char *pszFilename, unsigned iLine, const char *pszVarName)
5471{
5472 /*
5473 * Estimate block size, allocate one and initialize it.
5474 */
5475 PKMKCCEVALPROG pEvalProg;
5476 PKMKCCBLOCK pBlock;
5477 pEvalProg = kmk_cc_block_alloc_first(&pBlock, sizeof(*pEvalProg), cchContent / 32); /** @todo adjust */
5478 if (pEvalProg)
5479 {
5480 pEvalProg->pBlockTail = pBlock;
5481 pEvalProg->pFirstInstr = (PKMKCCEVALCORE)kmk_cc_block_get_next_ptr(pBlock);
5482 pEvalProg->pszFilename = pszFilename ? pszFilename : "<unknown>";
5483 pEvalProg->pszVarName = pszVarName;
5484 pEvalProg->cRefs = 1;
5485#ifdef KMK_CC_STRICT
5486 pEvalProg->uInputHash = kmk_cc_debug_string_hash_n(0, pszContent, cchContent);
5487#endif
5488
5489 /*
5490 * Do the actual compiling.
5491 */
5492#ifdef CONFIG_WITH_EVAL_COMPILER
5493 if (kmk_cc_eval_compile_worker(pEvalProg, pszContent, cchContent, iLine) == 0)
5494#else
5495 if (0)
5496#endif
5497 {
5498#ifdef KMK_CC_WITH_STATS
5499 pBlock = pEvalProg->pBlockTail;
5500 if (!pBlock->pNext)
5501 g_cSingleBlockEvalProgs++;
5502 else if (!pBlock->pNext->pNext)
5503 g_cTwoBlockEvalProgs++;
5504 else
5505 g_cMultiBlockEvalProgs++;
5506 for (; pBlock; pBlock = pBlock->pNext)
5507 {
5508 g_cBlocksAllocatedEvalProgs++;
5509 g_cbAllocatedEvalProgs += pBlock->cbBlock;
5510 g_cbUnusedMemEvalProgs += pBlock->cbBlock - pBlock->offNext;
5511 }
5512#endif
5513 return pEvalProg;
5514 }
5515 kmk_cc_block_free_list(pEvalProg->pBlockTail);
5516 }
5517 return NULL;
5518}
5519
5520
5521/**
5522 * Compiles a variable direct evaluation as is, setting v->evalprog on success.
5523 *
5524 * @returns Pointer to the program on success, NULL if no program was created.
5525 * @param pVar Pointer to the variable.
5526 */
5527struct kmk_cc_evalprog *kmk_cc_compile_variable_for_eval(struct variable *pVar)
5528{
5529 PKMKCCEVALPROG pEvalProg = pVar->evalprog;
5530 if (!pEvalProg)
5531 {
5532#ifdef CONFIG_WITH_EVAL_COMPILER
5533 pEvalProg = kmk_cc_eval_compile(pVar->value, pVar->value_length,
5534 pVar->fileinfo.filenm, pVar->fileinfo.lineno, pVar->name);
5535 pVar->evalprog = pEvalProg;
5536#endif
5537 g_cVarForEvalCompilations++;
5538 }
5539 return pEvalProg;
5540}
5541
5542
5543/**
5544 * Compiles a makefile for
5545 *
5546 * @returns Pointer to the program on success, NULL if no program was created.
5547 * @param pVar Pointer to the variable.
5548 */
5549struct kmk_cc_evalprog *kmk_cc_compile_file_for_eval(FILE *pFile, const char *pszFilename)
5550{
5551 PKMKCCEVALPROG pEvalProg;
5552
5553 /*
5554 * Read the entire file into a zero terminate memory buffer.
5555 */
5556 size_t cchContent = 0;
5557 char *pszContent = NULL;
5558 struct stat st;
5559 if (!fstat(fileno(pFile), &st))
5560 {
5561 if ( st.st_size > (off_t)16*1024*1024
5562 && st.st_size < 0)
5563 fatal(NULL, _("Makefile too large to compile: %ld bytes (%#lx) - max 16MB"), (long)st.st_size, (long)st.st_size);
5564 cchContent = (size_t)st.st_size;
5565 pszContent = (char *)xmalloc(cchContent + 1);
5566
5567 cchContent = fread(pszContent, 1, cchContent, pFile);
5568 if (ferror(pFile))
5569 fatal(NULL, _("Read error: %s"), strerror(errno));
5570 }
5571 else
5572 {
5573 size_t cbAllocated = 2048;
5574 do
5575 {
5576 cbAllocated *= 2;
5577 if (cbAllocated > 16*1024*1024)
5578 fatal(NULL, _("Makefile too large to compile: max 16MB"));
5579 pszContent = (char *)xrealloc(pszContent, cbAllocated);
5580 cchContent += fread(&pszContent[cchContent], 1, cbAllocated - 1 - cchContent, pFile);
5581 if (ferror(pFile))
5582 fatal(NULL, _("Read error: %s"), strerror(errno));
5583 } while (!feof(pFile));
5584 }
5585 pszContent[cchContent] = '\0';
5586
5587 /*
5588 * Call common function to do the compilation.
5589 */
5590 pEvalProg = kmk_cc_eval_compile(pszContent, cchContent, pszFilename, 1, NULL /*pszVarName*/);
5591 g_cFileForEvalCompilations++;
5592
5593 free(pszContent);
5594 if (!pEvalProg)
5595 fseek(pFile, 0, SEEK_SET);
5596 return pEvalProg;
5597}
5598
5599
5600/**
5601 * Equivalent of eval_buffer, only it's using the evalprog of the variable.
5602 *
5603 * @param pVar Pointer to the variable. Must have a program.
5604 */
5605void kmk_exec_eval_variable(struct variable *pVar)
5606{
5607 KMK_CC_ASSERT(pVar->evalprog);
5608 assert(0);
5609}
5610
5611
5612/**
5613 * Worker for eval_makefile.
5614 *
5615 * @param pEvalProg The program pointer.
5616 */
5617void kmk_exec_eval_file(struct kmk_cc_evalprog *pEvalProg)
5618{
5619 KMK_CC_ASSERT(pEvalProg);
5620 assert(0);
5621}
5622
5623
5624
5625/*
5626 *
5627 * Program destruction hooks.
5628 * Program destruction hooks.
5629 * Program destruction hooks.
5630 *
5631 */
5632
5633
5634/**
5635 * Called when a variable with expandprog or/and evalprog changes.
5636 *
5637 * @param pVar Pointer to the variable.
5638 */
5639void kmk_cc_variable_changed(struct variable *pVar)
5640{
5641 PKMKCCEXPPROG pProg = pVar->expandprog;
5642
5643 KMK_CC_ASSERT(pVar->evalprog || pProg);
5644
5645 if (pVar->evalprog)
5646 {
5647 kmk_cc_block_free_list(pVar->evalprog->pBlockTail);
5648 pVar->evalprog = NULL;
5649 }
5650
5651 if (pProg)
5652 {
5653 if (pProg->cRefs == 1)
5654 kmk_cc_block_free_list(pProg->pBlockTail);
5655 else
5656 fatal(NULL, _("Modifying a variable (%s) while its expansion program is running is not supported"), pVar->name);
5657 pVar->expandprog = NULL;
5658 }
5659}
5660
5661
5662/**
5663 * Called when a variable with expandprog or/and evalprog is deleted.
5664 *
5665 * @param pVar Pointer to the variable.
5666 */
5667void kmk_cc_variable_deleted(struct variable *pVar)
5668{
5669 PKMKCCEXPPROG pProg = pVar->expandprog;
5670
5671 KMK_CC_ASSERT(pVar->evalprog || pProg);
5672
5673 if (pVar->evalprog)
5674 {
5675 kmk_cc_block_free_list(pVar->evalprog->pBlockTail);
5676 pVar->evalprog = NULL;
5677 }
5678
5679 if (pProg)
5680 {
5681 if (pProg->cRefs == 1)
5682 kmk_cc_block_free_list(pProg->pBlockTail);
5683 else
5684 fatal(NULL, _("Deleting a variable (%s) while its expansion program is running is not supported"), pVar->name);
5685 pVar->expandprog = NULL;
5686 }
5687}
5688
5689
5690
5691
5692
5693
5694
5695#endif /* CONFIG_WITH_COMPILER */
5696
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette