VirtualBox

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

Last change on this file since 3387 was 3233, checked in by bird, 6 years ago

kmk_cc_exec.c: Some updates, needs more work.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use