VirtualBox

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

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

kmk_cc_exec.c: More code.

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