VirtualBox

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

Last change on this file since 2989 was 2817, checked in by bird, 9 years ago

comment typo.

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