VirtualBox

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

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

MSVC build fixes.

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