diff --git a/src/engine/Jam.html b/src/engine/Jam.html index 5d612ecba..4afac4e52 100644 --- a/src/engine/Jam.html +++ b/src/engine/Jam.html @@ -248,7 +248,8 @@ jam [ -a ] [ -n ] [ -v ] with two exceptions: double quotes (") can enclose whitespace to embed it into a token, and everything between the matching curly braces ({}) in the definition of a rule action is treated - as a single string. A backslash (\) can escape a double quote. + as a single string. A backslash (\) can escape a double quote, + or any single whitespace character.

@@ -299,6 +300,17 @@ jam [ -a ] [ -n ] [ -v ]

+ Rules can return values, which can be expanded into a list with + "[ rule args ... ]". A rule's value is the value + of its last statement, though only the following statements + have values: 'if' (value of the leg chosen), 'switch' (value of the case + chosen), set (value of the resulting variable), and 'return' (value + of its arguments). Note that 'return' doesn't actually cause a + return, i.e., is a no-op unless it is the last statement + of the last block executed within rule body. + +

+ The jam statements for defining and invoking rules are as follows: @@ -325,15 +337,33 @@ jam [ -a ] [ -n ] [ -v ]

Invoke a rule. +

+ on target rulename field1 : field2 : ... + : fieldN ; + + +
Invoke a rule under the influence of target's specific + variables.. + +

+ [ rulename field1 : field2 : ... + : fieldN ]
+ [ on target rulename field1 : field2 : ... + : fieldN ]
+ +
+ +
Used as an argument, expands to the return value of the rule invoked. +

A rule is invoked with values in field1 through fieldN. They may be referenced in the procedure's - statements as $(1) through $(N), and the first - two only may be referenced in the action's commands as - $(1) and $(2). $(<) and $(>) are synonymous with $(1) + statements as $(1) through $(N) (9 max), and the + first two only may be referenced in the action's commands + as $(1) and $(2). $(<) and $(>) are synonymous with $(1) and $(2).

@@ -396,7 +426,7 @@ jam [ -a ] [ -n ] [ -v ]

Built-in Rules

- Jam has ten built-in rules, all of which are pure + Jam has eleven built-in rules, all of which are pure procedure rules without updating actions. They are in three groups: the first builds the dependency graph; the second modifies it; and the third are just utility @@ -421,8 +451,8 @@ jam [ -a ] [ -n ] [ -v ] INCLUDES targets1 : targets2 ; -

Builds a sibling dependency: makes each of targets2 - depend on anything upon which each of targets1 depends. +
Builds a sibling dependency: makes any target that depends + on any of targets1 also depend on each of targets2. This reflects the dependencies that arise when one source file includes another: the object built from the source file depends both on the original and included source file, but the two @@ -435,7 +465,7 @@ jam [ -a ] [ -n ] [ -v ]

- "foo.h" depends on "foo.c" and "foo.h" in this example. + "foo.o" depends on "foo.c" and "foo.h" in this example. @@ -550,6 +580,31 @@ jam [ -a ] [ -n ] [ -v ]

Blurts out the message args to stdout and then exits with a failure status. +

+ + "Echo", "echo", "Exit", and "exit" are accepted as aliases for ECHO + and EXIT, since it is hard to tell that these are built-in + rules and not part of the language, like "include". + + + +

+ + The GLOB rule does filename globbing. + +

+ +

+ GLOB directories : patterns + + +
Using the same wildcards as for the patterns in the + switch statement). + It is invoked by being used as an argument to a rule invocation + inside of `[ ]`. For example: "FILES = [ GLOB dir1 dir2 : *.c *.h ]" + will set the value of A to the list of C source and header files in + dir1 or dir2. +

Flow-of-Control

@@ -570,7 +625,9 @@ jam [ -a ] [ -n ] [ -v ] list, setting the variable var to the element value. +

+ if cond { statements }
[ else statements ] @@ -654,7 +711,21 @@ jam [ -a ] [ -n ] [ -v ]

+ return values ; + + + +

Within a rule body, the return statement sets the return + value for an invocation of the rule. It does not cause the + rule to return; a rule's value is actually the value of the + last statement executed, so a return should be the + last statement executed before the rule "naturally" returns. + +

+ + switch value +
{
case pattern1 : statements ;
case pattern2 : statements ; @@ -677,9 +748,22 @@ jam [ -a ] [ -n ] [ -v ] match zero or more characters [chars] match any single character in chars + [^chars] + match any single character not in chars + \x + match x (escapes the other wildcards) +

+ + while cond { statements } + + + +

Repeatedly execute statements while cond + remains true upon entry. (See the description of cond + expression syntax under if, above).

Variables

@@ -876,6 +960,13 @@ jam [ -a ] [ -n ] [ -v ] Prepend root to the whole file name, if not already rooted. + :E=value + Assign value to the variable if it is unset. + + :J=joinval + Concatentate list elements into single + element, separated by joinval. +

@@ -1188,13 +1279,19 @@ jam [ -a ] [ -n ] [ -v ]

- Copyright 1997, 2000 Perforce Software, Inc. + Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
Comments to info@perforce.com
Last updated: December 31, 2000
+<<<<<<< variant A $Id$ +>>>>>>> variant B + $Id$ +####### Ancestor + $Id$ +======= end diff --git a/src/engine/Jambase.html b/src/engine/Jambase.html index 2c108f8fa..af3a4709e 100644 --- a/src/engine/Jambase.html +++ b/src/engine/Jambase.html @@ -79,15 +79,31 @@ Jambase Rules Removes existing targets when clean is built. clean is not a dependency of all, and must be built explicitly for targets to be removed. + + FDefines defines ;

+ Expands a list of definitions into a list of compiler + (or preprocessor) switches (such as + -Dsymbol=val on Unix) + to pass the definitions.
File target : source ;
Copies source into target. +
+ FIncludes dirs ;
+ Expands a list of directories into a list of compiler + (or preprocessor) switches (such as -Idir on Unix) + to add the directories to the header inclusion search path.
Fortran obj.o : source.f ;
Compile the Fortran source file source.f. Called by the Object rule. +
+ FQuote files ;
+ Returns each of files suitably quoted so as to hide shell + metacharacters (such as whitespace and filename matching wildcards) + from the shell.

GenFile target : image sources ; @@ -221,6 +237,10 @@ Jambase Rules value of $(CCFLAGS) or $(C++FLAGS) when compiling source. Any file suffix on source is ignored. + ObjectDefines object : defines ;

+ Adds preprocessor symbol definitions to the (gristed) + target-specific $(CCDEFS) for the object. +
ObjectHdrs source : dirs ;
Add dirs to the source-specific value of $(HDRS) when scanning and compiling source. @@ -265,10 +285,11 @@ Jambase Rules Adds flags to the compiler flags for source files in SubDir's directory.
- SubDirHdrs paths ; + SubDirHdrs d1 ... dn ;
- Adds paths to the header search paths for source files - in SubDir's directory. + Adds the path d1/.../dn/ to the header search paths for + source files in SubDir's directory. d1 through dn + are elements of a directory path.
SubInclude VAR d1 ... dn ;
@@ -466,6 +487,17 @@ Jambase Variables On Macintosh, the root of the Code Warrior Pro 5 directory.
+ DEFINES + +
+ Preprocessor symbol definitions for Cc and C++ rule targets. + The Cc and C++ rules set target-specific $(CCDEFS) + values on their targets, based on $(DEFINES). (The + "indirection" here is required to support compilers, + like VMS, with baroque command line syntax for + setting symbols). +
+ DOT
@@ -866,16 +898,28 @@ Jambase Variables The yacc(1) command flags.
+ YACCGEN + +
+ The suffix used on generated yacc(1) output. +
+


Back to top.

- Copyright 1997, 2000 Perforce Software, Inc. + Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
Comments to info@perforce.com
Last updated: Dec 31, 2000
+<<<<<<< variant A $Id$ +>>>>>>> variant B + $Id$ +####### Ancestor + $Id$ +======= end diff --git a/src/engine/Jamfile b/src/engine/Jamfile index b1bf00ddb..5aee1ffbc 100644 --- a/src/engine/Jamfile +++ b/src/engine/Jamfile @@ -116,7 +116,8 @@ Library libjam.a : command.c compile.c $(code) expand.c glob.c hash.c headers.c hdrmacro.c lists.c make.c make1.c newstr.c option.c parse.c regexp.c rules.c scan.c search.c subst.c - timestamp.c variable.c modules.c strings.c filesys.c ; + timestamp.c variable.c modules.c strings.c filesys.c + builtins.c ; if $(BINDIR) { InstallBin $(BINDIR) : jam ; } diff --git a/src/engine/Jamfile.html b/src/engine/Jamfile.html index 2f94ddf9d..8e78926ab 100644 --- a/src/engine/Jamfile.html +++ b/src/engine/Jamfile.html @@ -1445,6 +1445,12 @@ RmTemps Rule
Last updated: Dec 31, 2000
+<<<<<<< variant A $Id$ +>>>>>>> variant B + $Id$ +####### Ancestor + $Id$ +======= end diff --git a/src/engine/README b/src/engine/README index 6f94add06..9ba116cc3 100644 --- a/src/engine/README +++ b/src/engine/README @@ -9,7 +9,7 @@ The complete and detailed list of changes is available at: Jam/MR (aka "jam - make(1) redux") /+\ - +\ Copyright 1993, 2000 Christopher Seiwald. + +\ Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. \+/ This is Release 2.3 of Jam/MR, a make-like program. @@ -53,14 +53,12 @@ FEATURES INFORMATION GUIDE - Jam.html jam command usage + Jam.html jam and language reference. Jambase.html Reference for the Jambase boilerplate file. Jamfile.html Easy reading on creating a Jamfile and using jam. - Jamlang.html The Jam language description. - RELNOTES Release 2.3 release notes. Porting Notes on porting jam to wildcat platforms. diff --git a/src/engine/RELNOTES b/src/engine/RELNOTES index 47b7bfe69..b27221d5f 100644 --- a/src/engine/RELNOTES +++ b/src/engine/RELNOTES @@ -1,3 +1,4 @@ +<<<<<<< variant A Release notes for FTJam 2.3.5 (previous release was named "20010626") 0. Bugs fixed since 20010626: @@ -26,6 +27,159 @@ Release notes for FTJam 2.3.5 (previous release was named "20010626") ============================================================================ +>>>>>>> variant B +Release notes for Jam/MR [UNRELEASED] +(aka Jam - make(1) redux) + +*** Note: These Release notes represent work in progress, +*** not a completed release! + +1. Release info: (TENTATIVE) + + Jam/MR 2.4 (TENTATIVE, IN PROGRESS!) + Month, dd, 2002 + VERSION 2.4 (TENTATIVE, IN PROGRESS!) + +2. Compatibility + + Jam 2.4 is upward compatible with Jam 2.3 + + The Jam 2.4 language is a superset of the 2.3 language; + Jamfiles, Jambase, and other rulesets used in 2.3 can be used + with the 2.4 language support. + +3. Changes since 2.3. + +3.1. Changes to Jam Language + + The mechanism for calling rules that return values - "[ rule + args ...]", (and 'return' in the rule body), is now a + documented part of the language. + + Add "on ..." syntax, to invoke a + rule under the influence of a target's specific variables. + + Add "[ on targ rule ... ]" to call a rule returning a value, + under the influence of a target's specific variables. + + New 'Glob' builtin that returns a list of files in a list of + directories, given a list of patterns. + + New 'while expr { block }' construct. + + New :E=value modifier provides default value if variable unset. + + New :J=joinval modifier concatentates list elements into single + element, separated by joinval. + + \ can now be used to escape a space (or any single whitespace + character), so that you don't have to resort to quotes. + + 'Echo' and 'Exit' now have aliases 'echo' and 'exit', since it + is really hard to tell that these are built-in rules and not + part of the language, like 'include'. Real rules continue to + start with a capital. + +3.2. Jambase Changes + + Support for YACCGEN, the suffix used on generated yacc output. + + Fix ups to have jam and p4 build with borland C 5.5, + and minor win98 jam support for jam clean + + SubDirHdrs now takes directory names in the same format as + SubInclude : one directory element per word. + + More portable support for specifying includes and #defines: + New ASHDRS, CCHDRS, CCDEFS, DEFINES, ObjectDefines, FQuote, + FIncludes, FDefines. Ordering of cc and c++ flags grossly + rearranged. + + Jambase has been compacted by applying the new E: and J: + expansion modifiers. + +3.3. Jam internal code changes + + Optimize rule compilation, with right-recursion instead of left. + + Split jam's built-in rules out to builtins.c from compile.c, + so that compile.c only deals with the language. + + Split jam's pathsys.h from filesys.h, since they are really + two different pieces. + + evaluate_if(), which evaluated the condition tree for 'if' and + returned an int, has been replaced with compile_eval(), which does + essentially the same but returns a LIST. + +4. Fixed bugs + + Defining a rule within another rule, and invoking the enclosing + rule more than once, would result in giving the first rule a + null definition. Fixed. + + $(d:P) now works properly on the mac, climbing up directories. + Thanks to Miklos Fazekas . + + No longer (sometimes) treat \ as a directory separator on + UNIX. It isn't supposed to be, but was due to bungled ifdefs. + + Applying just :U or :D (or :E, :J) mods no longer causes the + variable value to be treated as a filename (parsed and rebuilt + using the OS specific pathsys routines). Previously, if _any_ + mods were present then the value was parsed and rebuilt as if + a filename, and that could in certain cases munge the value. + Only the file modifiers (:GDBSM) treat the value as a + filename. + + Four rules makeCommon, makeGrist, makeString, makeSubDir from + jam 2.2 missing in 2.3 have been readded, with apologies to + dtb@cisco.com. + + Return status more likely to be correct when using -d0, now that + targets are could as being built even with no debugging output. + Thanks to Miklos Fazekas . + +5. Porting + + [MACINTOSH] Paths are now downshifted (interally) so as to + handle its case insensitivity. Thanks to Miklos Fazekas + . + + [NT] MS changed the macro for the IA64 Windows NT 64bit + compiler. + + [CYGWIN] Cygwin jam porting: dance around bison and yyacc. + Use bison's -y flag to use yacc's output file naming + conventions, and don't use yyacc on systems whose SUFEXE is + set. + + [VMS] The Jambase itself was not formatting the CCHDRS and + CCDEFS properly: on VMS they can't be appended to, because + multiple /define or /include directives don't work. Instead + now CCHDRS and CCDEFS is reformatted from HDRS and DEFINES + anytime those latter two change. This requires the recent + change to jam to allow access to target-specific variables + when setting other variables. + + [VMS] Remove exception call when file_dirscan() can't, for + some reason, scan a directory. Use a better set of #ifdefs to + determine if we're on a vax, rather than relying on the C + compiler being a specific version: we're able to build with + the C++ compiler now. + + [VMS] Port new jam to run with just cxx compiler. + (The C compiler being a extra-cost item). + + [NT] Add entry for DevStudio when the settings are already in the + system environment. + +=============================================================================== +=============================================================================== + + +####### Ancestor +======= end Release notes for Jam/MR 2.3 (aka Jam - make(1) redux) @@ -233,7 +387,7 @@ Release Notes for Jam 2.2 Documentation rewritten; HTML versions supplied. -3.1 Changes to Jam Language (See Jamlang.html) +3.1 Changes to Jam Language Rules may now have more fields than just $(<) and $(>). diff --git a/src/engine/builtins.c b/src/engine/builtins.c new file mode 100644 index 000000000..9c7cef8a4 --- /dev/null +++ b/src/engine/builtins.c @@ -0,0 +1,594 @@ +/* + * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. + * + * This file is part of Jam - see jam.c for Copyright information. + */ + +# include "jam.h" + +# include "lists.h" +# include "parse.h" +# include "builtins.h" +# include "rules.h" +# include "filesys.h" +# include "newstr.h" +# include "frames.h" +# include "hash.h" +# include "strings.h" + +/* + * builtins.c - builtin jam rules + * + * External routines: + * + * load_builtin() - define builtin rules + * + * Internal routines: + * + * builtin_depends() - DEPENDS/INCLUDES rule + * builtin_echo() - ECHO rule + * builtin_exit() - EXIT rule + * builtin_flags() - NOCARE, NOTFILE, TEMPORARY rule + * builtin_glob() - GLOB rule + * + * 01/10/01 (seiwald) - split from compile.c + */ + +/* + * compile_builtin() - define builtin rules + */ + +# define P0 (PARSE *)0 +# define C0 (char *)0 + +int glob( char *s, char *c ); + +static void lol_build( LOL* lol, char** elements ); +void backtrace( FRAME *frame ); +void backtrace_line( FRAME *frame ); +void print_source_line( PARSE* p ); + +RULE* bind_builtin( char* name, LIST*(*f)(PARSE*, FRAME*), int flags, char** args ) +{ + argument_list* arg_list = 0; + + if ( args ) + { + arg_list = args_new(); + lol_build( arg_list->data, args ); + } + + return new_rule_body( root_module(), name, arg_list, + parse_make( f, P0, P0, P0, C0, C0, flags ), 1 ); +} + +RULE* duplicate_rule( char* name, RULE* other ) +{ + return import_rule( other, root_module(), name ); +} + +void +load_builtins() +{ + duplicate_rule( "Always" , + bind_builtin( "ALWAYS" , + builtin_flags, T_FLAG_TOUCHED, 0 ) ); + + duplicate_rule( "Depends" , + bind_builtin( "DEPENDS" , + builtin_depends, T_DEPS_DEPENDS, 0 ) ); + + duplicate_rule( "echo" , + duplicate_rule( "Echo" , + bind_builtin( "ECHO" , + builtin_echo, 0, 0 ) ) ); + + duplicate_rule( "exit" , + duplicate_rule( "Exit" , + bind_builtin( "EXIT" , + builtin_exit, 0, 0 ) ) ); + + duplicate_rule( "Glob" , + bind_builtin( "GLOB" , + builtin_glob, 0, 0 ) ); + + duplicate_rule( "Includes" , + bind_builtin( "INCLUDES" , + builtin_depends, T_DEPS_INCLUDES, 0 ) ); + + duplicate_rule( "Leaves" , + bind_builtin( "LEAVES" , + builtin_flags, T_FLAG_LEAVES, 0 ) ); + + duplicate_rule( "NoCare" , + bind_builtin( "NOCARE" , + builtin_flags, T_FLAG_NOCARE, 0 ) ); + + duplicate_rule( "NOTIME" , + duplicate_rule( "NotFile" , + bind_builtin( "NOTFILE" , + builtin_flags, T_FLAG_NOTFILE, 0 ) ) ); + + duplicate_rule( "NoUpdate" , + bind_builtin( "NOUPDATE" , + builtin_flags, T_FLAG_NOUPDATE, 0 ) ); + + duplicate_rule( "Temporary" , + bind_builtin( "TEMPORARY" , + builtin_flags, T_FLAG_TEMP, 0 ) ); + + duplicate_rule( "HdrMacro" , + bind_builtin( "HDRMACRO" , + builtin_hdrmacro, 0, 0 ) ); + + /* FAIL_EXPECTED is an experimental built-in that is used to indicate */ + /* that the result of a target build action should be inverted (ok <=> fail) */ + /* this can be useful when performing test runs from Jamfiles.. */ + /* */ + /* Beware that this rule might disappear or be renamed in the future.. */ + /* contact david.turner@freetype.org for more details.. */ + bind_builtin( "FAIL_EXPECTED" , + builtin_flags, T_FLAG_FAIL_EXPECTED, 0 ); + + { + char * args[] = { "string", "pattern", "replacements", "+", 0 }; + duplicate_rule( "subst" , + bind_builtin( "SUBST" , + builtin_subst, 0, args ) ); + } + + { + char * args[] = { "module", "?", 0 }; + bind_builtin( "RULENAMES" , + builtin_rulenames, 0, args ); + } + + { + char * args[] = { "source_module", "?", + ":", "source_rules", "*", + ":", "target_module", "?", + ":", "target_rules", "*", + ":", "localize", "?", 0 }; + bind_builtin( "IMPORT" , + builtin_import, 0, args ); + } + + { + char * args[] = { "module", "?", ":", "rules", "*", 0 }; + bind_builtin( "EXPORT" , + builtin_export, 0, args ); + } + + { + char * args[] = { "levels", "?", 0 }; + bind_builtin( "CALLER_MODULE" , + builtin_caller_module, 0, args ); + } + + { + char * args[] = { 0 }; + bind_builtin( "BACKTRACE" , + builtin_backtrace, 0, args ); + } +} + +/* + * builtin_depends() - DEPENDS/INCLUDES rule + * + * The DEPENDS builtin rule appends each of the listed sources on the + * dependency list of each of the listed targets. It binds both the + * targets and sources as TARGETs. + */ + +LIST * +builtin_depends( + PARSE *parse, + FRAME *frame ) +{ + LIST *targets = lol_get( frame->args, 0 ); + LIST *sources = lol_get( frame->args, 1 ); + int which = parse->num; + LIST *l; + + for( l = targets; l; l = list_next( l ) ) + { + TARGET *t = bindtarget( l->string ); + t->deps[ which ] = targetlist( t->deps[ which ], sources ); + } + + return L0; +} + +/* + * builtin_echo() - ECHO rule + * + * The ECHO builtin rule echoes the targets to the user. No other + * actions are taken. + */ + +LIST * +builtin_echo( + PARSE *parse, + FRAME *frame ) +{ + list_print( lol_get( frame->args, 0 ) ); + printf( "\n" ); + return L0; +} + +/* + * builtin_exit() - EXIT rule + * + * The EXIT builtin rule echoes the targets to the user and exits + * the program with a failure status. + */ + +LIST * +builtin_exit( + PARSE *parse, + FRAME *frame ) +{ + list_print( lol_get( frame->args, 0 ) ); + printf( "\n" ); + exit( EXITBAD ); /* yeech */ + return L0; +} + +/* + * builtin_flags() - NOCARE, NOTFILE, TEMPORARY rule + * + * Builtin_flags() marks the target with the appropriate flag, for use + * by make0(). It binds each target as a TARGET. + */ + +LIST * +builtin_flags( + PARSE *parse, + FRAME *frame ) +{ + LIST *l = lol_get( frame->args, 0 ); + + for( ; l; l = list_next( l ) ) + bindtarget( l->string )->flags |= parse->num; + + return L0; +} + +/* + * builtin_globbing() - GLOB rule + */ + +struct globbing { + LIST *patterns; + LIST *results; +} ; + +static void +builtin_glob_back( + void *closure, + char *file, + int status, + time_t time ) +{ + struct globbing *globbing = (struct globbing *)closure; + LIST *l; + + for( l = globbing->patterns; l; l = l->next ) + if( !glob( l->string, file ) ) + { + globbing->results = list_new( globbing->results, newstr( file ) ); + break; + } +} + +LIST * +builtin_glob( + PARSE *parse, + FRAME *frame ) +{ + LIST *l = lol_get( frame->args, 0 ); + LIST *r = lol_get( frame->args, 1 ); + + struct globbing globbing; + + globbing.results = L0; + globbing.patterns = r; + + for( ; l; l = list_next( l ) ) + file_dirscan( l->string, builtin_glob_back, &globbing ); + + return globbing.results; +} + +LIST * +builtin_hdrmacro( + PARSE *parse, + FRAME *frame ) +{ + LIST* l = lol_get( frame->args, 0 ); + + for ( ; l; l = list_next(l) ) + { + TARGET* t = bindtarget( l->string ); + + /* scan file for header filename macro definitions */ + if ( DEBUG_HEADER ) + printf( "scanning '%s' for header file macro definitions\n", + l->string ); + + macro_headers( t ); + } + + return L0; +} + +/* builtin_rulenames() - RULENAMES ( MODULE ? ) + * + * Returns a list of the non-local rule names in the given MODULE. If + * MODULE is not supplied, returns the list of rule names in the + * global module. + */ + +/* helper function for builtin_rulenames(), below */ +static void add_rule_name( void* r_, void* result_ ) +{ + RULE* r = r_; + LIST** result = result_; + + if ( r->exported ) + *result = list_new( *result, copystr( r->name ) ); +} + +LIST * +builtin_rulenames( + PARSE *parse, + FRAME *frame ) +{ + LIST *arg0 = lol_get( frame->args, 0 ); + LIST *result = L0; + module* source_module = bindmodule( arg0 ? arg0->string : 0 ); + + hashenumerate( source_module->rules, add_rule_name, &result ); + return result; +} + +static void unknown_rule( FRAME *frame, char* key, char *module_name, char *rule_name ) +{ + backtrace_line( frame->prev ); + printf( "%s error: rule \"%s\" unknown in module \"%s\"\n", key, rule_name, module_name ); + backtrace( frame->prev ); + exit(1); + +} + +/* + * builtin_import() - IMPORT ( SOURCE_MODULE ? : SOURCE_RULES * : TARGET_MODULE ? : TARGET_RULES * : LOCALIZE ? ) + * + * The IMPORT rule imports rules from the SOURCE_MODULE into the + * TARGET_MODULE as local rules. If either SOURCE_MODULE or + * TARGET_MODULE is not supplied, it refers to the global + * module. SOURCE_RULES specifies which rules from the SOURCE_MODULE + * to import; TARGET_RULES specifies the names to give those rules in + * TARGET_MODULE. If SOURCE_RULES contains a name which doesn't + * correspond to a rule in SOURCE_MODULE, or if it contains a + * different number of items than TARGET_RULES, an error is issued. + * if LOCALIZE is specified, the rules will be executed in + * TARGET_MODULE, with corresponding access to its module local + * variables. + */ +LIST * +builtin_import( + PARSE *parse, + FRAME *frame ) +{ + LIST *source_module_list = lol_get( frame->args, 0 ); + LIST *source_rules = lol_get( frame->args, 1 ); + LIST *target_module_list = lol_get( frame->args, 2 ); + LIST *target_rules = lol_get( frame->args, 3 ); + LIST *localize = lol_get( frame->args, 4 ); + + module* target_module = bindmodule( target_module_list ? target_module_list->string : 0 ); + module* source_module = bindmodule( source_module_list ? source_module_list->string : 0 ); + + LIST *source_name, *target_name; + + for ( source_name = source_rules, target_name = target_rules; + source_name && target_name; + source_name = list_next( source_name ) + , target_name = list_next( target_name ) ) + { + RULE r_, *r = &r_, *imported; + r_.name = source_name->string; + + if ( !hashcheck( source_module->rules, (HASHDATA**)&r ) ) + unknown_rule( frame, "IMPORT", source_module->name, r_.name ); + + imported = import_rule( r, target_module, target_name->string ); + if ( localize ) + imported->module = target_module; + imported->exported = 0; /* this rule is really part of some other module; just refer to it here, but don't let it out */ + } + + if ( source_name || target_name ) + { + backtrace_line( frame->prev ); + printf( "import error: length of source and target rule name lists don't match" ); + backtrace( frame->prev ); + exit(1); + } + + return L0; +} + + +/* + * builtin_export() - EXPORT ( MODULE ? : RULES * ) + * + * The EXPORT rule marks RULES from the SOURCE_MODULE as non-local + * (and thus exportable). If an element of RULES does not name a rule + * in MODULE, an error is issued. + */ +LIST * +builtin_export( + PARSE *parse, + FRAME *frame ) +{ + LIST *module_list = lol_get( frame->args, 0 ); + LIST *rules = lol_get( frame->args, 1 ); + + module* m = bindmodule( module_list ? module_list->string : 0 ); + + + for ( ; rules; rules = list_next( rules ) ) + { + RULE r_, *r = &r_; + r_.name = rules->string; + + if ( !hashcheck( m->rules, (HASHDATA**)&r ) ) + unknown_rule( frame, "EXPORT", m->name, r_.name ); + + r->exported = 1; + } + return L0; +} + +/* Retrieve the file and line number that should be indicated for a + * given procedure in debug output or an error backtrace + */ +static void get_source_line( PARSE* procedure, char** file, int* line ) +{ + if ( procedure ) + { + char* f = procedure->file; + int l = procedure->line; + if ( !strcmp( f, "+" ) ) + { + f = "jambase.c"; + l += 3; + } + *file = f; + *line = l; + } + else + { + *file = "(builtin)"; + *line = -1; + } +} + +void print_source_line( PARSE* p ) +{ + char* file; + int line; + + get_source_line( p, &file, &line ); + if ( line < 0 ) + printf( "(builtin):" ); + else + printf( "%s:%d:", file, line); +} + +/* Print a single line of error backtrace for the given frame */ +void backtrace_line( FRAME *frame ) +{ + print_source_line( frame->procedure ); + printf( " in %s\n", frame->rulename ); +} + +/* Print the entire backtrace from the given frame to the Jambase + * which invoked it. + */ +void backtrace( FRAME *frame ) +{ + while ( frame = frame->prev ) + { + backtrace_line( frame ); + } +} + +/* A Jam version of the backtrace function, taking no arguments and + * returning a list of quadruples: FILENAME LINE MODULE. RULENAME + * describing each frame. Note that the module-name is always + * followed by a period. + */ +LIST *builtin_backtrace( PARSE *parse, FRAME *frame ) +{ + LIST* result = L0; + while ( frame = frame->prev ) + { + char* file; + int line; + char buf[32]; + get_source_line( frame->procedure, &file, &line ); + sprintf( buf, "%d", line ); + result = list_new( result, newstr( file ) ); + result = list_new( result, newstr( buf ) ); + result = list_new( result, newstr( frame->module->name ) ); + result = list_new( result, newstr( frame->rulename ) ); + } + return result; +} + +/* + * builtin_caller_module() - CALLER_MODULE ( levels ? ) + * + * If levels is not supplied, returns the name of the module of the rule which + * called the one calling this one. If levels is supplied, it is interpreted as + * an integer specifying a number of additional levels of call stack to traverse + * in order to locate the module in question. If no such module exists, + * returns the empty list. Also returns the empty list when the module in + * question is the global module. This rule is needed for implementing module + * import behavior. + */ +LIST *builtin_caller_module( PARSE *parse, FRAME *frame ) +{ + LIST* levels_arg = lol_get( frame->args, 0 ); + int levels = levels_arg ? atoi( levels_arg->string ) : 0 ; + + int i; + for (i = 0; i < levels + 2 && frame->prev; ++i) + frame = frame->prev; + + if ( frame->module == root_module() ) + { + return L0; + } + else + { + LIST* result; + + string name; + string_copy( &name, frame->module->name ); + string_pop_back( &name ); + + result = list_new( L0, newstr(name.value) ); + + string_free( &name ); + + return result; + } +} + +static void lol_build( LOL* lol, char** elements ) +{ + LIST* l = L0; + lol_init( lol ); + + while ( elements && *elements ) + { + if ( !strcmp( *elements, ":" ) ) + { + lol_add( lol, l ); + l = L0 ; + } + else + { + l = list_new( l, newstr( *elements ) ); + } + ++elements; + } + + if ( l != L0 ) + lol_add( lol, l ); +} + diff --git a/src/engine/builtins.h b/src/engine/builtins.h new file mode 100644 index 000000000..8d71fe815 --- /dev/null +++ b/src/engine/builtins.h @@ -0,0 +1,31 @@ +/* + * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. + * + * This file is part of Jam - see jam.c for Copyright information. + */ + +#ifndef JAM_BUILTINS_H +# define JAM_BUILTINS_H + +# include "frames.h" + +/* + * builtins.h - compile parsed jam statements + */ + +void load_builtins(); + +LIST *builtin_depends( PARSE *parse, FRAME *args ); +LIST *builtin_echo( PARSE *parse, FRAME *args ); +LIST *builtin_exit( PARSE *parse, FRAME *args ); +LIST *builtin_flags( PARSE *parse, FRAME *args ); +LIST *builtin_glob( PARSE *parse, FRAME *args ); +LIST *builtin_subst( PARSE *parse, FRAME *args ); +LIST *builtin_hdrmacro( PARSE *parse, FRAME *args ); +LIST *builtin_rulenames( PARSE *parse, FRAME *args ); +LIST *builtin_import( PARSE *parse, FRAME *args ); +LIST *builtin_export( PARSE *parse, FRAME *args ); +LIST *builtin_caller_module( PARSE *parse, FRAME *args ); +LIST *builtin_backtrace( PARSE *parse, FRAME *args ); + +#endif diff --git a/src/engine/common.mk b/src/engine/common.mk index 6abd3e86b..5d55eb001 100644 --- a/src/engine/common.mk +++ b/src/engine/common.mk @@ -9,7 +9,7 @@ SOURCES = \ hdrmacro.c headers.c jam.c jambase.c jamgram.c lists.c make.c make1.c \ newstr.c option.c parse.c pathunix.c pathvms.c regexp.c \ rules.c scan.c search.c subst.c timestamp.c variable.c modules.c \ - strings.c filesys.c + strings.c filesys.c builtins.c # the bootstrap "jam0" build tool # diff --git a/src/engine/compile.c b/src/engine/compile.c index 22c31ef28..398a6c0c1 100644 --- a/src/engine/compile.c +++ b/src/engine/compile.c @@ -44,6 +44,7 @@ * compile_list() - expand and return a list * compile_local() - declare (and set) local variables * compile_null() - do nothing -- a stub for parsing + * compile_on() - run rule under influence of on-target variables * compile_rule() - compile a single user defined rule * compile_rules() - compile a chain of rules * compile_set() - compile the "set variable" statement @@ -51,12 +52,10 @@ * compile_setexec() - support for `actions` - save execution string * compile_settings() - compile the "on =" (set variable on exec) statement * compile_switch() - compile 'switch' rule - * * Internal routines: * * debug_compile() - printf with indent to show rule expansion. * - * evaluate_if() - evaluate if to determine which leg to compile * evaluate_rule() - execute a rule invocation * * builtin_depends() - DEPENDS/INCLUDES rule @@ -82,32 +81,14 @@ * New compile_append() and compile_list() in * support of building lists here, rather than * in jamgram.yy. + * 01/10/00 (seiwald) - built-ins split out to builtin.c. */ static void debug_compile( int which, char *s, FRAME* frame ); - -static int evaluate_if( PARSE *parse, FRAME *frame ); - -static void backtrace_line( FRAME* frame ); -static void backtrace( FRAME* frame ); -static void get_source_line( PARSE*, char** file, int* line ); -static void print_source_line( PARSE* ); - -static LIST *builtin_depends( PARSE *parse, FRAME *frame ); -static LIST *builtin_echo( PARSE *parse, FRAME *frame ); -static LIST *builtin_exit( PARSE *parse, FRAME *frame ); -static LIST *builtin_flags( PARSE *parse, FRAME *frame ); -static LIST *builtin_hdrmacro( PARSE *parse, FRAME *frame ); -static LIST *builtin_rulenames( PARSE *parse, FRAME *frame ); -static LIST *builtin_import( PARSE *parse, FRAME *frame ); -static LIST *builtin_export( PARSE *parse, FRAME *frame ); -static LIST *builtin_caller_module( PARSE *parse, FRAME *frame ); -static LIST *builtin_backtrace( PARSE *parse, FRAME *frame ); - - -LIST *builtin_subst( PARSE *parse, FRAME *frame ); - int glob( char *s, char *c ); +/* Internal functions from builtins.c */ +void backtrace_line( FRAME *frame ); +void print_source_line( PARSE* p ); void frame_init( FRAME* frame ) @@ -124,127 +105,6 @@ void frame_free( FRAME* frame ) lol_free( frame->args ); } -/* - * compile_builtin() - define builtin rules - */ - -# define P0 (PARSE *)0 -# define C0 (char *)0 - -static void lol_build( LOL* lol, char** elements ) -{ - LIST* l = L0; - lol_init( lol ); - - while ( elements && *elements ) - { - if ( !strcmp( *elements, ":" ) ) - { - lol_add( lol, l ); - l = L0 ; - } - else - { - l = list_new( l, newstr( *elements ) ); - } - ++elements; - } - - if ( l != L0 ) - lol_add( lol, l ); -} - -static RULE* bind_builtin( char* name, LIST*(*f)(PARSE*, FRAME*), int flags, char** args ) -{ - argument_list* arg_list = 0; - - if ( args ) - { - arg_list = args_new(); - lol_build( arg_list->data, args ); - } - - return new_rule_body( root_module(), name, arg_list, - parse_make( f, P0, P0, P0, C0, C0, flags ), 1 ); -} - -static RULE* duplicate_rule( char* name, RULE* other ) -{ - return import_rule( other, root_module(), name ); -} - -void -compile_builtins() -{ - duplicate_rule( "Always", bind_builtin( "ALWAYS", builtin_flags, T_FLAG_TOUCHED, 0 ) ); - duplicate_rule( "Depends", bind_builtin( "DEPENDS", builtin_depends, T_DEPS_DEPENDS, 0 ) ); - duplicate_rule( "Echo", bind_builtin( "ECHO", builtin_echo, 0, 0 ) ); - duplicate_rule( "Exit", bind_builtin( "EXIT", builtin_exit, 0, 0 ) ); - duplicate_rule( "Includes", bind_builtin( "INCLUDES", builtin_depends, T_DEPS_INCLUDES, 0 ) ); - duplicate_rule( "HdrMacro", bind_builtin( "HDRMACRO", builtin_hdrmacro, 0, 0 ) ); - duplicate_rule( "Leaves", bind_builtin( "LEAVES", builtin_flags, T_FLAG_LEAVES, 0 ) ); - duplicate_rule( "NoCare", bind_builtin( "NOCARE", builtin_flags, T_FLAG_NOCARE, 0 ) ); - duplicate_rule( "NOTIME", - duplicate_rule( "NotFile", - bind_builtin( "NOTFILE", builtin_flags, T_FLAG_NOTFILE, 0 ) ) ); - - duplicate_rule( "NoUpdate", bind_builtin( "NOUPDATE", builtin_flags, T_FLAG_NOUPDATE, 0 ) ); - duplicate_rule( "Temporary", bind_builtin( "TEMPORARY", builtin_flags, T_FLAG_TEMP, 0 ) ); - - /* FAIL_EXPECTED is an experimental built-in that is used to indicate */ - /* that the result of a target build action should be inverted (ok <=> fail) */ - /* this can be useful when performing test runs from Jamfiles.. */ - /* */ - /* Beware that this rule might disappear or be renamed in the future.. */ - /* contact david.turner@freetype.org for more details.. */ - bind_builtin( "FAIL_EXPECTED", builtin_flags, T_FLAG_FAIL_EXPECTED, 0 ); - - { - char* args[] = { "string", "pattern", "replacements", "+", 0 }; - duplicate_rule( "subst", bind_builtin( "SUBST", builtin_subst, 0, args ) ); - } - - { - char* args[] = { - "module", "?", 0 - }; - - bind_builtin( "RULENAMES", builtin_rulenames, 0, args ); - } - - { - char* args[] = { - "source_module", "?" - , ":", "source_rules", "*" - , ":", "target_module", "?" - , ":", "target_rules", "*" - , ":", "localize", "?", 0 - }; - - bind_builtin( "IMPORT", builtin_import, 0, args ); - } - - - { - char* args[] = { - "module", "?" - , ":", "rules", "*", 0 - }; - - bind_builtin( "EXPORT", builtin_export, 0, args ); - } - - { - char* args[] = { "levels", "?", 0 }; - bind_builtin( "CALLER_MODULE", builtin_caller_module, 0, args ); - } - - { - char* args[] = { 0 }; - bind_builtin( "BACKTRACE", builtin_backtrace, 0, args ); - } -} - /* * compile_append() - append list results of two statements * @@ -264,6 +124,124 @@ compile_append( parse_evaluate( parse->right, frame ) ); } +/* + * compile_eval() - evaluate if to determine which leg to compile + * + * Returns: + * list if expression true - compile 'then' clause + * L0 if expression false - compile 'else' clause + */ + +static int +lcmp( LIST *t, LIST *s ) +{ + int status = 0; + + while( !status && ( t || s ) ) + { + char *st = t ? t->string : ""; + char *ss = s ? s->string : ""; + + status = strcmp( st, ss ); + + t = t ? list_next( t ) : t; + s = s ? list_next( s ) : s; + } + + return status; +} + +LIST * +compile_eval( + PARSE *parse, + FRAME *frame ) +{ + LIST *ll = parse_evaluate( parse->left, frame ); + LIST *lr = parse->right ? parse_evaluate( parse->right, frame ) : 0; + LIST *s, *t; + int status = 0; + + switch( parse->num ) + { + case EXPR_EXISTS: + if( ll && ll->string[0] ) status = 1; + break; + + case EXPR_NOT: + if( !ll ) status = 1; + break; + + case EXPR_AND: + if ( ll ) + { + if ( parse->third ) lr = parse_evaluate( parse->third, frame ); + if ( lr ) status = 1; + } + break; + + case EXPR_OR: + if ( ll ) + { + status = 1; + } + else + { + if ( parse->third ) lr = parse_evaluate( parse->third, frame ); + if ( lr ) status = 1; + } + break; + + case EXPR_IN: + /* "a in b": make sure each of */ + /* ll is equal to something in lr. */ + + for( t = ll; t; t = list_next( t ) ) + { + for( s = lr; s; s = list_next( s ) ) + if( !strcmp( t->string, s->string ) ) + break; + if( !s ) break; + } + + /* No more ll? Success */ + + if( !t ) status = 1; + + break; + + case EXPR_EQUALS: if( lcmp( ll, lr ) == 0 ) status = 1; break; + case EXPR_NOTEQ: if( lcmp( ll, lr ) != 0 ) status = 1; break; + case EXPR_LESS: if( lcmp( ll, lr ) < 0 ) status = 1; break; + case EXPR_LESSEQ: if( lcmp( ll, lr ) <= 0 ) status = 1; break; + case EXPR_MORE: if( lcmp( ll, lr ) > 0 ) status = 1; break; + case EXPR_MOREEQ: if( lcmp( ll, lr ) >= 0 ) status = 1; break; + + } + + if( DEBUG_IF ) + { + debug_compile( 0, "if", frame ); + list_print( ll ); + printf( "(%d) ", status ); + list_print( lr ); + printf( "\n" ); + } + + /* Find something to return. */ + /* In odd circumstances (like "" = "") */ + /* we'll have to return a new string. */ + + if( !status ) t = 0; + else if( ll ) t = ll, ll = 0; + else if( lr ) t = lr, lr = 0; + else t = list_new( L0, newstr( "1" ) ); + + if( ll ) list_free( ll ); + if( lr ) list_free( lr ); + return t; +} + + /* * compile_foreach() - compile the "for x in y" statement * @@ -322,8 +300,10 @@ compile_if( PARSE *p, FRAME *frame ) { - if( evaluate_if( p->left, frame ) ) + LIST *l = parse_evaluate( p->left, frame ); + if( l ) { + list_free( l ); return parse_evaluate( p->right, frame ); } else @@ -337,127 +317,17 @@ compile_while( PARSE *p, FRAME *frame ) { - while ( evaluate_if( p->left, frame ) ) + LIST *r = 0; + LIST *l; + while ( l = parse_evaluate( p->left, frame ) ) { - list_free( parse_evaluate( p->right, frame ) ); + list_free( l ); + if( r ) list_free( r ); + r = parse_evaluate( p->right, frame ); } - return L0; + return r; } -/* - * evaluate_if() - evaluate if to determine which leg to compile - * - * Returns: - * !0 if expression true - compile 'then' clause - * 0 if expression false - compile 'else' clause - */ - -static int -evaluate_if( - PARSE *parse, - FRAME *frame ) -{ - int status; - - if( parse->num <= COND_OR ) - { - /* Handle one of the logical operators */ - - switch( parse->num ) - { - case COND_NOT: - status = !evaluate_if( parse->left, frame ); - break; - - case COND_AND: - status = evaluate_if( parse->left, frame ) && - evaluate_if( parse->right, frame ); - break; - - case COND_OR: - status = evaluate_if( parse->left, frame ) || - evaluate_if( parse->right, frame ); - break; - - default: - status = 0; /* can't happen */ - } - } - else - { - /* Handle one of the comparison operators */ - /* Expand targets and sources */ - - LIST *nt = parse_evaluate( parse->left, frame ); - LIST *ns = parse_evaluate( parse->right, frame ); - - /* "a in b" make sure each of a is equal to something in b. */ - /* Otherwise, step through pairwise comparison. */ - - if( parse->num == COND_IN ) - { - LIST *s, *t; - - /* Try each t until failure. */ - - for( status = 1, t = nt; status && t; t = list_next( t ) ) - { - int stat1; - - /* Try each s until success */ - - for( stat1 = 0, s = ns; !stat1 && s; s = list_next( s ) ) - stat1 = !strcmp( t->string, s->string ); - - status = stat1; - } - } - else - { - LIST *s = ns, *t = nt; - - status = 0; - - while( !status && ( t || s ) ) - { - char *st = t ? t->string : ""; - char *ss = s ? s->string : ""; - - status = strcmp( st, ss ); - - t = t ? list_next( t ) : t; - s = s ? list_next( s ) : s; - } - } - - switch( parse->num ) - { - case COND_EXISTS: status = status > 0 ; break; - case COND_EQUALS: status = !status; break; - case COND_NOTEQ: status = status != 0; break; - case COND_LESS: status = status < 0; break; - case COND_LESSEQ: status = status <= 0; break; - case COND_MORE: status = status > 0; break; - case COND_MOREEQ: status = status >= 0; break; - case COND_IN: /* status = status */ break; - } - - if( DEBUG_IF ) - { - debug_compile( 0, "if", frame); - list_print( nt ); - printf( "(%d)", status ); - list_print( ns ); - printf( "\n" ); - } - - list_free( nt ); - list_free( ns ); - - } - - return status; -} /* * compile_include() - support for 'include' - call include() on file @@ -614,6 +484,48 @@ compile_null( return L0; } +/* + * compile_on() - run rule under influence of on-target variables + * + * parse->left list of files to include (can only do 1) + * parse->right rule to run + * + * EXPERIMENTAL! + */ + +LIST * +compile_on( + PARSE *parse, + FRAME *frame ) +{ + LIST *nt = parse_evaluate( parse->left, frame ); + LIST *result = 0; + PARSE *p; + + if( DEBUG_COMPILE ) + { + debug_compile( 0, "on", frame ); + list_print( nt ); + printf( "\n" ); + } + + if( nt ) + { + TARGET *t = bindtarget( nt->string ); + pushsettings( t->settings ); + + result = parse_evaluate( parse->right, frame ); + + t->boundname = search( t->name, &t->time ); + popsettings( t->settings ); + } + + list_free( nt ); + + return result; +} + + /* * compile_rule() - compile a single user defined rule * @@ -952,8 +864,8 @@ evaluate_rule( /* * compile_rules() - compile a chain of rules * - * parse->left more compile_rules() by left-recursion - * parse->right single rule + * parse->left single rule + * parse->right more compile_rules() by right-recursion */ LIST * @@ -962,9 +874,12 @@ compile_rules( FRAME *frame ) { /* Ignore result from first statement; return the 2nd. */ + /* Optimize recursion on the right by looping. */ - list_free( parse_evaluate( parse->left, frame ) ); - return parse_evaluate( parse->right, frame ); + do list_free( parse_evaluate( parse->left, frame ) ); + while( (parse = parse->right)->func == compile_rules ); + + return parse_evaluate( parse, frame ); } /* @@ -1211,360 +1126,6 @@ compile_switch( return result; } - - -/* - * builtin_depends() - DEPENDS/INCLUDES rule - * - * The DEPENDS builtin rule appends each of the listed sources on the - * dependency list of each of the listed targets. It binds both the - * targets and sources as TARGETs. - */ - -static LIST * -builtin_depends( - PARSE *parse, - FRAME *frame ) -{ - LIST *targets = lol_get( frame->args, 0 ); - LIST *sources = lol_get( frame->args, 1 ); - int which = parse->num; - LIST *l; - - for( l = targets; l; l = list_next( l ) ) - { - TARGET *t = bindtarget( l->string ); - t->deps[ which ] = targetlist( t->deps[ which ], sources ); - } - - return L0; -} - -/* - * builtin_echo() - ECHO rule - * - * The ECHO builtin rule echoes the targets to the user. No other - * actions are taken. - */ - -static LIST * -builtin_echo( - PARSE *parse, - FRAME *frame ) -{ - list_print( lol_get( frame->args, 0 ) ); - printf( "\n" ); - return L0; -} - -/* - * builtin_exit() - EXIT rule - * - * The EXIT builtin rule echoes the targets to the user and exits - * the program with a failure status. - */ - -static LIST * -builtin_exit( - PARSE *parse, - FRAME *frame ) -{ - list_print( lol_get( frame->args, 0 ) ); - printf( "\n" ); - exit( EXITBAD ); /* yeech */ - return L0; -} - -/* - * builtin_flags() - NOCARE, NOTFILE, TEMPORARY rule - * - * Builtin_flags() marks the target with the appropriate flag, for use - * by make0(). It binds each target as a TARGET. - */ - -static LIST * -builtin_flags( - PARSE *parse, - FRAME *frame ) -{ - LIST *l = lol_get( frame->args, 0 ); - - for( ; l; l = list_next( l ) ) - bindtarget( l->string )->flags |= parse->num; - - return L0; -} - - -static LIST * -builtin_hdrmacro( - PARSE *parse, - FRAME *frame ) -{ - LIST* l = lol_get( frame->args, 0 ); - - for ( ; l; l = list_next(l) ) - { - TARGET* t = bindtarget( l->string ); - - /* scan file for header filename macro definitions */ - if ( DEBUG_HEADER ) - printf( "scanning '%s' for header file macro definitions\n", - l->string ); - - macro_headers( t ); - } - - return L0; -} - -/* builtin_rulenames() - RULENAMES ( MODULE ? ) - * - * Returns a list of the non-local rule names in the given MODULE. If - * MODULE is not supplied, returns the list of rule names in the - * global module. - */ - -/* helper function for builtin_rulenames(), below */ -static void add_rule_name( void* r_, void* result_ ) -{ - RULE* r = r_; - LIST** result = result_; - - if ( r->exported ) - *result = list_new( *result, copystr( r->name ) ); -} - -static LIST * -builtin_rulenames( - PARSE *parse, - FRAME *frame ) -{ - LIST *arg0 = lol_get( frame->args, 0 ); - LIST *result = L0; - module* source_module = bindmodule( arg0 ? arg0->string : 0 ); - - hashenumerate( source_module->rules, add_rule_name, &result ); - return result; -} - -static void unknown_rule( FRAME *frame, char* key, char *module_name, char *rule_name ) -{ - backtrace_line( frame->prev ); - printf( "%s error: rule \"%s\" unknown in module \"%s\"\n", key, rule_name, module_name ); - backtrace( frame->prev ); - exit(1); - -} - -/* - * builtin_import() - IMPORT ( SOURCE_MODULE ? : SOURCE_RULES * : TARGET_MODULE ? : TARGET_RULES * : LOCALIZE ? ) - * - * The IMPORT rule imports rules from the SOURCE_MODULE into the - * TARGET_MODULE as local rules. If either SOURCE_MODULE or - * TARGET_MODULE is not supplied, it refers to the global - * module. SOURCE_RULES specifies which rules from the SOURCE_MODULE - * to import; TARGET_RULES specifies the names to give those rules in - * TARGET_MODULE. If SOURCE_RULES contains a name which doesn't - * correspond to a rule in SOURCE_MODULE, or if it contains a - * different number of items than TARGET_RULES, an error is issued. - * if LOCALIZE is specified, the rules will be executed in - * TARGET_MODULE, with corresponding access to its module local - * variables. - */ -static LIST * -builtin_import( - PARSE *parse, - FRAME *frame ) -{ - LIST *source_module_list = lol_get( frame->args, 0 ); - LIST *source_rules = lol_get( frame->args, 1 ); - LIST *target_module_list = lol_get( frame->args, 2 ); - LIST *target_rules = lol_get( frame->args, 3 ); - LIST *localize = lol_get( frame->args, 4 ); - - module* target_module = bindmodule( target_module_list ? target_module_list->string : 0 ); - module* source_module = bindmodule( source_module_list ? source_module_list->string : 0 ); - - LIST *source_name, *target_name; - - for ( source_name = source_rules, target_name = target_rules; - source_name && target_name; - source_name = list_next( source_name ) - , target_name = list_next( target_name ) ) - { - RULE r_, *r = &r_, *imported; - r_.name = source_name->string; - - if ( !hashcheck( source_module->rules, (HASHDATA**)&r ) ) - unknown_rule( frame, "IMPORT", source_module->name, r_.name ); - - imported = import_rule( r, target_module, target_name->string ); - if ( localize ) - imported->module = target_module; - imported->exported = 0; /* this rule is really part of some other module; just refer to it here, but don't let it out */ - } - - if ( source_name || target_name ) - { - backtrace_line( frame->prev ); - printf( "import error: length of source and target rule name lists don't match" ); - backtrace( frame->prev ); - exit(1); - } - - return L0; -} - - -/* - * builtin_export() - EXPORT ( MODULE ? : RULES * ) - * - * The EXPORT rule marks RULES from the SOURCE_MODULE as non-local - * (and thus exportable). If an element of RULES does not name a rule - * in MODULE, an error is issued. - */ -static LIST * -builtin_export( - PARSE *parse, - FRAME *frame ) -{ - LIST *module_list = lol_get( frame->args, 0 ); - LIST *rules = lol_get( frame->args, 1 ); - - module* m = bindmodule( module_list ? module_list->string : 0 ); - - - for ( ; rules; rules = list_next( rules ) ) - { - RULE r_, *r = &r_; - r_.name = rules->string; - - if ( !hashcheck( m->rules, (HASHDATA**)&r ) ) - unknown_rule( frame, "EXPORT", m->name, r_.name ); - - r->exported = 1; - } - return L0; -} - -/* Retrieve the file and line number that should be indicated for a - * given procedure in debug output or an error backtrace - */ -static void get_source_line( PARSE* procedure, char** file, int* line ) -{ - if ( procedure ) - { - char* f = procedure->file; - int l = procedure->line; - if ( !strcmp( f, "+" ) ) - { - f = "jambase.c"; - l += 3; - } - *file = f; - *line = l; - } - else - { - *file = "(builtin)"; - *line = -1; - } -} - -static void print_source_line( PARSE* p ) -{ - char* file; - int line; - - get_source_line( p, &file, &line ); - if ( line < 0 ) - printf( "(builtin):" ); - else - printf( "%s:%d:", file, line); -} - -/* Print a single line of error backtrace for the given frame */ -static void backtrace_line( FRAME *frame ) -{ - print_source_line( frame->procedure ); - printf( " in %s\n", frame->rulename ); -} - -/* Print the entire backtrace from the given frame to the Jambase - * which invoked it. - */ -static void backtrace( FRAME *frame ) -{ - while ( frame = frame->prev ) - { - backtrace_line( frame ); - } -} - -/* A Jam version of the backtrace function, taking no arguments and - * returning a list of quadruples: FILENAME LINE MODULE. RULENAME - * describing each frame. Note that the module-name is always - * followed by a period. - */ -static LIST *builtin_backtrace( PARSE *parse, FRAME *frame ) -{ - LIST* result = L0; - while ( frame = frame->prev ) - { - char* file; - int line; - char buf[32]; - get_source_line( frame->procedure, &file, &line ); - sprintf( buf, "%d", line ); - result = list_new( result, newstr( file ) ); - result = list_new( result, newstr( buf ) ); - result = list_new( result, newstr( frame->module->name ) ); - result = list_new( result, newstr( frame->rulename ) ); - } - return result; -} - -/* - * builtin_caller_module() - CALLER_MODULE ( levels ? ) - * - * If levels is not supplied, returns the name of the module of the rule which - * called the one calling this one. If levels is supplied, it is interpreted as - * an integer specifying a number of additional levels of call stack to traverse - * in order to locate the module in question. If no such module exists, - * returns the empty list. Also returns the empty list when the module in - * question is the global module. This rule is needed for implementing module - * import behavior. - */ -static LIST *builtin_caller_module( PARSE *parse, FRAME *frame ) -{ - LIST* levels_arg = lol_get( frame->args, 0 ); - int levels = levels_arg ? atoi( levels_arg->string ) : 0 ; - - int i; - for (i = 0; i < levels + 2 && frame->prev; ++i) - frame = frame->prev; - - if ( frame->module == root_module() ) - { - return L0; - } - else - { - LIST* result; - - string name; - string_copy( &name, frame->module->name ); - string_pop_back( &name ); - - result = list_new( L0, newstr(name.value) ); - - string_free( &name ); - - return result; - } -} - /* * debug_compile() - printf with indent to show rule expansion. */ diff --git a/src/engine/compile.h b/src/engine/compile.h index 31d686188..89811ef4a 100644 --- a/src/engine/compile.h +++ b/src/engine/compile.h @@ -28,11 +28,13 @@ void compile_builtins(); LIST *compile_append( PARSE *parse, FRAME *frame ); LIST *compile_foreach( PARSE *parse, FRAME *frame ); LIST *compile_if( PARSE *parse, FRAME *frame ); +LIST *compile_eval( PARSE *parse, FRAME *args ); LIST *compile_include( PARSE *parse, FRAME *frame ); LIST *compile_list( PARSE *parse, FRAME *frame ); LIST *compile_local( PARSE *parse, FRAME *frame ); LIST *compile_module( PARSE *parse, FRAME *frame ); LIST *compile_null( PARSE *parse, FRAME *frame ); +LIST *compile_on( PARSE *parse, FRAME *frame ); LIST *compile_rule( PARSE *parse, FRAME *frame ); LIST *compile_rules( PARSE *parse, FRAME *frame ); LIST *compile_set( PARSE *parse, FRAME *frame ); @@ -66,18 +68,18 @@ void profile_dump(); /* Conditions for compile_if() */ -# define COND_NOT 0 /* ! cond */ -# define COND_AND 1 /* cond && cond */ -# define COND_OR 2 /* cond || cond */ +# define EXPR_NOT 0 /* ! cond */ +# define EXPR_AND 1 /* cond && cond */ +# define EXPR_OR 2 /* cond || cond */ -# define COND_EXISTS 3 /* arg */ -# define COND_EQUALS 4 /* arg = arg */ -# define COND_NOTEQ 5 /* arg != arg */ -# define COND_LESS 6 /* arg < arg */ -# define COND_LESSEQ 7 /* arg <= arg */ -# define COND_MORE 8 /* arg > arg */ -# define COND_MOREEQ 9 /* arg >= arg */ -# define COND_IN 10 /* arg in arg */ +# define EXPR_EXISTS 3 /* arg */ +# define EXPR_EQUALS 4 /* arg = arg */ +# define EXPR_NOTEQ 5 /* arg != arg */ +# define EXPR_LESS 6 /* arg < arg */ +# define EXPR_LESSEQ 7 /* arg <= arg */ +# define EXPR_MORE 8 /* arg > arg */ +# define EXPR_MOREEQ 9 /* arg >= arg */ +# define EXPR_IN 10 /* arg in arg */ #endif // COMPILE_DWA20011022_H diff --git a/src/engine/expand.c b/src/engine/expand.c index 366afd508..b6a918483 100644 --- a/src/engine/expand.c +++ b/src/engine/expand.c @@ -1,53 +1,43 @@ -/* - * Copyright 1993, 1995 Christopher Seiwald. - * - * This file is part of Jam - see jam.c for Copyright information. - */ -/* This file is ALSO: - * (C) Copyright David Abrahams 2001. Permission to copy, use, - * modify, sell and distribute this software is granted provided this - * copyright notice appears in all copies. This software is provided - * "as is" without express or implied warranty, and with no claim as - * to its suitability for any purpose. - */ - # include "jam.h" # include "lists.h" # include "variable.h" # include "expand.h" -# include "filesys.h" +# include "pathsys.h" # include "newstr.h" -# include "strings.h" - # include -# include + /* * expand.c - expand a buffer, given variable values * * External routines: * - * var_expand() - variable-expand input string into list of strings + * var_expand() - variable-expand input string into list of strings * * Internal routines: * - * var_edit() - copy input target name to output, performing : modifiers - * var_mods() - parse : modifiers into FILENAME structure + * var_edit_parse() - parse : modifiers into PATHNAME structure + * var_edit_file() - copy input target name to output, modifying filename + * var_edit_shift() - do upshift/downshift mods * * 01/25/94 (seiwald) - $(X)$(UNDEF) was expanding like plain $(X) * 04/13/94 (seiwald) - added shorthand L0 for null list pointer + * 01/11/01 (seiwald) - added support for :E=emptyvalue, :J=joinval */ typedef struct { - char downshift; /* :L -- downshift result */ - char upshift; /* :U -- upshift result */ - char parent; /* :P -- go to parent directory */ - char to_slashes; /* :T -- convert "\" to "/" */ -} VAR_ACTS ; + PATHNAME f; /* :GDBSMR -- pieces */ + char parent; /* :P -- go to parent directory */ + char filemods; /* one of the above applied */ + char downshift; /* :L -- downshift result */ + char upshift; /* :U -- upshift result */ + char to_slashes; /* :T -- convert "\" to "/" */ + PATHPART empty; /* :E -- default for empties */ + PATHPART join; /* :J -- join list with char */ +} VAR_EDITS ; -static void var_edit( char *in, char *mods, string *out ); -static void var_mods( char *mods, FILENAME *f, VAR_ACTS *acts ); - -static int adjust_index( int index, int length ); +static void var_edit_parse( char *mods, VAR_EDITS *edits ); +static void var_edit_file( char *in, string *out, VAR_EDITS *edits ); +static void var_edit_shift( string *out, VAR_EDITS *edits ); # define MAGIC_COLON '\001' # define MAGIC_LEFT '\002' @@ -73,9 +63,11 @@ var_expand( LOL *lol, int cancopyin ) { - string buf[1]; - size_t prefix_length; - char *out; + char out_buf[ MAXSYM ]; + string buf[1]; + string out1; /* Temporary buffer */ + size_t prefix_length; + char *out; char *inp = in; char *ov; /* for temp copy of variable in outbuf */ int depth; @@ -99,10 +91,10 @@ var_expand( } } - /* See if we can use a simple copy of in to out. */ + /* Just try simple copy of in to out. */ - while ( in < end ) - if ( *in++ == '$' && *in == '(' ) + while( in < end ) + if( *in++ == '$' && *in == '(' ) goto expand; /* No variables expanded - just add copy of input string to list. */ @@ -111,47 +103,47 @@ var_expand( /* item, we can use the copystr() to put it on the new list. */ /* Otherwise, we use the slower newstr(). */ - if ( cancopyin ) - { + if( cancopyin ) + { return list_new( l, copystr( inp ) ); - } + } else - { - LIST* r; - string_new( buf ); - string_append_range( buf, inp, in ); - - r = list_new( l, newstr( buf->value ) ); - string_free( buf ); - return r; - } + { + LIST* r; + string_new( buf ); + string_append_range( buf, inp, end ); + + r = list_new( l, newstr( buf->value) ); + string_free( buf ); + return r; + } expand: - string_new( buf ); - string_append_range( buf, inp, in - 1 ); /* copy in initial stuff */ + string_new( buf ); + string_append_range( buf, inp, in - 1); /* copy the part before '$'. */ /* - * Input so far (ignore blanks): - * - * stuff-in-outbuf $(variable) remainder - * ^ ^ - * in end - * Output so far: - * - * stuff-in-outbuf $ - * ^ ^ - * out_buf out - * - * - * We just copied the $ of $(...), so back up one on the output. - * We now find the matching close paren, copying the variable and - * modifiers between the $( and ) temporarily into out_buf, so that - * we can replace :'s with MAGIC_COLON. This is necessary to avoid - * being confused by modifier values that are variables containing - * :'s. Ugly. - */ + * Input so far (ignore blanks): + * + * stuff-in-outbuf $(variable) remainder + * ^ ^ + * in end + * Output so far: + * + * stuff-in-outbuf $ + * ^ ^ + * out_buf out + * + * + * We just copied the $ of $(...), so back up one on the output. + * We now find the matching close paren, copying the variable and + * modifiers between the $( and ) temporarily into out_buf, so that + * we can replace :'s with MAGIC_COLON. This is necessary to avoid + * being confused by modifier values that are variables containing + * :'s. Ugly. + */ depth = 1; - inp = ++in; /* skip over the '(' */ + inp = ++in; /* skip over the '(' */ while( in < end && depth ) { @@ -219,103 +211,198 @@ var_expand( for( vars = variables; vars; vars = list_next( vars ) ) { - LIST *value; + LIST *value, *evalue = 0; char *colon; char *bracket; - int i, sub1, sub2; - string variable; - char *varname; + string variable; + char *varname; + int sub1 = 0, sub2 = -1; + VAR_EDITS edits; /* Look for a : modifier in the variable name */ /* Must copy into varname so we can modify it */ - - string_copy( &variable, vars->string ); - varname = variable.value; + + string_copy( &variable, vars->string ); + varname = variable.value; if( colon = strchr( varname, MAGIC_COLON ) ) - { - string_truncate( &variable, colon - varname ); - } - - if( bracket = strchr( varname, MAGIC_LEFT ) ) { - char *dash = 0; + string_truncate( &variable, colon - varname ); + var_edit_parse( colon + 1, &edits ); + } - if( bracket[1] && ( dash = strchr( bracket + 2, '-' ) ) ) - { - if( dash == bracket + 2 && *( bracket + 1 ) == '-') - --dash; - string_truncate( &variable, dash - varname ); - sub1 = atoi( bracket + 1 ); - sub2 = atoi( dash + 1 ); - } - else - { - sub1 = sub2 = atoi( bracket + 1 ); - } + /* Look for [x-y] subscripting */ + /* sub1 and sub2 are x and y. */ + + if ( bracket = strchr( varname, MAGIC_LEFT ) ) + { + /* + ** Make all syntax errors in [] subscripting + ** result in the same behavior: silenty return an empty + ** expansion (by setting sub2 = 0). Brute force parsing; + ** May get moved into yacc someday. + */ + + char *s = bracket + 1; string_truncate( &variable, bracket - varname ); - } - else - { - sub1 = sub2 = 0; /* not needed */ - } + + do /* so we can use "break" */ + { + /* Allow negative indexes. */ + if (! isdigit( *s ) && ! ( *s == '-') ) + { + sub2 = 0; + break; + } + sub1 = atoi(s); + + /* Skip over the first symbol, which is either a digit or dash. */ + s++; + while ( isdigit( *s ) ) s++; + + if ( *s == MAGIC_RIGHT ) + { + sub2 = sub1; + break; + } + + if ( *s != '-') + { + sub2 = 0; + break; + } + + s++; + + if ( *s == MAGIC_RIGHT ) + { + sub2 = -1; + break; + } + + if (! isdigit( *s ) && ! ( *s == '-') ) + { + sub2 = 0; + break; + } + + /* First, compute the index of the last element. */ + sub2 = atoi(s); + s++; + while ( isdigit( *s ) ) s++; + + if ( *s != MAGIC_RIGHT) + sub2 = 0; + + } while (0); + + /* + ** Anything but the end of the string, or the colon + ** introducing a modifier is a syntax error. + */ + + s++; + if (*s && *s != MAGIC_COLON) + sub2 = 0; + + *bracket = '\0'; + } /* Get variable value, specially handling $(<), $(>), $(n) */ if( varname[0] == '<' && !varname[1] ) - { value = lol_get( lol, 0 ); - } else if( varname[0] == '>' && !varname[1] ) - { value = lol_get( lol, 1 ); - } else if( varname[0] >= '1' && varname[0] <= '9' && !varname[1] ) - { value = lol_get( lol, varname[0] - '1' ); - } else - { value = var_get( varname ); - } - - /* The fast path: $(x) - just copy the variable value. */ - if( out == buf->value && !bracket && !colon && in == end ) + /* Handle negitive indexes: part two. */ + { + int length = list_length( value ); + + if (sub1 < 0) + sub1 = length + sub1; + else + sub1 -= 1; + + if (sub2 < 0) + sub2 = length + 1 + sub2 - sub1; + else + sub2 -= sub1; + /* + ** The "sub2 < 0" test handles the semantic error + ** of sub2 < sub1. + */ + if ( sub2 < 0 ) + sub2 = 0; + } + + + + /* The fast path: $(x) - just copy the variable value. */ + /* This is only an optimization */ + + if( out == out_buf && !bracket && !colon && in == end ) { - string_free( &variable ); + string_free( &variable ); l = list_copy( l, value ); continue; } - /* Adjust negative indices */ - if ( sub1 < 0 || sub2 < 0 ) - { - int length = list_length( value ); - sub1 = adjust_index( sub1, length ); - sub2 = adjust_index( sub2, length ); - } + /* Handle start subscript */ + + while( sub1 > 0 && value ) + --sub1, value = list_next( value ); + + /* Empty w/ :E=default? */ + + if( !value && colon && edits.empty.ptr ) + evalue = value = list_new( L0, newstr( edits.empty.ptr ) ); /* For each variable value */ - for( i = 1; value; i++, value = list_next( value ) ) + + string_new( &out1 ); + for( ; value; value = list_next( value ) ) { LIST *rem; - size_t postfix_start; + size_t postfix_start; - /* Skip members not in subscript */ + /* Handle end subscript (length actually) */ - if( bracket && ( i < sub1 || sub2 && i > sub2 ) ) - continue; + if( sub2 >= 0 && --sub2 < 0 ) + break; - string_truncate( buf, prefix_length ); + string_truncate( buf, prefix_length ); /* Apply : mods, if present */ - if( colon ) - var_edit( value->string, colon + 1, buf ); + if( colon && edits.filemods ) + var_edit_file( value->string, &out1, &edits ); else - string_append( buf, value->string ); + string_append( &out1, value->string ); + + if( colon && ( edits.upshift || edits.downshift || edits.to_slashes ) ) + var_edit_shift( &out1, &edits ); + + /* Handle :J=joinval */ + /* If we have more values for this var, just */ + /* keep appending them (with the join value) */ + /* rather than creating separate LIST elements. */ + + if( colon && edits.join.ptr && + ( list_next( value ) || list_next( vars ) ) ) + { + string_append( &out1, edits.join.ptr ); + continue; + } + + string_append( buf, out1.value ); + string_free( &out1 ); + string_new( &out1 ); /* If no remainder, append result to output chain. */ @@ -325,22 +412,27 @@ var_expand( continue; } + /* For each remainder, append the complete string */ + /* to the output chain. */ /* Remember the end of the variable expansion so */ /* we can just tack on each instance of 'remainder' */ - postfix_start = buf->size; - - /* For each remainder, or just once if no remainder, */ - /* append the complete string to the output chain */ + postfix_start = buf->size; for( rem = remainder; rem; rem = list_next( rem ) ) { - string_truncate( buf, postfix_start ); - string_append( buf, rem->string ); + string_truncate( buf, postfix_start ); + string_append( buf, rem->string ); l = list_new( l, newstr( buf->value ) ); } + string_free( &variable ); } - string_free( &variable ); + string_new( &out1 ); + + /* Toss used empty */ + + if( evalue ) + list_free( evalue ); } /* variables & remainder were gifts from var_expand */ @@ -358,92 +450,17 @@ var_expand( printf( "\n" ); } - string_free( buf ); + string_free( buf ); return l; } } /* - * var_edit() - copy input target name to output, performing : modifiers - */ - -static void -var_edit( - char *in, - char *mods, - string *out) -{ - FILENAME oldf, newf; - VAR_ACTS acts; - - /* Parse apart original filename, putting parts into "oldf" */ - - file_parse( in, &oldf ); - - /* Parse apart modifiers, putting them into "newf" */ - - var_mods( mods, &newf, &acts ); - - /* Replace any oldf with newf */ - - if( newf.f_grist.ptr ) - oldf.f_grist = newf.f_grist; - - if( newf.f_root.ptr ) - oldf.f_root = newf.f_root; - - if( newf.f_dir.ptr ) - oldf.f_dir = newf.f_dir; - - if( newf.f_base.ptr ) - oldf.f_base = newf.f_base; - - if( newf.f_suffix.ptr ) - oldf.f_suffix = newf.f_suffix; - - if( newf.f_member.ptr ) - oldf.f_member = newf.f_member; - - /* If requested, modify oldf to point to parent */ - - if( acts.parent ) - file_parent( &oldf ); - - /* Put filename back together */ - - file_build( &oldf, out, 0 ); - - /* Handle upshifting, downshifting now */ - /* Handle conversion of "\" to "/" */ - { - char* p; - for ( p = out->value; *p; ++p) - { - if( acts.upshift ) - { - *p = toupper( *p ); - } - else if( acts.downshift ) - { - *p = tolower( *p ); - } - if ( acts.to_slashes ) - { - if ( *p == '\\' ) - *p = '/'; - } - } - out->size = p - out->value; - } -} - - -/* - * var_mods() - parse : modifiers into FILENAME structure + * var_edit_parse() - parse : modifiers into PATHNAME structure * * The : modifiers in a $(varname:modifier) currently support replacing * or omitting elements of a filename, and so they are parsed into a - * FILENAME structure (which contains pointers into the original string). + * PATHNAME structure (which contains pointers into the original string). * * Modifiers of the form "X=value" replace the component X with * the given value. Modifiers without the "=value" cause everything @@ -470,109 +487,164 @@ var_edit( * f->f_xxx.len = 0 * -> omit component xxx * - * var_edit() above and file_build() obligingly follow this convention. + * var_edit_file() below and path_build() obligingly follow this convention. */ static void -var_mods( +var_edit_parse( char *mods, - FILENAME *f, - VAR_ACTS *acts ) + VAR_EDITS *edits ) { - char *flags = "GRDBSMT"; int havezeroed = 0; - memset( (char *)f, 0, sizeof( *f ) ); - memset( (char *)acts, 0, sizeof( *acts ) ); + memset( (char *)edits, 0, sizeof( *edits ) ); while( *mods ) { - char *fl; - FILEPART *fp; + char *p; + PATHPART *fp; - /* First take care of :U or :L (upshift, downshift) */ - - if( *mods == 'L' ) + switch( *mods++ ) { - acts->downshift = 1; - ++mods; - continue; + case 'L': edits->downshift = 1; continue; + case 'U': edits->upshift = 1; continue; + case 'P': edits->parent = edits->filemods = 1; continue; + case 'E': fp = &edits->empty; goto strval; + case 'J': fp = &edits->join; goto strval; + case 'G': fp = &edits->f.f_grist; goto fileval; + case 'R': fp = &edits->f.f_root; goto fileval; + case 'D': fp = &edits->f.f_dir; goto fileval; + case 'B': fp = &edits->f.f_base; goto fileval; + case 'S': fp = &edits->f.f_suffix; goto fileval; + case 'M': fp = &edits->f.f_member; goto fileval; + case 'T': edits->to_slashes = 1; continue; + + default: return; /* should complain, but so what... */ } - else if( *mods == 'U' ) + + fileval: + + /* Handle :CHARS, where each char (without a following =) */ + /* selects a particular file path element. On the first such */ + /* char, we deselect all others (by setting ptr = "", len = 0) */ + /* and for each char we select that element (by setting ptr = 0) */ + + edits->filemods = 1; + + if( *mods != '=' ) { - acts->upshift = 1; - ++mods; - continue; - } - else if( *mods == 'P' ) - { - acts->parent = 1; - ++mods; - continue; - } - else if ( *mods == 'T' ) - { - acts->to_slashes = 1; - ++mods; - continue; - } - - /* Now handle the file component flags */ - - if( !( fl = strchr( flags, *mods++ ) ) ) - break; /* should complain, but so what... */ - - fp = &f->part[ fl - flags ]; - - if( *mods++ != '=' ) - { - /* :X - turn everything but X off */ - int i; - mods--; - if( !havezeroed++ ) for( i = 0; i < 6; i++ ) { - f->part[ i ].len = 0; - f->part[ i ].ptr = ""; + edits->f.part[ i ].len = 0; + edits->f.part[ i ].ptr = ""; } fp->ptr = 0; + continue; + } + + strval: + + /* Handle :X=value, or :X */ + + if( *mods != '=' ) + { + fp->ptr = ""; + fp->len = 0; + } + else if( p = strchr( mods, MAGIC_COLON ) ) + { + *p = 0; + fp->ptr = ++mods; + fp->len = p - mods; + mods = p + 1; } else { - /* :X=value - set X to value */ - - char *p; - - if( p = strchr( mods, MAGIC_COLON ) ) - { - fp->ptr = mods; - fp->len = p - mods; - mods = p + 1; - } - else - { - fp->ptr = mods; - fp->len = strlen( mods ); - mods += fp->len; - } + fp->ptr = ++mods; + fp->len = strlen( mods ); + mods += fp->len; } } } -static int adjust_index( int index, int length ) +/* + * var_edit_file() - copy input target name to output, modifying filename + */ + +static void +var_edit_file( + char *in, + string *out, + VAR_EDITS *edits ) { - if ( index < 0 ) - index = length + 1 + index; - /** For first range index negative values are ok. - For second return value of 0 means don't use second bound. - We need to make it -1 so that all elements are skipped. - */ - if ( index == 0 ) - index = -1; - return index; + PATHNAME pathname; + + /* Parse apart original filename, putting parts into "pathname" */ + + path_parse( in, &pathname ); + + /* Replace any pathname with edits->f */ + + if( edits->f.f_grist.ptr ) + pathname.f_grist = edits->f.f_grist; + + if( edits->f.f_root.ptr ) + pathname.f_root = edits->f.f_root; + + if( edits->f.f_dir.ptr ) + pathname.f_dir = edits->f.f_dir; + + if( edits->f.f_base.ptr ) + pathname.f_base = edits->f.f_base; + + if( edits->f.f_suffix.ptr ) + pathname.f_suffix = edits->f.f_suffix; + + if( edits->f.f_member.ptr ) + pathname.f_member = edits->f.f_member; + + /* If requested, modify pathname to point to parent */ + + if( edits->parent ) + path_parent( &pathname ); + + /* Put filename back together */ + + path_build( &pathname, out, 0 ); +} + +/* + * var_edit_shift() - do upshift/downshift mods + */ + +static void +var_edit_shift( + string *out, + VAR_EDITS *edits ) +{ + /* Handle upshifting, downshifting and slash translation now */ + + char *p; + for ( p = out->value; *p; ++p) + { + if (edits->upshift) + { + *p = toupper( *p ); + } + else if ( edits->downshift ) + { + *p = tolower( *p ); + } + if ( edits->to_slashes ) + { + if ( *p == '\\') + *p = '/'; + } + } + out->size = p - out->value; } #ifndef NDEBUG diff --git a/src/engine/filemac.c b/src/engine/filemac.c index 6339b7062..a14bf83d6 100644 --- a/src/engine/filemac.c +++ b/src/engine/filemac.c @@ -1,5 +1,5 @@ /* - * Copyright 1993, 1995 Christopher Seiwald. + * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. * * This file is part of Jam - see jam.c for Copyright information. */ @@ -14,6 +14,7 @@ # include "jam.h" # include "filesys.h" +# include "pathsys.h" # ifdef OS_MAC @@ -61,9 +62,10 @@ void CopyC2PStr(const char * cstr, StringPtr pstr) void file_dirscan( char *dir, - void (*func)( char *file, int s, time_t t ) ) + scanback func, + void *closure ) { - FILENAME f; + PATHNAME f; string filename[1]; unsigned char fullPath[ 512 ]; @@ -86,7 +88,7 @@ file_dirscan( /* Special case ":" - enter it */ if( f.f_dir.len == 1 && f.f_dir.ptr[0] == ':' ) - (*func)( dir, 0 /* not stat()'ed */, (time_t)0 ); + (*func)( closure, dir, 0 /* not stat()'ed */, (time_t)0 ); /* Now enter contents of directory */ @@ -131,8 +133,8 @@ file_dirscan( f.f_base.len = *fullPath; string_truncate( filename, 0 ); - file_build( &f, filename, 0 ); - (*func)( filename->value, 0 /* not stat()'ed */, (time_t)0 ); + path_build( &f, filename, 0 ); + (*func)( closure, filename->value, 0 /* not stat()'ed */, (time_t)0 ); } string_free( filename ); } @@ -163,8 +165,8 @@ file_time( void file_archscan( char *archive, - void (*func)( char *file, int s, time_t t ) ) - + scanback func, + void *closure ) { } diff --git a/src/engine/filent.c b/src/engine/filent.c index 268d50e3d..ea8e58871 100644 --- a/src/engine/filent.c +++ b/src/engine/filent.c @@ -14,6 +14,7 @@ # include "jam.h" # include "filesys.h" +# include "pathsys.h" # include "strings.h" # ifdef OS_NT @@ -56,9 +57,10 @@ void file_dirscan( char *dir, - void (*func)( char *file, int status, time_t t ) ) + scanback func, + void *closure ) { - FILENAME f; + PATHNAME f; string filespec[1]; string filename[1]; long handle; @@ -77,9 +79,9 @@ file_dirscan( /* Special case \ or d:\ : enter it */ if( f.f_dir.len == 1 && f.f_dir.ptr[0] == '\\' ) - (*func)( dir, 0 /* not stat()'ed */, (time_t)0 ); + (*func)( closure, dir, 0 /* not stat()'ed */, (time_t)0 ); else if( f.f_dir.len == 3 && f.f_dir.ptr[1] == ':' ) - (*func)( dir, 0 /* not stat()'ed */, (time_t)0 ); + (*func)( closure, dir, 0 /* not stat()'ed */, (time_t)0 ); /* Now enter contents of directory */ @@ -106,9 +108,9 @@ file_dirscan( f.f_base.len = strlen( finfo->ff_name ); string_truncate( filename, 0 ); - file_build( &f, filename ); + path_build( &f, filename ); - (*func)( filename->value, 1 /* stat()'ed */, time_write ); + (*func)( closure, filename->value, 1 /* stat()'ed */, time_write ); ret = findnext( finfo ); } @@ -128,9 +130,9 @@ file_dirscan( f.f_base.len = strlen( finfo->name ); string_truncate( filename, 0 ); - file_build( &f, filename, 0 ); + path_build( &f, filename, 0 ); - (*func)( filename->value, 1 /* stat()'ed */, finfo->time_write ); + (*func)( closure, filename->value, 1 /* stat()'ed */, finfo->time_write ); ret = _findnext( handle, finfo ); } @@ -189,7 +191,8 @@ struct ar_hdr { void file_archscan( char *archive, - void (*func)( char *file, int status, time_t t ) ) + scanback func, + void *closure ) { struct ar_hdr ar_hdr; char *string_table = 0; @@ -271,7 +274,7 @@ file_archscan( name = c + 1; sprintf( buf, "%s(%.*s)", archive, endname - name, name ); - (*func)( buf, 1 /* time valid */, (time_t)lar_date ); + (*func)( closure, buf, 1 /* time valid */, (time_t)lar_date ); offset += SARHDR + lar_size; lseek( fd, offset, 0 ); diff --git a/src/engine/fileos2.c b/src/engine/fileos2.c index 81204f2ba..6fe70b5ef 100644 --- a/src/engine/fileos2.c +++ b/src/engine/fileos2.c @@ -1,5 +1,5 @@ /* - * Copyright 1993, 1995 Christopher Seiwald. + * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. * * This file is part of Jam - see jam.c for Copyright information. */ @@ -14,6 +14,7 @@ # include "jam.h" # include "filesys.h" +# include "pathsys.h" /* note that we use "fileunix.c" when compiling with EMX on OS/2 */ # if defined(OS_OS2) && !defined(__EMX__) @@ -48,9 +49,10 @@ void file_dirscan( char *dir, - void (*func)( char *file, int status, time_t t ) ) + scanback func, + void *closure ) { - FILENAME f; + PATHNAME f; string filespec[1]; long handle; int ret; @@ -69,9 +71,9 @@ file_dirscan( string_copy( filespec, dir ); if( f.f_dir.len == 1 && f.f_dir.ptr[0] == '\\' ) - (*func)( dir, 0 /* not stat()'ed */, (time_t)0 ); + (*func)( closure, dir, 0 /* not stat()'ed */, (time_t)0 ); else if( f.f_dir.len == 3 && f.f_dir.ptr[1] == ':' ) - (*func)( dir, 0 /* not stat()'ed */, (time_t)0 ); + (*func)( closure, dir, 0 /* not stat()'ed */, (time_t)0 ); else string_push_back( filespec, '/' ); @@ -97,8 +99,8 @@ file_dirscan( f.f_base.len = strlen( finfo->name ); string_truncate( filename, 0 ); - file_build( &f, filename, 0 ); - (*func)( filename->value, 0 /* not stat()'ed */, (time_t)0 ); + path_build( &f, filename, 0 ); + (*func)( closure, filename->value, 0 /* not stat()'ed */, (time_t)0 ); } while( !_dos_findnext( finfo ) ); string_free( filename ); @@ -130,7 +132,8 @@ file_time( void file_archscan( char *archive, - void (*func)( char *file, int status, time_t t ) ) + scanback func, + void *closure ) { } diff --git a/src/engine/filesys.c b/src/engine/filesys.c index c38d9e468..597aa98bd 100644 --- a/src/engine/filesys.c +++ b/src/engine/filesys.c @@ -1,10 +1,10 @@ # include "jam.h" -# include "filesys.h" +# include "pathsys.h" # include "strings.h" void file_build1( - FILENAME *f, + PATHNAME *f, string* file) { if( DEBUG_SEARCH ) diff --git a/src/engine/filesys.h b/src/engine/filesys.h index 5ddbb2b7d..a445502f1 100644 --- a/src/engine/filesys.h +++ b/src/engine/filesys.h @@ -1,5 +1,5 @@ /* - * Copyright 1993, 1995 Christopher Seiwald. + * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. * * This file is part of Jam - see jam.c for Copyright information. */ @@ -13,57 +13,16 @@ */ /* - * filesys.h - FILENAME struct and OS specific file routines - */ - -/* - * FILENAME - a name of a file, broken into dir/base/suffix(member) - * - * is salt to distinguish between targets that otherwise would - * have the same name: it never appears in the bound name of a target. - * (member) is an archive member name: the syntax is arbitrary, but must - * agree in file_parse(), file_build() and the Jambase. - * - * On VMS, we keep track of whether the original path was a directory - * (without a file), so that $(VAR:D) can climb to the parent. + * filesys.h - OS specific file routines */ #ifndef FILESYS_DWA20011025_H # define FILESYS_DWA20011025_H -# include "strings.h" +typedef void (*scanback)( void *closure, char *file, int found, time_t t ); -typedef struct _filename FILENAME; -typedef struct _filepart FILEPART; - -struct _filepart { - char *ptr; - int len; -}; - -struct _filename { - FILEPART part[6]; -# ifdef OS_VMS - int parent; -# endif - -# define f_grist part[0] -# define f_root part[1] -# define f_dir part[2] -# define f_base part[3] -# define f_suffix part[4] -# define f_member part[5] - -} ; - -void file_build( FILENAME *f, string *file, int binding ); -void file_build1( FILENAME *f, string *file ); - -void file_parse( char *file, FILENAME *f ); -void file_parent( FILENAME *f ); - -void file_dirscan( char *dir, void (*func)( char *f, int s, time_t t ) ); -void file_archscan( char *arch, void (*func)( char *f, int s, time_t t ) ); +void file_dirscan( char *dir, scanback func, void *closure ); +void file_archscan( char *arch, scanback func, void *closure ); int file_time( char *filename, time_t *time ); diff --git a/src/engine/fileunix.c b/src/engine/fileunix.c index a75db95b8..538adf8ca 100644 --- a/src/engine/fileunix.c +++ b/src/engine/fileunix.c @@ -1,5 +1,5 @@ /* - * Copyright 1993, 1995 Christopher Seiwald. + * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. * * This file is part of Jam - see jam.c for Copyright information. */ @@ -15,6 +15,7 @@ # include "jam.h" # include "filesys.h" # include "strings.h" +# include "pathsys.h" # ifdef USE_FILEUNIX @@ -48,7 +49,7 @@ # endif # if defined( OS_MVS ) || \ - defined( OS_INTERIX ) + defined( OS_INTERIX ) || defined(OS_AIX) #define ARMAG "!\n" #define SARMAG 8 @@ -108,9 +109,10 @@ struct ar_hdr /* archive file member header - printable ascii */ void file_dirscan( char *dir, - void (*func)( char *file, int status, time_t t ) ) + scanback func, + void *closure ) { - FILENAME f; + PATHNAME f; DIR *d; STRUCT_DIRENT *dirent; string filename[1]; @@ -127,7 +129,7 @@ file_dirscan( /* Special case / : enter it */ if( f.f_dir.len == 1 && f.f_dir.ptr[0] == '/' ) - (*func)( dir, 0 /* not stat()'ed */, (time_t)0 ); + (*func)( closure, dir, 0 /* not stat()'ed */, (time_t)0 ); /* Now enter contents of directory */ @@ -149,9 +151,9 @@ file_dirscan( f.f_base.len = strlen( f.f_base.ptr ); string_truncate( filename, 0 ); - file_build( &f, filename, 0 ); + path_build( &f, filename, 0 ); - (*func)( filename->value, 0 /* not stat()'ed */, (time_t)0 ); + (*func)( closure, filename->value, 0 /* not stat()'ed */, (time_t)0 ); } string_free( filename ); @@ -188,7 +190,8 @@ file_time( void file_archscan( char *archive, - void (*func)( char *file, int status, time_t t ) ) + scanback func, + void *closure ) { # ifndef NO_AR struct ar_hdr ar_hdr; @@ -266,7 +269,7 @@ file_archscan( sprintf( buf, "%s(%s)", archive, lar_name ); - (*func)( buf, 1 /* time valid */, (time_t)lar_date ); + (*func)( closure, buf, 1 /* time valid */, (time_t)lar_date ); offset += SARHDR + ( ( lar_size + 1 ) & ~1 ); lseek( fd, offset, 0 ); @@ -286,7 +289,8 @@ file_archscan( void file_archscan( char *archive, - void (*func)( char *file, int status, time_t t ) ) + scanback func, + void *closure ) { struct fl_hdr fl_hdr; @@ -332,7 +336,7 @@ file_archscan( sprintf( buf, "%s(%s)", archive, ar_hdr.hdr._ar_name.ar_name ); - (*func)( buf, 1 /* time valid */, (time_t)lar_date ); + (*func)( closure, buf, 1 /* time valid */, (time_t)lar_date ); } close( fd ); diff --git a/src/engine/filevms.c b/src/engine/filevms.c index 1149382d8..787b5cdf3 100644 --- a/src/engine/filevms.c +++ b/src/engine/filevms.c @@ -1,5 +1,5 @@ /* - * Copyright 1993, 1995 Christopher Seiwald. + * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. * * This file is part of Jam - see jam.c for Copyright information. */ @@ -14,6 +14,7 @@ # include "jam.h" # include "filesys.h" +# include "pathsys.h" # ifdef OS_VMS @@ -52,25 +53,41 @@ #include /* Supply missing prototypes for lbr$-routines*/ -int lbr$close(); -int lbr$get_index(); -int lbr$ini_control(); -int lbr$open(); -int lbr$set_module(); -/* - * unlink() - remove a file - */ +extern "C" { -#if __CRTL_VER < 70000000 +int lbr$set_module( + void **, + unsigned long *, + struct dsc$descriptor_s *, + unsigned short *, + void * ); + +int lbr$open( void **, + struct dsc$descriptor_s *, + void *, + void *, + void *, + void *, + void * ); + +int lbr$ini_control( + void **, + unsigned long *, + unsigned long *, + void * ); + +int lbr$get_index( + void **, + unsigned long *, + int (*func)( struct dsc$descriptor_s *, unsigned long *), + void * ); + +int lbr$close( + void ** ); -unlink( char *f ) -{ - remove( f ); } -#endif - static void file_cvttime( unsigned int *curtime, @@ -91,7 +108,8 @@ file_cvttime( void file_dirscan( char *dir, - void (*func)( char *file, int status, time_t t ) ) + scanback func, + void *closure ) { struct FAB xfab; @@ -102,7 +120,7 @@ file_dirscan( string filename2[1]; char dirname[256]; register int status; - FILENAME f; + PATHNAME f; memset( (char *)&f, '\0', sizeof( f ) ); @@ -145,15 +163,15 @@ file_dirscan( if( !strcmp( dir, "[000000]" ) ) { - (*func)( "[000000]", 1 /* time valid */, 1 /* old but true */ ); + (*func)( closure, "[000000]", 1 /* time valid */, 1 /* old but true */ ); } /* Add bogus directory for [] */ if( !strcmp( dir, "[]" ) ) { - (*func)( "[]", 1 /* time valid */, 1 /* old but true */ ); - (*func)( "[-]", 1 /* time valid */, 1 /* old but true */ ); + (*func)( closure, "[]", 1 /* time valid */, 1 /* old but true */ ); + (*func)( closure, "[-]", 1 /* time valid */, 1 /* old but true */ ); } string_new( filename2 ); @@ -199,7 +217,7 @@ file_dirscan( } string_truncate( filename2, 0 ); - file_build( &f, filename2, 0 ); + path_build( &f, filename2, 0 ); /* if( DEBUG_SEARCH ) @@ -210,12 +228,9 @@ file_dirscan( filename2); */ - (*func)( filename2->value, 1 /* time valid */, time ); + (*func)( closure, filename2->value, 1 /* time valid */, time ); } string_free( filename2 ); - - if ( status != RMS$_NMF && status != RMS$_FNF ) - lib$signal( xfab.fab$l_sts, xfab.fab$l_stv ); } int @@ -229,7 +244,8 @@ file_time( } static char *VMS_archive = 0; -static void (*VMS_func)( char *file, int status, time_t t ) = 0; +static scanback VMS_func; +static void *VMS_closure; static void *context; static int @@ -254,6 +270,7 @@ file_archmember( bufdsc.dsc$w_length = sizeof( filename ); status = lbr$set_module( &context, rfa, &bufdsc, &bufdsc.dsc$w_length, NULL ); + if ( !(status & 1) ) return ( 1 ); @@ -268,7 +285,7 @@ file_archmember( sprintf( buf, "%s(%s.obj)", VMS_archive, filename ); - (*VMS_func)( buf, 1 /* time valid */, (time_t)library_date ); + (*VMS_func)( VMS_closure, buf, 1 /* time valid */, (time_t)library_date ); return ( 1 ); } @@ -276,7 +293,8 @@ file_archmember( void file_archscan( char *archive, - void (*func)( char *file, int status, time_t t ) ) + scanback func, + void *closure ) { static struct dsc$descriptor_s library = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL}; @@ -289,6 +307,7 @@ file_archscan( VMS_archive = archive; VMS_func = func; + VMS_closure = closure; status = lbr$ini_control( &context, &lfunc, &typ, NULL ); if ( !( status & 1 ) ) diff --git a/src/engine/frames.c b/src/engine/frames.c new file mode 100644 index 000000000..5e8e45a6f --- /dev/null +++ b/src/engine/frames.c @@ -0,0 +1,25 @@ +/* + * (C) Copyright David Abrahams 2001. Permission to copy, use, + * modify, sell and distribute this software is granted provided this + * copyright notice appears in all copies. This software is provided + * "as is" without express or implied warranty, and with no claim as + * to its suitability for any purpose. + */ + +# include "frames.h" +# include "lists.h" + + +void frame_init( FRAME* frame ) +{ + frame->prev = 0; + lol_init(frame->args); + frame->module = root_module(); + frame->rulename = "module scope"; + frame->procedure = 0; +} + +void frame_free( FRAME* frame ) +{ + lol_free( frame->args ); +} diff --git a/src/engine/jam.c b/src/engine/jam.c index 502ff0893..b21a42fb3 100644 --- a/src/engine/jam.c +++ b/src/engine/jam.c @@ -1,6 +1,6 @@ /* * /+\ - * +\ Copyright 1993, 2000 Christopher Seiwald. + * +\ Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. * \+/ * * This file is part of jam. @@ -23,7 +23,7 @@ /* * jam.c - make redux * - * See Jam.html and Jamlang.html for usage information. + * See Jam.html for usage information. * * These comments document the code. * @@ -38,14 +38,18 @@ * / | \ \ * / | \ | * scan | compile make - * | | / \ / | \ - * | | / \ / | \ - * | | / \ / | \ - * jambase parse rules search make1 - * | | \ - * | | \ - * | | \ - * timestamp command execute + * | | / | \ / | \ + * | | / | \ / | \ + * | | / | \ / | \ + * jambase parse | rules search make1 + * | | | \ + * | | | \ + * | | | \ + * builtins timestamp command execute + * | + * | + * | + * filesys * * * The support routines are called by all of the above, but themselves @@ -55,7 +59,7 @@ * / | | | * / | | | * / | | | - * lists | | filesys + * lists | | pathsys * \ | | * \ | | * \ | | @@ -67,15 +71,13 @@ * * Roughly, the modules are: * + * builtins.c - jam's built-in rules * command.c - maintain lists of commands * compile.c - compile parsed jam statements * execunix.c - execute a shell script on UNIX * execvms.c - execute a shell script, ala VMS * expand.c - expand a buffer, given variable values - * fileunix.c - manipulate file names and scan directories on UNIX - * filevms.c - manipulate file names and scan directories on VMS - * fileos2.c - manipulate file names and scan directories on OS/2 - * filent.c - manipulate file names and scan directories on Windows + * file*.c - scan directories and archives on * * hash.c - simple in-memory hashing routines * hdrmacro.c - handle header file parsing for filename macro definitions * headers.c - handle #includes in source files @@ -87,6 +89,8 @@ * newstr.c - string manipulation routines * option.c - command line option processing * parse.c - make and destroy parse trees as driven by the parser + * path*.c - manipulate file names on * + * hash.c - simple in-memory hashing routines * regexp.c - Henry Spencer's regexp * rules.c - access to RULEs, TARGETs, and ACTIONs * scan.c - the jam yacc scanner @@ -98,6 +102,7 @@ * 02/08/95 (seiwald) - -n implies -d2. * 02/22/95 (seiwald) - -v for version info. * 09/11/00 (seiwald) - PATCHLEVEL folded into VERSION. + * 01/10/01 (seiwald) - pathsys.h split from filesys.h */ # include "jam.h" @@ -110,6 +115,7 @@ # include "parse.h" # include "variable.h" # include "compile.h" +# include "builtins.h" # include "rules.h" # include "newstr.h" # include "scan.h" @@ -226,9 +232,9 @@ int main( int argc, char **argv, char **arg_environ ) printf( "Boost.Jam " ); printf( "Version %s. ", VERSION ); printf( "%s.\n", OSMINOR ); - printf( " Copyright 1993, 2000 Christopher Seiwald.\n" ); - printf( " Copyright 2001 David Turner.\n" ); - printf( " Copyright 2001 David Abrahams.\n" ); + printf( " Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. \n" ); + printf( " Copyright 2001 David Turner.\n" ); + printf( " Copyright 2001 David Abrahams.\n" ); return EXITOK; } @@ -343,10 +349,9 @@ int main( int argc, char **argv, char **arg_environ ) var_defines( symv ); } - /* Initialize builtins */ + /* Initialize built-in rules */ - - compile_builtins(); + load_builtins(); /* Parse ruleset */ diff --git a/src/engine/jamgram.c b/src/engine/jamgram.c index 57818047b..f8f2c2e1f 100644 --- a/src/engine/jamgram.c +++ b/src/engine/jamgram.c @@ -13,7 +13,7 @@ yyrcsid[] = "$FreeBSD: src/usr.bin/yacc/skeleton.c,v 1.28 2000/01/17 02:04:06 bd #define YYRECOVERING() (yyerrflag!=0) static int yygrowstack(); #define YYPREFIX "yy" -#line 94 "jamgram.y" +#line 99 "jamgram.y" #include "jam.h" #include "lists.h" @@ -27,6 +27,8 @@ static int yygrowstack(); # define S0 (char *)0 # define pappend( l,r ) parse_make( compile_append,l,r,P0,S0,S0,0 ) +# define peval( c,l,r ) parse_make( compile_eval,l,r,P0,S0,S0,c ) +# define pshortcircuiteval( c,l,r ) parse_make( compile_eval,l,P0,r,S0,S0,c ) # define pfor( s,l,r,x ) parse_make( compile_foreach,l,r,P0,s,S0,x ) # define pif( l,r,t ) parse_make( compile_if,l,r,t,S0,S0,0 ) # define pwhile( l,r ) parse_make( compile_while,l,r,P0,S0,S0,0 ) @@ -35,6 +37,7 @@ static int yygrowstack(); # define plocal( l,r,t ) parse_make( compile_local,l,r,t,S0,S0,0 ) # define pmodule( l,r ) parse_make( compile_module,l,r,P0,S0,S0,0 ) # define pnull() parse_make( compile_null,P0,P0,P0,S0,S0,0 ) +# define pon( l,r ) parse_make( compile_on,l,r,P0,S0,S0,0 ) # define prule( s,p ) parse_make( compile_rule,p,P0,P0,s,S0,0 ) # define prules( l,r ) parse_make( compile_rules,l,r,P0,S0,S0,0 ) # define pset( l,r,a ) parse_make( compile_set,l,r,P0,S0,S0,a ) @@ -45,203 +48,211 @@ static int yygrowstack(); # define pswitch( l,r ) parse_make( compile_switch,l,r,P0,S0,S0,0 ) # define pnode( l,r ) parse_make( F0,l,r,P0,S0,S0,0 ) -# define pcnode( c,l,r ) parse_make( F0,l,r,P0,S0,S0,c ) # define psnode( s,l ) parse_make( F0,l,P0,P0,s,S0,0 ) -#line 52 "y.tab.c" +#line 54 "y.tab.c" #define YYERRCODE 256 #define _BANG 257 #define _BANG_EQUALS 258 -#define _AMPERAMPER 259 -#define _LPAREN 260 -#define _RPAREN 261 -#define _PLUS_EQUALS 262 -#define _COLON 263 -#define _SEMIC 264 -#define _LANGLE 265 -#define _LANGLE_EQUALS 266 -#define _EQUALS 267 -#define _RANGLE 268 -#define _RANGLE_EQUALS 269 -#define _QUESTION_EQUALS 270 -#define _LBRACKET 271 -#define _RBRACKET 272 -#define ACTIONS 273 -#define BIND 274 -#define CASE 275 -#define DEFAULT 276 -#define ELSE 277 -#define EXISTING 278 -#define FOR 279 -#define IF 280 -#define IGNORE 281 -#define IN 282 -#define INCLUDE 283 -#define LOCAL 284 -#define MODULE 285 -#define ON 286 -#define PIECEMEAL 287 -#define QUIETLY 288 -#define RETURN 289 -#define RULE 290 -#define SWITCH 291 -#define TOGETHER 292 -#define UPDATED 293 -#define WHILE 294 -#define _LBRACE 295 -#define _BARBAR 296 -#define _RBRACE 297 -#define ARG 298 -#define STRING 299 +#define _AMPER 259 +#define _AMPERAMPER 260 +#define _LPAREN 261 +#define _RPAREN 262 +#define _PLUS_EQUALS 263 +#define _COLON 264 +#define _SEMIC 265 +#define _LANGLE 266 +#define _LANGLE_EQUALS 267 +#define _EQUALS 268 +#define _RANGLE 269 +#define _RANGLE_EQUALS 270 +#define _QUESTION_EQUALS 271 +#define _LBRACKET 272 +#define _RBRACKET 273 +#define ACTIONS 274 +#define BIND 275 +#define CASE 276 +#define DEFAULT 277 +#define ELSE 278 +#define EXISTING 279 +#define FOR 280 +#define IF 281 +#define IGNORE 282 +#define IN 283 +#define INCLUDE 284 +#define LOCAL 285 +#define MODULE 286 +#define ON 287 +#define PIECEMEAL 288 +#define QUIETLY 289 +#define RETURN 290 +#define RULE 291 +#define SWITCH 292 +#define TOGETHER 293 +#define UPDATED 294 +#define WHILE 295 +#define _LBRACE 296 +#define _BAR 297 +#define _BARBAR 298 +#define _RBRACE 299 +#define ARG 300 +#define STRING 301 const short yylhs[] = { -1, 0, 0, 2, 2, 1, 1, 1, 3, 6, 6, 7, 7, 9, 9, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 16, 17, - 4, 11, 11, 11, 11, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 12, 12, 18, - 8, 8, 5, 19, 19, 10, 10, 14, 14, 20, - 20, 20, 20, 20, 20, 15, 15, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 16, + 17, 4, 11, 11, 11, 11, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 12, 12, 18, 8, 8, 5, 19, 19, 10, 21, + 10, 20, 20, 20, 14, 14, 22, 22, 22, 22, + 22, 22, 15, 15, }; const short yylen[] = { 2, 0, 1, 1, 1, 1, 2, 5, 0, 2, 1, 3, 0, 1, 0, 3, 3, 3, 4, 5, 6, - 3, 8, 5, 5, 5, 5, 7, 5, 0, 0, - 9, 1, 1, 1, 2, 1, 3, 3, 3, 3, - 3, 3, 3, 2, 3, 3, 3, 0, 2, 4, - 1, 3, 1, 0, 2, 1, 4, 0, 2, 1, - 1, 1, 1, 1, 1, 0, 2, + 3, 8, 5, 5, 5, 5, 7, 5, 3, 0, + 0, 9, 1, 1, 1, 2, 1, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, + 0, 2, 4, 1, 3, 1, 0, 2, 1, 0, + 4, 2, 4, 4, 0, 2, 1, 1, 1, 1, + 1, 1, 0, 2, }; const short yydefred[] = { 0, - 0, 58, 0, 0, 54, 0, 0, 54, 54, 0, - 0, 0, 0, 2, 0, 0, 0, 54, 0, 13, - 0, 0, 0, 56, 0, 0, 0, 0, 0, 54, - 0, 0, 0, 0, 4, 0, 3, 0, 0, 6, - 0, 33, 32, 34, 0, 54, 54, 0, 65, 62, - 64, 63, 61, 60, 0, 59, 0, 44, 0, 0, - 0, 0, 0, 0, 0, 54, 0, 0, 0, 16, - 55, 54, 10, 0, 0, 0, 21, 0, 0, 15, - 54, 17, 0, 35, 0, 0, 57, 54, 0, 54, - 47, 38, 39, 40, 37, 41, 42, 43, 45, 0, - 0, 9, 0, 0, 0, 0, 0, 0, 0, 52, - 54, 0, 54, 18, 67, 29, 0, 0, 7, 19, - 25, 0, 23, 49, 26, 0, 28, 0, 0, 0, - 0, 0, 11, 20, 30, 0, 27, 50, 0, 22, - 31, + 60, 65, 0, 0, 57, 0, 0, 0, 57, 57, + 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, + 13, 0, 0, 0, 59, 0, 0, 0, 0, 0, + 57, 0, 0, 0, 0, 0, 4, 0, 3, 0, + 0, 6, 0, 34, 33, 35, 0, 57, 57, 0, + 57, 0, 72, 69, 71, 70, 68, 67, 0, 66, + 0, 49, 0, 0, 0, 0, 0, 0, 0, 57, + 0, 0, 0, 0, 0, 16, 58, 57, 10, 0, + 0, 0, 29, 21, 0, 0, 15, 57, 17, 0, + 36, 0, 0, 0, 62, 61, 57, 0, 57, 50, + 39, 40, 41, 38, 42, 43, 48, 44, 45, 0, + 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, + 55, 57, 0, 57, 18, 57, 57, 74, 30, 0, + 0, 7, 19, 25, 0, 23, 52, 26, 0, 28, + 0, 64, 63, 0, 0, 0, 0, 11, 20, 31, + 0, 27, 53, 0, 22, 32, }; -const short yydgoto[] = { 13, - 35, 36, 37, 15, 38, 74, 112, 39, 16, 17, - 47, 107, 26, 19, 89, 129, 139, 108, 28, 56, +const short yydgoto[] = { 14, + 37, 38, 39, 16, 40, 80, 123, 41, 17, 18, + 49, 118, 27, 20, 98, 144, 154, 119, 29, 52, + 19, 60, }; -const short yysindex[] = { -120, - -282, 0, -267, -234, 0, 0, -259, 0, 0, -234, - -120, 0, 0, 0, -120, -261, -83, 0, -131, 0, - -236, -234, -234, 0, -69, -250, -181, -244, -188, 0, - -210, -175, -204, -209, 0, -205, 0, -157, -154, 0, - -184, 0, 0, 0, -152, 0, 0, -156, 0, 0, - 0, 0, 0, 0, -153, 0, -158, 0, -185, -244, - -244, -244, -244, -244, -244, 0, -234, -120, -234, 0, - 0, 0, 0, -135, -188, -120, 0, -144, -120, 0, - 0, 0, -128, 0, -150, -124, 0, 0, -149, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, -155, - -118, 0, -120, -110, -139, -143, -125, -144, -114, 0, - 0, -103, 0, 0, 0, 0, -129, -104, 0, 0, - 0, -78, 0, 0, 0, -71, 0, -70, -98, -120, - -103, -120, 0, 0, 0, -95, 0, 0, -93, 0, - 0, +const short yysindex[] = { -88, + 0, 0, -269, -248, 0, 0, -257, -229, 0, 0, + -248, -88, 0, 0, 0, -88, -254, -160, -267, -44, + 0, -258, -248, -248, 0, -36, -212, -219, -229, -200, + 0, -222, -71, -188, -215, -209, 0, -203, 0, -166, + -155, 0, -201, 0, 0, 0, -168, 0, 0, -229, + 0, -152, 0, 0, 0, 0, 0, 0, -170, 0, + -159, 0, -153, -229, -229, -229, -229, -229, -229, 0, + -248, -248, -88, -248, -248, 0, 0, 0, 0, -140, + -200, -88, 0, 0, -146, -88, 0, 0, 0, -135, + 0, -20, -124, -245, 0, 0, 0, -147, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, -141, + -165, -165, 0, -88, -105, -137, -148, -136, -146, -133, + 0, 0, -71, 0, 0, 0, 0, 0, 0, -132, + -109, 0, 0, 0, -94, 0, 0, 0, -87, 0, + -84, 0, 0, -112, -88, -71, -88, 0, 0, 0, + -108, 0, 0, -104, 0, 0, }; const short yyrindex[] = { 7, - 0, 0, -92, 0, 0, -162, -201, 0, 0, 0, - -275, -163, 0, 0, 3, 0, 0, 0, 0, 0, - 0, 0, 0, 0, -229, 0, 0, -223, -59, 0, - 0, 0, 0, 0, 0, 0, 0, -142, 0, 0, + 0, 0, -110, 0, 0, -115, -238, 0, 0, 0, + 0, -198, -149, 0, 0, 3, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -237, 0, 0, -233, -60, + 0, 0, -97, 0, 0, 0, 0, 0, 0, -45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, -88, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, -275, 0, 0, - 0, 0, 0, 0, -59, -275, 0, -89, -275, 0, - 0, 0, -146, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - -253, 0, 4, 0, 0, 0, 0, -89, 0, 0, - 0, -81, 0, 0, 0, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, -275, - -81, -194, 0, 0, 0, 0, 0, 0, 0, 0, - 0, + 0, 0, -198, 0, 0, 0, 0, 0, 0, 0, + -60, -198, 0, 0, -93, -198, 0, 0, 0, -113, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -150, -142, 0, 4, 0, 0, 0, 0, -93, 0, + 0, 0, -97, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, -198, -97, -111, 0, 0, 0, + 0, 0, 0, 0, 0, 0, }; const short yygindex[] = { 0, - 75, -48, -27, -43, 5, 135, 0, -13, 208, -4, - 127, 106, 11, 0, 0, 0, 0, 0, 0, 0, + 41, -65, -25, -33, 5, 130, 0, -49, 215, 68, + 131, 107, -5, 0, 0, 0, 0, 0, 0, 0, + 0, 0, }; -#define YYTABLESIZE 301 -const short yytable[] = { 25, - 24, 73, 5, 8, 48, 25, 1, 46, 67, 27, - 29, 31, 32, 33, 14, 18, 20, 25, 25, 100, - 34, 8, 22, 71, 30, 23, 1, 105, 41, 36, - 109, 36, 58, 59, 75, 53, 1, 53, 53, 53, - 53, 46, 46, 53, 68, 69, 53, 73, 53, 67, - 85, 86, 53, 24, 119, 92, 93, 94, 95, 96, - 97, 57, 25, 24, 25, 36, 36, 110, 127, 54, - 98, 53, 53, 67, 14, 91, 102, 99, 72, 101, - 8, 136, 70, 138, 76, 79, 69, 137, 77, 40, - 78, 80, 115, 54, 117, 14, 54, 126, 56, 54, - 54, 54, 8, 56, 54, 81, 56, 54, 54, 82, - 69, 42, 56, 83, 84, 87, 43, 128, 51, 44, - 88, 51, 56, 90, 12, 45, 12, 13, 103, 51, - 106, 111, 12, 12, 54, 54, 12, 12, 12, 114, - 67, 118, 12, 12, 12, 116, 49, 12, 12, 50, - 1, 12, 2, 120, 122, 51, 52, 121, 3, 4, - 53, 54, 5, 6, 7, 130, 55, 1, 8, 2, - 9, 123, 131, 10, 11, 3, 4, 12, 42, 5, - 20, 7, 125, 43, 132, 8, 44, 9, 60, 133, - 10, 11, 45, 134, 12, 61, 62, 63, 64, 65, - 135, 140, 46, 141, 8, 14, 66, 48, 14, 104, - 21, 113, 66, 124, 0, 0, 0, 0, 0, 0, +#define YYTABLESIZE 303 +const short yytable[] = { 83, + 24, 95, 5, 8, 79, 36, 1, 110, 23, 28, + 30, 32, 24, 34, 35, 21, 116, 62, 63, 50, + 120, 37, 37, 1, 37, 56, 56, 31, 56, 56, + 56, 56, 51, 57, 56, 81, 43, 56, 121, 56, + 15, 61, 1, 56, 126, 76, 71, 72, 132, 71, + 72, 25, 92, 93, 127, 79, 42, 57, 37, 37, + 37, 57, 56, 56, 56, 108, 109, 78, 111, 112, + 25, 26, 139, 82, 107, 33, 84, 143, 26, 151, + 85, 153, 113, 73, 74, 75, 86, 74, 75, 140, + 26, 26, 14, 71, 72, 87, 77, 88, 90, 91, + 8, 128, 44, 130, 97, 71, 72, 45, 100, 89, + 46, 46, 152, 59, 57, 57, 47, 94, 59, 47, + 96, 59, 57, 99, 114, 122, 48, 59, 141, 117, + 142, 101, 102, 103, 104, 105, 106, 59, 26, 26, + 125, 26, 26, 74, 75, 46, 46, 46, 129, 57, + 57, 135, 57, 47, 47, 47, 57, 131, 12, 133, + 12, 134, 136, 145, 8, 138, 12, 12, 146, 147, + 12, 12, 12, 12, 148, 13, 12, 12, 12, 14, + 149, 12, 12, 1, 57, 2, 12, 8, 150, 14, + 155, 3, 4, 14, 156, 5, 6, 7, 8, 73, + 1, 9, 2, 10, 8, 51, 11, 12, 3, 4, + 115, 13, 5, 21, 7, 8, 54, 22, 9, 54, + 10, 64, 124, 11, 12, 137, 0, 54, 13, 65, + 66, 67, 68, 69, 53, 0, 0, 54, 0, 0, + 0, 0, 44, 55, 56, 0, 70, 45, 57, 58, + 46, 0, 0, 0, 0, 59, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 24, 0, 24, 0, 24, 0, 5, 8, 24, - 24, 0, 0, 24, 24, 24, 0, 0, 0, 24, - 24, 24, 14, 14, 24, 24, 14, 24, 24, 5, - 8, + 0, 0, 24, 0, 24, 0, 24, 0, 5, 8, + 24, 24, 0, 0, 24, 24, 24, 24, 0, 0, + 24, 24, 24, 14, 14, 24, 24, 14, 0, 24, + 24, 5, 8, }; -const short yycheck[] = { 4, - 0, 29, 0, 0, 18, 10, 0, 261, 259, 5, - 6, 7, 8, 9, 290, 298, 284, 22, 23, 68, - 10, 297, 257, 28, 284, 260, 271, 76, 290, 259, - 79, 261, 22, 23, 30, 259, 271, 261, 262, 263, - 264, 295, 296, 267, 295, 296, 270, 75, 272, 259, - 46, 47, 276, 298, 103, 60, 61, 62, 63, 64, - 65, 298, 67, 298, 69, 295, 296, 81, 112, 271, - 66, 295, 296, 259, 0, 261, 72, 67, 267, 69, - 275, 130, 264, 132, 295, 295, 296, 131, 264, 15, - 295, 297, 88, 295, 90, 290, 298, 111, 262, 263, - 264, 264, 297, 267, 267, 263, 270, 271, 271, 264, - 296, 262, 276, 298, 267, 272, 267, 113, 261, 270, - 274, 264, 286, 282, 271, 276, 273, 290, 264, 272, - 275, 260, 279, 280, 298, 298, 283, 284, 285, 264, - 259, 297, 289, 290, 291, 295, 278, 294, 295, 281, - 271, 298, 273, 264, 298, 287, 288, 297, 279, 280, - 292, 293, 283, 284, 285, 295, 298, 271, 289, 273, - 291, 297, 277, 294, 295, 279, 280, 298, 262, 283, - 284, 285, 297, 267, 263, 289, 270, 291, 258, 261, - 294, 295, 276, 264, 298, 265, 266, 267, 268, 269, - 299, 297, 286, 297, 264, 298, 295, 297, 290, 75, - 3, 85, 282, 108, -1, -1, -1, -1, -1, -1, +const short yycheck[] = { 33, + 0, 51, 0, 0, 30, 11, 0, 73, 257, 5, + 6, 7, 261, 9, 10, 285, 82, 23, 24, 287, + 86, 259, 260, 272, 262, 259, 260, 285, 262, 263, + 264, 265, 300, 272, 268, 31, 291, 271, 88, 273, + 0, 300, 272, 277, 290, 265, 259, 260, 114, 259, + 260, 300, 48, 49, 300, 81, 16, 296, 296, 297, + 298, 300, 296, 297, 298, 71, 72, 268, 74, 75, + 300, 4, 122, 296, 70, 8, 265, 127, 11, 145, + 296, 147, 78, 296, 297, 298, 296, 297, 298, 123, + 23, 24, 291, 259, 260, 299, 29, 264, 300, 268, + 299, 97, 263, 99, 275, 259, 260, 268, 262, 265, + 271, 262, 146, 263, 264, 265, 277, 50, 268, 262, + 273, 271, 272, 283, 265, 261, 287, 277, 124, 276, + 126, 64, 65, 66, 67, 68, 69, 287, 71, 72, + 265, 74, 75, 297, 298, 296, 297, 298, 296, 265, + 300, 300, 268, 296, 297, 298, 272, 299, 272, 265, + 274, 299, 299, 296, 276, 299, 280, 281, 278, 264, + 284, 285, 286, 287, 262, 291, 290, 291, 292, 291, + 265, 295, 296, 272, 300, 274, 300, 299, 301, 300, + 299, 280, 281, 291, 299, 284, 285, 286, 287, 296, + 272, 290, 274, 292, 265, 299, 295, 296, 280, 281, + 81, 300, 284, 285, 286, 287, 262, 3, 290, 265, + 292, 258, 92, 295, 296, 119, -1, 273, 300, 266, + 267, 268, 269, 270, 279, -1, -1, 282, -1, -1, + -1, -1, 263, 288, 289, -1, 283, 268, 293, 294, + 271, -1, -1, -1, -1, 300, 277, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 271, -1, 273, -1, 275, -1, 275, 275, 279, - 280, -1, -1, 283, 284, 285, -1, -1, -1, 289, - 290, 291, 290, 290, 294, 295, 290, 297, 298, 297, - 297, + -1, -1, 272, -1, 274, -1, 276, -1, 276, 276, + 280, 281, -1, -1, 284, 285, 286, 287, -1, -1, + 290, 291, 292, 291, 291, 295, 296, 291, -1, 299, + 300, 299, 299, }; -#define YYFINAL 13 +#define YYFINAL 14 #ifndef YYDEBUG #define YYDEBUG 0 #endif -#define YYMAXTOKEN 299 +#define YYMAXTOKEN 301 #if YYDEBUG const char * const yyname[] = { "end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -250,13 +261,13 @@ const char * const yyname[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"_BANG","_BANG_EQUALS", +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"_BANG","_BANG_EQUALS","_AMPER", "_AMPERAMPER","_LPAREN","_RPAREN","_PLUS_EQUALS","_COLON","_SEMIC","_LANGLE", "_LANGLE_EQUALS","_EQUALS","_RANGLE","_RANGLE_EQUALS","_QUESTION_EQUALS", "_LBRACKET","_RBRACKET","ACTIONS","BIND","CASE","DEFAULT","ELSE","EXISTING", "FOR","IF","IGNORE","IN","INCLUDE","LOCAL","MODULE","ON","PIECEMEAL","QUIETLY", -"RETURN","RULE","SWITCH","TOGETHER","UPDATED","WHILE","_LBRACE","_BARBAR", -"_RBRACE","ARG","STRING", +"RETURN","RULE","SWITCH","TOGETHER","UPDATED","WHILE","_LBRACE","_BAR", +"_BARBAR","_RBRACE","ARG","STRING", }; const char * const yyrule[] = { "$accept : run", @@ -283,11 +294,12 @@ const char * const yyrule[] = { "rule : RETURN list _SEMIC", "rule : FOR local_opt ARG IN list _LBRACE block _RBRACE", "rule : SWITCH list _LBRACE cases _RBRACE", -"rule : IF cond _LBRACE block _RBRACE", +"rule : IF expr _LBRACE block _RBRACE", "rule : MODULE list _LBRACE block _RBRACE", -"rule : WHILE cond _LBRACE block _RBRACE", -"rule : IF cond _LBRACE block _RBRACE ELSE rule", +"rule : WHILE expr _LBRACE block _RBRACE", +"rule : IF expr _LBRACE block _RBRACE ELSE rule", "rule : local_opt RULE ARG arglist_opt rule", +"rule : ON arg rule", "$$1 :", "$$2 :", "rule : ACTIONS eflags ARG bindlist _LBRACE $$1 STRING $$2 _RBRACE", @@ -295,18 +307,20 @@ const char * const yyrule[] = { "assign : _PLUS_EQUALS", "assign : _QUESTION_EQUALS", "assign : DEFAULT _EQUALS", -"cond : arg", -"cond : arg _EQUALS arg", -"cond : arg _BANG_EQUALS arg", -"cond : arg _LANGLE arg", -"cond : arg _LANGLE_EQUALS arg", -"cond : arg _RANGLE arg", -"cond : arg _RANGLE_EQUALS arg", -"cond : arg IN list", -"cond : _BANG cond", -"cond : cond _AMPERAMPER cond", -"cond : cond _BARBAR cond", -"cond : _LPAREN cond _RPAREN", +"expr : arg", +"expr : arg _EQUALS arg", +"expr : arg _BANG_EQUALS arg", +"expr : arg _LANGLE arg", +"expr : arg _LANGLE_EQUALS arg", +"expr : arg _RANGLE arg", +"expr : arg _RANGLE_EQUALS arg", +"expr : expr _AMPER expr", +"expr : expr _AMPERAMPER expr", +"expr : expr _BAR expr", +"expr : expr _BARBAR expr", +"expr : arg IN list", +"expr : _BANG expr", +"expr : _LPAREN expr _RPAREN", "cases :", "cases : case cases", "case : CASE ARG _COLON block", @@ -316,7 +330,11 @@ const char * const yyrule[] = { "listp :", "listp : listp arg", "arg : ARG", -"arg : _LBRACKET ARG lol _RBRACKET", +"$$3 :", +"arg : _LBRACKET $$3 func _RBRACKET", +"func : ARG lol", +"func : ON arg ARG lol", +"func : ON arg RETURN list", "eflags :", "eflags : eflags eflag", "eflag : UPDATED", @@ -554,270 +572,298 @@ yyreduce: switch (yyn) { case 2: -#line 135 "jamgram.y" +#line 142 "jamgram.y" { parse_save( yyvsp[0].parse ); } break; case 3: -#line 146 "jamgram.y" +#line 153 "jamgram.y" { yyval.parse = yyvsp[0].parse; } break; case 4: -#line 148 "jamgram.y" +#line 155 "jamgram.y" { yyval.parse = yyvsp[0].parse; } break; case 5: -#line 152 "jamgram.y" +#line 159 "jamgram.y" { yyval.parse = yyvsp[0].parse; } break; case 6: -#line 154 "jamgram.y" +#line 161 "jamgram.y" { yyval.parse = prules( yyvsp[-1].parse, yyvsp[0].parse ); } break; case 7: -#line 156 "jamgram.y" +#line 163 "jamgram.y" { yyval.parse = plocal( yyvsp[-3].parse, yyvsp[-2].parse, yyvsp[0].parse ); } break; case 8: -#line 160 "jamgram.y" +#line 167 "jamgram.y" { yyval.parse = pnull(); } break; case 9: -#line 164 "jamgram.y" +#line 171 "jamgram.y" { yyval.parse = yyvsp[0].parse; yyval.number = ASSIGN_SET; } break; case 10: -#line 166 "jamgram.y" +#line 173 "jamgram.y" { yyval.parse = yyvsp[0].parse; yyval.number = ASSIGN_APPEND; } break; case 11: -#line 170 "jamgram.y" +#line 177 "jamgram.y" { yyval.parse = yyvsp[-1].parse; } break; case 12: -#line 172 "jamgram.y" +#line 179 "jamgram.y" { yyval.parse = P0; } break; case 13: -#line 176 "jamgram.y" +#line 183 "jamgram.y" { yyval.number = 1; } break; case 14: -#line 178 "jamgram.y" +#line 185 "jamgram.y" { yyval.number = 0; } break; case 15: -#line 182 "jamgram.y" +#line 189 "jamgram.y" { yyval.parse = yyvsp[-1].parse; } break; case 16: -#line 184 "jamgram.y" +#line 191 "jamgram.y" { yyval.parse = pincl( yyvsp[-1].parse ); } break; case 17: -#line 186 "jamgram.y" +#line 193 "jamgram.y" { yyval.parse = prule( yyvsp[-2].string, yyvsp[-1].parse ); } break; case 18: -#line 188 "jamgram.y" +#line 195 "jamgram.y" { yyval.parse = pset( yyvsp[-3].parse, yyvsp[-1].parse, yyvsp[-2].number ); } break; case 19: -#line 190 "jamgram.y" +#line 197 "jamgram.y" { yyval.parse = psetmodule( yyvsp[-2].parse, yyvsp[-1].parse, yyvsp[-1].number ); } break; case 20: -#line 192 "jamgram.y" +#line 199 "jamgram.y" { yyval.parse = pset1( yyvsp[-5].parse, yyvsp[-3].parse, yyvsp[-1].parse, yyvsp[-2].number ); } break; case 21: -#line 194 "jamgram.y" +#line 201 "jamgram.y" { yyval.parse = yyvsp[-1].parse; } break; case 22: -#line 196 "jamgram.y" +#line 203 "jamgram.y" { yyval.parse = pfor( yyvsp[-5].string, yyvsp[-3].parse, yyvsp[-1].parse, yyvsp[-6].number ); } break; case 23: -#line 198 "jamgram.y" +#line 205 "jamgram.y" { yyval.parse = pswitch( yyvsp[-3].parse, yyvsp[-1].parse ); } break; case 24: -#line 200 "jamgram.y" +#line 207 "jamgram.y" { yyval.parse = pif( yyvsp[-3].parse, yyvsp[-1].parse, pnull() ); } break; case 25: -#line 202 "jamgram.y" +#line 209 "jamgram.y" { yyval.parse = pmodule( yyvsp[-3].parse, yyvsp[-1].parse ); } break; case 26: -#line 204 "jamgram.y" +#line 211 "jamgram.y" { yyval.parse = pwhile( yyvsp[-3].parse, yyvsp[-1].parse ); } break; case 27: -#line 206 "jamgram.y" +#line 213 "jamgram.y" { yyval.parse = pif( yyvsp[-5].parse, yyvsp[-3].parse, yyvsp[0].parse ); } break; case 28: -#line 208 "jamgram.y" +#line 215 "jamgram.y" { yyval.parse = psetc( yyvsp[-2].string, yyvsp[0].parse, yyvsp[-1].parse, yyvsp[-4].number ); } break; case 29: -#line 210 "jamgram.y" -{ yymode( SCAN_STRING ); } +#line 217 "jamgram.y" +{ yyval.parse = pon( yyvsp[-1].parse, yyvsp[0].parse ); } break; case 30: -#line 212 "jamgram.y" -{ yymode( SCAN_NORMAL ); } +#line 219 "jamgram.y" +{ yymode( SCAN_STRING ); } break; case 31: -#line 214 "jamgram.y" -{ yyval.parse = psete( yyvsp[-6].string,yyvsp[-5].parse,yyvsp[-2].string,yyvsp[-7].number ); } +#line 221 "jamgram.y" +{ yymode( SCAN_NORMAL ); } break; case 32: -#line 222 "jamgram.y" -{ yyval.number = ASSIGN_SET; } +#line 223 "jamgram.y" +{ yyval.parse = psete( yyvsp[-6].string,yyvsp[-5].parse,yyvsp[-2].string,yyvsp[-7].number ); } break; case 33: -#line 224 "jamgram.y" -{ yyval.number = ASSIGN_APPEND; } +#line 231 "jamgram.y" +{ yyval.number = ASSIGN_SET; } break; case 34: -#line 226 "jamgram.y" -{ yyval.number = ASSIGN_DEFAULT; } +#line 233 "jamgram.y" +{ yyval.number = ASSIGN_APPEND; } break; case 35: -#line 228 "jamgram.y" +#line 235 "jamgram.y" { yyval.number = ASSIGN_DEFAULT; } break; case 36: -#line 236 "jamgram.y" -{ yyval.parse = pcnode( COND_EXISTS, yyvsp[0].parse, pnull() ); } +#line 237 "jamgram.y" +{ yyval.number = ASSIGN_DEFAULT; } break; case 37: -#line 238 "jamgram.y" -{ yyval.parse = pcnode( COND_EQUALS, yyvsp[-2].parse, yyvsp[0].parse ); } +#line 244 "jamgram.y" +{ yyval.parse = peval( EXPR_EXISTS, yyvsp[0].parse, pnull() ); } break; case 38: -#line 240 "jamgram.y" -{ yyval.parse = pcnode( COND_NOTEQ, yyvsp[-2].parse, yyvsp[0].parse ); } +#line 246 "jamgram.y" +{ yyval.parse = peval( EXPR_EQUALS, yyvsp[-2].parse, yyvsp[0].parse ); } break; case 39: -#line 242 "jamgram.y" -{ yyval.parse = pcnode( COND_LESS, yyvsp[-2].parse, yyvsp[0].parse ); } +#line 248 "jamgram.y" +{ yyval.parse = peval( EXPR_NOTEQ, yyvsp[-2].parse, yyvsp[0].parse ); } break; case 40: -#line 244 "jamgram.y" -{ yyval.parse = pcnode( COND_LESSEQ, yyvsp[-2].parse, yyvsp[0].parse ); } +#line 250 "jamgram.y" +{ yyval.parse = peval( EXPR_LESS, yyvsp[-2].parse, yyvsp[0].parse ); } break; case 41: -#line 246 "jamgram.y" -{ yyval.parse = pcnode( COND_MORE, yyvsp[-2].parse, yyvsp[0].parse ); } +#line 252 "jamgram.y" +{ yyval.parse = peval( EXPR_LESSEQ, yyvsp[-2].parse, yyvsp[0].parse ); } break; case 42: -#line 248 "jamgram.y" -{ yyval.parse = pcnode( COND_MOREEQ, yyvsp[-2].parse, yyvsp[0].parse ); } +#line 254 "jamgram.y" +{ yyval.parse = peval( EXPR_MORE, yyvsp[-2].parse, yyvsp[0].parse ); } break; case 43: -#line 250 "jamgram.y" -{ yyval.parse = pcnode( COND_IN, yyvsp[-2].parse, yyvsp[0].parse ); } +#line 256 "jamgram.y" +{ yyval.parse = peval( EXPR_MOREEQ, yyvsp[-2].parse, yyvsp[0].parse ); } break; case 44: -#line 252 "jamgram.y" -{ yyval.parse = pcnode( COND_NOT, yyvsp[0].parse, P0 ); } +#line 258 "jamgram.y" +{ yyval.parse = peval( EXPR_AND, yyvsp[-2].parse, yyvsp[0].parse ); } break; case 45: -#line 254 "jamgram.y" -{ yyval.parse = pcnode( COND_AND, yyvsp[-2].parse, yyvsp[0].parse ); } +#line 260 "jamgram.y" +{ yyval.parse = pshortcircuiteval( EXPR_AND, yyvsp[-2].parse, yyvsp[0].parse ); } break; case 46: -#line 256 "jamgram.y" -{ yyval.parse = pcnode( COND_OR, yyvsp[-2].parse, yyvsp[0].parse ); } +#line 262 "jamgram.y" +{ yyval.parse = peval( EXPR_OR, yyvsp[-2].parse, yyvsp[0].parse ); } break; case 47: -#line 258 "jamgram.y" -{ yyval.parse = yyvsp[-1].parse; } +#line 264 "jamgram.y" +{ yyval.parse = pshortcircuiteval( EXPR_OR, yyvsp[-2].parse, yyvsp[0].parse ); } break; case 48: -#line 268 "jamgram.y" -{ yyval.parse = P0; } +#line 266 "jamgram.y" +{ yyval.parse = peval( EXPR_IN, yyvsp[-2].parse, yyvsp[0].parse ); } break; case 49: -#line 270 "jamgram.y" -{ yyval.parse = pnode( yyvsp[-1].parse, yyvsp[0].parse ); } +#line 268 "jamgram.y" +{ yyval.parse = peval( EXPR_NOT, yyvsp[0].parse, pnull() ); } break; case 50: -#line 274 "jamgram.y" -{ yyval.parse = psnode( yyvsp[-2].string, yyvsp[0].parse ); } +#line 270 "jamgram.y" +{ yyval.parse = yyvsp[-1].parse; } break; case 51: -#line 283 "jamgram.y" -{ yyval.parse = pnode( P0, yyvsp[0].parse ); } +#line 281 "jamgram.y" +{ yyval.parse = P0; } break; case 52: -#line 285 "jamgram.y" -{ yyval.parse = pnode( yyvsp[0].parse, yyvsp[-2].parse ); } +#line 283 "jamgram.y" +{ yyval.parse = pnode( yyvsp[-1].parse, yyvsp[0].parse ); } break; case 53: -#line 295 "jamgram.y" -{ yyval.parse = yyvsp[0].parse; yymode( SCAN_NORMAL ); } +#line 287 "jamgram.y" +{ yyval.parse = psnode( yyvsp[-2].string, yyvsp[0].parse ); } break; case 54: -#line 299 "jamgram.y" -{ yyval.parse = pnull(); yymode( SCAN_PUNCT ); } +#line 296 "jamgram.y" +{ yyval.parse = pnode( P0, yyvsp[0].parse ); } break; case 55: -#line 301 "jamgram.y" -{ yyval.parse = pappend( yyvsp[-1].parse, yyvsp[0].parse ); } +#line 298 "jamgram.y" +{ yyval.parse = pnode( yyvsp[0].parse, yyvsp[-2].parse ); } break; case 56: -#line 305 "jamgram.y" -{ yyval.parse = plist( yyvsp[0].string ); } +#line 308 "jamgram.y" +{ yyval.parse = yyvsp[0].parse; yymode( SCAN_NORMAL ); } break; case 57: -#line 307 "jamgram.y" -{ yyval.parse = prule( yyvsp[-2].string, yyvsp[-1].parse ); } +#line 312 "jamgram.y" +{ yyval.parse = pnull(); yymode( SCAN_PUNCT ); } break; case 58: -#line 317 "jamgram.y" -{ yyval.number = 0; } +#line 314 "jamgram.y" +{ yyval.parse = pappend( yyvsp[-1].parse, yyvsp[0].parse ); } break; case 59: -#line 319 "jamgram.y" -{ yyval.number = yyvsp[-1].number | yyvsp[0].number; } +#line 318 "jamgram.y" +{ yyval.parse = plist( yyvsp[0].string ); } break; case 60: -#line 323 "jamgram.y" -{ yyval.number = EXEC_UPDATED; } +#line 319 "jamgram.y" +{ yymode( SCAN_NORMAL ); } break; case 61: -#line 325 "jamgram.y" -{ yyval.number = EXEC_TOGETHER; } +#line 320 "jamgram.y" +{ yyval.parse = yyvsp[-1].parse; } break; case 62: -#line 327 "jamgram.y" -{ yyval.number = EXEC_IGNORE; } +#line 329 "jamgram.y" +{ yyval.parse = prule( yyvsp[-1].string, yyvsp[0].parse ); } break; case 63: -#line 329 "jamgram.y" -{ yyval.number = EXEC_QUIETLY; } +#line 331 "jamgram.y" +{ yyval.parse = pon( yyvsp[-2].parse, prule( yyvsp[-1].string, yyvsp[0].parse ) ); } break; case 64: -#line 331 "jamgram.y" -{ yyval.number = EXEC_PIECEMEAL; } +#line 333 "jamgram.y" +{ yyval.parse = pon( yyvsp[-2].parse, yyvsp[0].parse ); } break; case 65: -#line 333 "jamgram.y" -{ yyval.number = EXEC_EXISTING; } +#line 343 "jamgram.y" +{ yyval.number = 0; } break; case 66: -#line 342 "jamgram.y" -{ yyval.parse = pnull(); } +#line 345 "jamgram.y" +{ yyval.number = yyvsp[-1].number | yyvsp[0].number; } break; case 67: -#line 344 "jamgram.y" +#line 349 "jamgram.y" +{ yyval.number = EXEC_UPDATED; } +break; +case 68: +#line 351 "jamgram.y" +{ yyval.number = EXEC_TOGETHER; } +break; +case 69: +#line 353 "jamgram.y" +{ yyval.number = EXEC_IGNORE; } +break; +case 70: +#line 355 "jamgram.y" +{ yyval.number = EXEC_QUIETLY; } +break; +case 71: +#line 357 "jamgram.y" +{ yyval.number = EXEC_PIECEMEAL; } +break; +case 72: +#line 359 "jamgram.y" +{ yyval.number = EXEC_EXISTING; } +break; +case 73: +#line 368 "jamgram.y" +{ yyval.parse = pnull(); } +break; +case 74: +#line 370 "jamgram.y" { yyval.parse = yyvsp[0].parse; } break; -#line 821 "y.tab.c" +#line 867 "y.tab.c" } yyssp -= yym; yystate = *yyssp; diff --git a/src/engine/jamgram.h b/src/engine/jamgram.h index c31089bc9..e96ee6d9a 100644 --- a/src/engine/jamgram.h +++ b/src/engine/jamgram.h @@ -4,44 +4,46 @@ #define _BANG 257 #define _BANG_EQUALS 258 -#define _AMPERAMPER 259 -#define _LPAREN 260 -#define _RPAREN 261 -#define _PLUS_EQUALS 262 -#define _COLON 263 -#define _SEMIC 264 -#define _LANGLE 265 -#define _LANGLE_EQUALS 266 -#define _EQUALS 267 -#define _RANGLE 268 -#define _RANGLE_EQUALS 269 -#define _QUESTION_EQUALS 270 -#define _LBRACKET 271 -#define _RBRACKET 272 -#define ACTIONS 273 -#define BIND 274 -#define CASE 275 -#define DEFAULT 276 -#define ELSE 277 -#define EXISTING 278 -#define FOR 279 -#define IF 280 -#define IGNORE 281 -#define IN 282 -#define INCLUDE 283 -#define LOCAL 284 -#define MODULE 285 -#define ON 286 -#define PIECEMEAL 287 -#define QUIETLY 288 -#define RETURN 289 -#define RULE 290 -#define SWITCH 291 -#define TOGETHER 292 -#define UPDATED 293 -#define WHILE 294 -#define _LBRACE 295 -#define _BARBAR 296 -#define _RBRACE 297 -#define ARG 298 -#define STRING 299 +#define _AMPER 259 +#define _AMPERAMPER 260 +#define _LPAREN 261 +#define _RPAREN 262 +#define _PLUS_EQUALS 263 +#define _COLON 264 +#define _SEMIC 265 +#define _LANGLE 266 +#define _LANGLE_EQUALS 267 +#define _EQUALS 268 +#define _RANGLE 269 +#define _RANGLE_EQUALS 270 +#define _QUESTION_EQUALS 271 +#define _LBRACKET 272 +#define _RBRACKET 273 +#define ACTIONS 274 +#define BIND 275 +#define CASE 276 +#define DEFAULT 277 +#define ELSE 278 +#define EXISTING 279 +#define FOR 280 +#define IF 281 +#define IGNORE 282 +#define IN 283 +#define INCLUDE 284 +#define LOCAL 285 +#define MODULE 286 +#define ON 287 +#define PIECEMEAL 288 +#define QUIETLY 289 +#define RETURN 290 +#define RULE 291 +#define SWITCH 292 +#define TOGETHER 293 +#define UPDATED 294 +#define WHILE 295 +#define _LBRACE 296 +#define _BAR 297 +#define _BARBAR 298 +#define _RBRACE 299 +#define ARG 300 +#define STRING 301 diff --git a/src/engine/jamgram.y b/src/engine/jamgram.y index dac17eb0a..bf7164a32 100644 --- a/src/engine/jamgram.y +++ b/src/engine/jamgram.y @@ -1,5 +1,6 @@ %token _BANG %token _BANG_EQUALS +%token _AMPER %token _AMPERAMPER %token _LPAREN %token _RPAREN @@ -37,6 +38,7 @@ %token UPDATED %token WHILE %token _LBRACE +%token _BAR %token _BARBAR %token _RBRACE /* @@ -86,10 +88,13 @@ %token ARG STRING -%left _BARBAR -%left _AMPERAMPER +%left _BARBAR _BAR +%left _AMPERAMPER _AMPER +%left _EQUALS _BANG_EQUALS IN +%left _LANGLE _LANGLE_EQUALS _RANGLE _RANGLE_EQUALS %left _BANG + %{ #include "jam.h" @@ -104,6 +109,8 @@ # define S0 (char *)0 # define pappend( l,r ) parse_make( compile_append,l,r,P0,S0,S0,0 ) +# define peval( c,l,r ) parse_make( compile_eval,l,r,P0,S0,S0,c ) +# define pshortcircuiteval( c,l,r ) parse_make( compile_eval,l,P0,r,S0,S0,c ) # define pfor( s,l,r,x ) parse_make( compile_foreach,l,r,P0,s,S0,x ) # define pif( l,r,t ) parse_make( compile_if,l,r,t,S0,S0,0 ) # define pwhile( l,r ) parse_make( compile_while,l,r,P0,S0,S0,0 ) @@ -112,6 +119,7 @@ # define plocal( l,r,t ) parse_make( compile_local,l,r,t,S0,S0,0 ) # define pmodule( l,r ) parse_make( compile_module,l,r,P0,S0,S0,0 ) # define pnull() parse_make( compile_null,P0,P0,P0,S0,S0,0 ) +# define pon( l,r ) parse_make( compile_on,l,r,P0,S0,S0,0 ) # define prule( s,p ) parse_make( compile_rule,p,P0,P0,s,S0,0 ) # define prules( l,r ) parse_make( compile_rules,l,r,P0,S0,S0,0 ) # define pset( l,r,a ) parse_make( compile_set,l,r,P0,S0,S0,a ) @@ -122,7 +130,6 @@ # define pswitch( l,r ) parse_make( compile_switch,l,r,P0,S0,S0,0 ) # define pnode( l,r ) parse_make( F0,l,r,P0,S0,S0,0 ) -# define pcnode( c,l,r ) parse_make( F0,l,r,P0,S0,S0,c ) # define psnode( s,l ) parse_make( F0,l,P0,P0,s,S0,0 ) %} @@ -196,16 +203,18 @@ rule : _LBRACE block _RBRACE { $$.parse = pfor( $3.string, $5.parse, $7.parse, $2.number ); } | SWITCH list _LBRACE cases _RBRACE { $$.parse = pswitch( $2.parse, $4.parse ); } - | IF cond _LBRACE block _RBRACE + | IF expr _LBRACE block _RBRACE { $$.parse = pif( $2.parse, $4.parse, pnull() ); } | MODULE list _LBRACE block _RBRACE { $$.parse = pmodule( $2.parse, $4.parse ); } - | WHILE cond _LBRACE block _RBRACE + | WHILE expr _LBRACE block _RBRACE { $$.parse = pwhile( $2.parse, $4.parse ); } - | IF cond _LBRACE block _RBRACE ELSE rule + | IF expr _LBRACE block _RBRACE ELSE rule { $$.parse = pif( $2.parse, $4.parse, $7.parse ); } - | local_opt RULE ARG arglist_opt rule + | local_opt RULE ARG arglist_opt rule { $$.parse = psetc( $3.string, $5.parse, $4.parse, $1.number ); } + | ON arg rule + { $$.parse = pon( $2.parse, $3.parse ); } | ACTIONS eflags ARG bindlist _LBRACE { yymode( SCAN_STRING ); } STRING @@ -229,35 +238,39 @@ assign : _EQUALS ; /* - * cond - a conditional for 'if' + * expr - an expression for if */ - -cond : arg - { $$.parse = pcnode( COND_EXISTS, $1.parse, pnull() ); } +expr : arg + { $$.parse = peval( EXPR_EXISTS, $1.parse, pnull() ); } | arg _EQUALS arg - { $$.parse = pcnode( COND_EQUALS, $1.parse, $3.parse ); } + { $$.parse = peval( EXPR_EQUALS, $1.parse, $3.parse ); } | arg _BANG_EQUALS arg - { $$.parse = pcnode( COND_NOTEQ, $1.parse, $3.parse ); } + { $$.parse = peval( EXPR_NOTEQ, $1.parse, $3.parse ); } | arg _LANGLE arg - { $$.parse = pcnode( COND_LESS, $1.parse, $3.parse ); } + { $$.parse = peval( EXPR_LESS, $1.parse, $3.parse ); } | arg _LANGLE_EQUALS arg - { $$.parse = pcnode( COND_LESSEQ, $1.parse, $3.parse ); } + { $$.parse = peval( EXPR_LESSEQ, $1.parse, $3.parse ); } | arg _RANGLE arg - { $$.parse = pcnode( COND_MORE, $1.parse, $3.parse ); } + { $$.parse = peval( EXPR_MORE, $1.parse, $3.parse ); } | arg _RANGLE_EQUALS arg - { $$.parse = pcnode( COND_MOREEQ, $1.parse, $3.parse ); } + { $$.parse = peval( EXPR_MOREEQ, $1.parse, $3.parse ); } + | expr _AMPER expr + { $$.parse = peval( EXPR_AND, $1.parse, $3.parse ); } + | expr _AMPERAMPER expr + { $$.parse = pshortcircuiteval( EXPR_AND, $1.parse, $3.parse ); } + | expr _BAR expr + { $$.parse = peval( EXPR_OR, $1.parse, $3.parse ); } + | expr _BARBAR expr + { $$.parse = pshortcircuiteval( EXPR_OR, $1.parse, $3.parse ); } | arg IN list - { $$.parse = pcnode( COND_IN, $1.parse, $3.parse ); } - | _BANG cond - { $$.parse = pcnode( COND_NOT, $2.parse, P0 ); } - | cond _AMPERAMPER cond - { $$.parse = pcnode( COND_AND, $1.parse, $3.parse ); } - | cond _BARBAR cond - { $$.parse = pcnode( COND_OR, $1.parse, $3.parse ); } - | _LPAREN cond _RPAREN + { $$.parse = peval( EXPR_IN, $1.parse, $3.parse ); } + | _BANG expr + { $$.parse = peval( EXPR_NOT, $2.parse, pnull() ); } + | _LPAREN expr _RPAREN { $$.parse = $2.parse; } ; + /* * cases - action elements inside a 'switch' * case - a single action element inside a 'switch' @@ -303,8 +316,21 @@ listp : /* empty */ arg : ARG { $$.parse = plist( $1.string ); } - | _LBRACKET ARG lol _RBRACKET - { $$.parse = prule( $2.string, $3.parse ); } + | _LBRACKET { yymode( SCAN_NORMAL ); } func _RBRACKET + { $$.parse = $3.parse; } + ; + +/* + * func - a function call (inside []) + * This needs to be split cleanly out of 'rule' + */ + +func : ARG lol + { $$.parse = prule( $1.string, $2.parse ); } + | ON arg ARG lol + { $$.parse = pon( $2.parse, prule( $3.string, $4.parse ) ); } + | ON arg RETURN list + { $$.parse = pon( $2.parse, $4.parse ); } ; diff --git a/src/engine/jamgram.yy b/src/engine/jamgram.yy index 4690159a3..d49ef016e 100644 --- a/src/engine/jamgram.yy +++ b/src/engine/jamgram.yy @@ -45,10 +45,13 @@ %token ARG STRING -%left `||` -%left `&&` +%left `||` `|` +%left `&&` `&` +%left `=` `!=` `in` +%left `<` `<=` `>` `>=` %left `!` + %{ #include "jam.h" @@ -63,6 +66,8 @@ # define S0 (char *)0 # define pappend( l,r ) parse_make( compile_append,l,r,P0,S0,S0,0 ) +# define peval( c,l,r ) parse_make( compile_eval,l,r,P0,S0,S0,c ) +# define pshortcircuiteval( c,l,r ) parse_make( compile_eval,l,P0,r,S0,S0,c ) # define pfor( s,l,r,x ) parse_make( compile_foreach,l,r,P0,s,S0,x ) # define pif( l,r,t ) parse_make( compile_if,l,r,t,S0,S0,0 ) # define pwhile( l,r ) parse_make( compile_while,l,r,P0,S0,S0,0 ) @@ -71,6 +76,7 @@ # define plocal( l,r,t ) parse_make( compile_local,l,r,t,S0,S0,0 ) # define pmodule( l,r ) parse_make( compile_module,l,r,P0,S0,S0,0 ) # define pnull() parse_make( compile_null,P0,P0,P0,S0,S0,0 ) +# define pon( l,r ) parse_make( compile_on,l,r,P0,S0,S0,0 ) # define prule( s,p ) parse_make( compile_rule,p,P0,P0,s,S0,0 ) # define prules( l,r ) parse_make( compile_rules,l,r,P0,S0,S0,0 ) # define pset( l,r,a ) parse_make( compile_set,l,r,P0,S0,S0,a ) @@ -81,7 +87,6 @@ # define pswitch( l,r ) parse_make( compile_switch,l,r,P0,S0,S0,0 ) # define pnode( l,r ) parse_make( F0,l,r,P0,S0,S0,0 ) -# define pcnode( c,l,r ) parse_make( F0,l,r,P0,S0,S0,c ) # define psnode( s,l ) parse_make( F0,l,P0,P0,s,S0,0 ) %} @@ -155,16 +160,18 @@ rule : `{` block `}` { $$.parse = pfor( $3.string, $5.parse, $7.parse, $2.number ); } | `switch` list `{` cases `}` { $$.parse = pswitch( $2.parse, $4.parse ); } - | `if` cond `{` block `}` + | `if` expr `{` block `}` { $$.parse = pif( $2.parse, $4.parse, pnull() ); } | `module` list `{` block `}` { $$.parse = pmodule( $2.parse, $4.parse ); } - | `while` cond `{` block `}` + | `while` expr `{` block `}` { $$.parse = pwhile( $2.parse, $4.parse ); } - | `if` cond `{` block `}` `else` rule + | `if` expr `{` block `}` `else` rule { $$.parse = pif( $2.parse, $4.parse, $7.parse ); } - | local_opt `rule` ARG arglist_opt rule + | local_opt `rule` ARG arglist_opt rule { $$.parse = psetc( $3.string, $5.parse, $4.parse, $1.number ); } + | `on` arg rule + { $$.parse = pon( $2.parse, $3.parse ); } | `actions` eflags ARG bindlist `{` { yymode( SCAN_STRING ); } STRING @@ -188,35 +195,39 @@ assign : `=` ; /* - * cond - a conditional for 'if' + * expr - an expression for if */ - -cond : arg - { $$.parse = pcnode( COND_EXISTS, $1.parse, pnull() ); } +expr : arg + { $$.parse = peval( EXPR_EXISTS, $1.parse, pnull() ); } | arg `=` arg - { $$.parse = pcnode( COND_EQUALS, $1.parse, $3.parse ); } + { $$.parse = peval( EXPR_EQUALS, $1.parse, $3.parse ); } | arg `!=` arg - { $$.parse = pcnode( COND_NOTEQ, $1.parse, $3.parse ); } + { $$.parse = peval( EXPR_NOTEQ, $1.parse, $3.parse ); } | arg `<` arg - { $$.parse = pcnode( COND_LESS, $1.parse, $3.parse ); } + { $$.parse = peval( EXPR_LESS, $1.parse, $3.parse ); } | arg `<=` arg - { $$.parse = pcnode( COND_LESSEQ, $1.parse, $3.parse ); } + { $$.parse = peval( EXPR_LESSEQ, $1.parse, $3.parse ); } | arg `>` arg - { $$.parse = pcnode( COND_MORE, $1.parse, $3.parse ); } + { $$.parse = peval( EXPR_MORE, $1.parse, $3.parse ); } | arg `>=` arg - { $$.parse = pcnode( COND_MOREEQ, $1.parse, $3.parse ); } + { $$.parse = peval( EXPR_MOREEQ, $1.parse, $3.parse ); } + | expr `&` expr + { $$.parse = peval( EXPR_AND, $1.parse, $3.parse ); } + | expr `&&` expr + { $$.parse = pshortcircuiteval( EXPR_AND, $1.parse, $3.parse ); } + | expr `|` expr + { $$.parse = peval( EXPR_OR, $1.parse, $3.parse ); } + | expr `||` expr + { $$.parse = pshortcircuiteval( EXPR_OR, $1.parse, $3.parse ); } | arg `in` list - { $$.parse = pcnode( COND_IN, $1.parse, $3.parse ); } - | `!` cond - { $$.parse = pcnode( COND_NOT, $2.parse, P0 ); } - | cond `&&` cond - { $$.parse = pcnode( COND_AND, $1.parse, $3.parse ); } - | cond `||` cond - { $$.parse = pcnode( COND_OR, $1.parse, $3.parse ); } - | `(` cond `)` + { $$.parse = peval( EXPR_IN, $1.parse, $3.parse ); } + | `!` expr + { $$.parse = peval( EXPR_NOT, $2.parse, pnull() ); } + | `(` expr `)` { $$.parse = $2.parse; } ; + /* * cases - action elements inside a 'switch' * case - a single action element inside a 'switch' @@ -262,8 +273,21 @@ listp : /* empty */ arg : ARG { $$.parse = plist( $1.string ); } - | `[` ARG lol `]` - { $$.parse = prule( $2.string, $3.parse ); } + | `[` { yymode( SCAN_NORMAL ); } func `]` + { $$.parse = $3.parse; } + ; + +/* + * func - a function call (inside []) + * This needs to be split cleanly out of 'rule' + */ + +func : ARG lol + { $$.parse = prule( $1.string, $2.parse ); } + | `on` arg ARG lol + { $$.parse = pon( $2.parse, prule( $3.string, $4.parse ) ); } + | `on` arg `return` list + { $$.parse = pon( $2.parse, $4.parse ); } ; diff --git a/src/engine/jamgramtab.h b/src/engine/jamgramtab.h index 018555b93..e6cd0afe0 100644 --- a/src/engine/jamgramtab.h +++ b/src/engine/jamgramtab.h @@ -1,5 +1,6 @@ { "!", _BANG }, { "!=", _BANG_EQUALS }, + { "&", _AMPER }, { "&&", _AMPERAMPER }, { "(", _LPAREN }, { ")", _RPAREN }, @@ -37,5 +38,6 @@ { "updated", UPDATED }, { "while", WHILE }, { "{", _LBRACE }, + { "|", _BAR }, { "||", _BARBAR }, { "}", _RBRACE }, diff --git a/src/engine/make1.c b/src/engine/make1.c index 83e1b3954..f15d687b6 100644 --- a/src/engine/make1.c +++ b/src/engine/make1.c @@ -1,5 +1,5 @@ /* - * Copyright 1993, 1995 Christopher Seiwald. + * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. * * This file is part of Jam - see jam.c for Copyright information. */ diff --git a/src/engine/makedebugjam.bat b/src/engine/makedebugjam.bat index 3da69d3c8..ef01766e2 100755 --- a/src/engine/makedebugjam.bat +++ b/src/engine/makedebugjam.bat @@ -2,4 +2,7 @@ call c:\tools\msvc6\vc98\bin\vcvars32.bat set VISUALC=c:\tools\msvc6\vc98 set JAM_TOOLSET=VISUALC rm -rf bin.ntx86/jam.exe bin.ntx86/*.obj bin.ntx86/*.lib +set BOOST_ROOT= +set BOOST_BUILD_PATH= +set JAMBASE= nmake -fbuilds/win32-visualc.mk JAMBASE= BOOST_ROOT= BOOST_BUILD_PATH= CFLAGS="/GZ /Zi /MLd -DNT" CCFLAGS="/GZ /Zi /MLd" LINKLIBS="c:\tools\msvc6\vc98\lib\advapi32.lib c:\tools\msvc6\vc98\lib\oldnames.lib c:\tools\msvc6\vc98\lib\gdi32.lib c:\tools\msvc6\vc98\lib\user32.lib c:\tools\msvc6\vc98\lib\kernel32.lib" LINKFLAGS="/DEBUG" YACC="byacc" YACCFILES="y.tab" YACCFLAGS=-vd %* diff --git a/src/engine/pathmac.c b/src/engine/pathmac.c index 757b8869e..ad39a671b 100644 --- a/src/engine/pathmac.c +++ b/src/engine/pathmac.c @@ -1,5 +1,5 @@ /* - * Copyright 1993, 1995 Christopher Seiwald. + * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. * * This file is part of Jam - see jam.c for Copyright information. */ @@ -13,7 +13,7 @@ */ # include "jam.h" -# include "filesys.h" +# include "pathsys.h" # ifdef OS_MAC @@ -24,15 +24,15 @@ * * External routines: * - * file_parse() - split a file name into dir/base/suffix/member - * file_build() - build a filename given dir/base/suffix/member - * file_parent() - make a FILENAME point to its parent dir + * path_parse() - split a file name into dir/base/suffix/member + * path_build() - build a filename given dir/base/suffix/member + * path_parent() - make a PATHNAME point to its parent dir * - * File_parse() and file_build() just manipuate a string and a structure; + * File_parse() and path_build() just manipuate a string and a structure; * they do not make system calls. * * 04/08/94 (seiwald) - Coherent/386 support added. - * 12/26/93 (seiwald) - handle dir/.suffix properly in file_build() + * 12/26/93 (seiwald) - handle dir/.suffix properly in path_build() * 12/19/94 (mikem) - solaris string table insanity support * 12/21/94 (wingerd) Use backslashes for pathnames - the NT way. * 02/14/95 (seiwald) - parse and build /xxx properly @@ -44,16 +44,19 @@ * 05/03/96 (seiwald) - split from filent.c, fileunix.c * 12/20/96 (seiwald) - when looking for the rightmost . in a file name, * don't include the archive member name. + * 01/10/01 (seiwald) - path_parse now strips the trailing : from the + * directory name, unless the directory name is all + * :'s, so that $(d:P) works. */ /* - * file_parse() - split a file name into dir/base/suffix/member + * path_parse() - split a file name into dir/base/suffix/member */ void -file_parse( +path_parse( char *file, - FILENAME *f ) + PATHNAME *f ) { char *p, *q; char *end; @@ -71,16 +74,19 @@ file_parse( /* Look for dir: */ - p = strrchr( file, DELIM ); - - if( p ) + if( p = strrchr( file, DELIM ) ) { f->f_dir.ptr = file; f->f_dir.len = p - file; - - /* Dir of : is : */ - f->f_dir.len++; file = p + 1; + + /* All :'s? Include last : as part of directory name */ + + while( p > f->f_dir.ptr && *--p == DELIM ) + ; + + if( p == f->f_dir.ptr ) + f->f_dir.len++; } end = file + strlen( file ); @@ -117,7 +123,7 @@ file_parse( } /* - * file_build() - build a filename given dir/base/suffix/member + * path_build() - build a filename given dir/base/suffix/member */ # define DIR_EMPTY 0 /* "" */ @@ -159,8 +165,8 @@ file_flags( } void -file_build( - FILENAME *f, +path_build( + PATHNAME *f, string* file, int binding ) { @@ -237,11 +243,11 @@ file_build( } /* - * file_parent() - make a FILENAME point to its parent dir + * path_parent() - make a PATHNAME point to its parent dir */ void -file_parent( FILENAME *f ) +path_parent( PATHNAME *f ) { /* just set everything else to nothing */ diff --git a/src/engine/pathsys.h b/src/engine/pathsys.h new file mode 100644 index 000000000..d7a0b8476 --- /dev/null +++ b/src/engine/pathsys.h @@ -0,0 +1,57 @@ +/* + * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. + * + * This file is part of Jam - see jam.c for Copyright information. + */ + +/* + * pathsys.h - PATHNAME struct + */ + +/* + * PATHNAME - a name of a file, broken into dir/base/suffix(member) + * + * is salt to distinguish between targets that otherwise would + * have the same name: it never appears in the bound name of a target. + * (member) is an archive member name: the syntax is arbitrary, but must + * agree in path_parse(), path_build() and the Jambase. + * + * On VMS, we keep track of whether the original path was a directory + * (without a file), so that $(VAR:D) can climb to the parent. + */ + +#ifndef PATHSYS_VP_20020211_H +# define PATHSYS_VP_20020211_H + +#include "strings.h" + +typedef struct _pathname PATHNAME; +typedef struct _pathpart PATHPART; + +struct _pathpart { + char *ptr; + int len; +}; + +struct _pathname { + PATHPART part[6]; +# ifdef OS_VMS + int parent; +# endif + +# define f_grist part[0] +# define f_root part[1] +# define f_dir part[2] +# define f_base part[3] +# define f_suffix part[4] +# define f_member part[5] + +} ; + +void path_build( PATHNAME *f, string *file, int binding ); +void path_build1( PATHNAME *f, string *file ); + +void path_parse( char *file, PATHNAME *f ); +void path_parent( PATHNAME *f ); + +#endif // PATHSYS_VP_20020211_H diff --git a/src/engine/pathunix.c b/src/engine/pathunix.c index eee1e62e0..112d691f3 100644 --- a/src/engine/pathunix.c +++ b/src/engine/pathunix.c @@ -1,5 +1,5 @@ /* - * Copyright 1993, 1995 Christopher Seiwald. + * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. * * This file is part of Jam - see jam.c for Copyright information. */ @@ -13,7 +13,7 @@ */ # include "jam.h" -# include "filesys.h" +# include "pathsys.h" # include "strings.h" # ifdef USE_PATHUNIX @@ -23,15 +23,15 @@ * * External routines: * - * file_parse() - split a file name into dir/base/suffix/member - * file_build() - build a filename given dir/base/suffix/member - * file_parent() - make a FILENAME point to its parent dir + * path_parse() - split a file name into dir/base/suffix/member + * path_build() - build a filename given dir/base/suffix/member + * path_parent() - make a PATHNAME point to its parent dir * - * File_parse() and file_build() just manipuate a string and a structure; + * File_parse() and path_build() just manipuate a string and a structure; * they do not make system calls. * * 04/08/94 (seiwald) - Coherent/386 support added. - * 12/26/93 (seiwald) - handle dir/.suffix properly in file_build() + * 12/26/93 (seiwald) - handle dir/.suffix properly in path_build() * 12/19/94 (mikem) - solaris string table insanity support * 12/21/94 (wingerd) Use backslashes for pathnames - the NT way. * 02/14/95 (seiwald) - parse and build /xxx properly @@ -43,16 +43,17 @@ * 05/03/96 (seiwald) - split from filent.c, fileunix.c * 12/20/96 (seiwald) - when looking for the rightmost . in a file name, * don't include the archive member name. + * 01/13/01 (seiwald) - turn on \ handling on UNIX, on by accident */ /* - * file_parse() - split a file name into dir/base/suffix/member + * path_parse() - split a file name into dir/base/suffix/member */ void -file_parse( +path_parse( char *file, - FILENAME *f ) + PATHNAME *f ) { char *p, *q; char *end; @@ -72,14 +73,12 @@ file_parse( p = strrchr( file, '/' ); -# ifndef UNIX -# ifndef AMIGA +# if PATH_DELIM == '\\' /* On NT, look for dir\ as well */ { char *p1 = strrchr( file, '\\' ); p = p1 > p ? p1 : p; } -# endif # endif if( p ) @@ -92,13 +91,11 @@ file_parse( if( !f->f_dir.len ) f->f_dir.len = 1; -# ifndef UNIX -# ifndef AMIGA +# if PATH_DELIM == '\\' /* Special case for D:/ - dirname is D:/, not "D:" */ if( f->f_dir.len == 2 && file[1] == ':' ) f->f_dir.len = 3; -# endif # endif file = p + 1; @@ -138,12 +135,12 @@ file_parse( } /* - * file_build() - build a filename given dir/base/suffix/member + * path_build() - build a filename given dir/base/suffix/member */ void -file_build( - FILENAME *f, +path_build( + PATHNAME *f, string *file, int binding ) { @@ -210,11 +207,11 @@ file_build( } /* - * file_parent() - make a FILENAME point to its parent dir + * path_parent() - make a PATHNAME point to its parent dir */ void -file_parent( FILENAME *f ) +path_parent( PATHNAME *f ) { /* just set everything else to nothing */ diff --git a/src/engine/pathvms.c b/src/engine/pathvms.c index 91ac11594..e348f7da3 100644 --- a/src/engine/pathvms.c +++ b/src/engine/pathvms.c @@ -1,5 +1,5 @@ /* - * Copyright 1993, 1995 Christopher Seiwald. + * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. * * This file is part of Jam - see jam.c for Copyright information. */ @@ -13,7 +13,7 @@ */ # include "jam.h" -# include "filesys.h" +# include "pathsys.h" # ifdef OS_VMS @@ -24,11 +24,11 @@ * * External routines: * - * file_parse() - split a file name into dir/base/suffix/member - * file_build() - build a filename given dir/base/suffix/member - * file_parent() - make a FILENAME point to its parent dir + * path_parse() - split a file name into dir/base/suffix/member + * path_build() - build a filename given dir/base/suffix/member + * path_parent() - make a PATHNAME point to its parent dir * - * File_parse() and file_build() just manipuate a string and a structure; + * File_parse() and path_build() just manipuate a string and a structure; * they do not make system calls. * * WARNING! This file contains voodoo logic, as black magic is @@ -40,13 +40,13 @@ */ /* - * file_parse() - split a file name into dir/base/suffix/member + * path_parse() - split a file name into dir/base/suffix/member */ void -file_parse( +path_parse( char *file, - FILENAME *f ) + PATHNAME *f ) { char *p, *q; char *end; @@ -88,7 +88,7 @@ file_parse( p = 0; q = file; - while( q = memchr( q, '.', end - q ) ) + while( q = (char *)memchr( q, '.', end - q ) ) p = q++; if( p ) @@ -233,12 +233,12 @@ dir_flags( } /* - * file_build() - build a filename given dir/base/suffix/member + * path_build() - build a filename given dir/base/suffix/member */ void -file_build( - FILENAME *f, +path_build( + PATHNAME *f, string *file, int binding ) { @@ -393,11 +393,11 @@ file_build( } /* - * file_parent() - make a FILENAME point to its parent dir + * path_parent() - make a PATHNAME point to its parent dir */ void -file_parent( FILENAME *f ) +path_parent( PATHNAME *f ) { if( f->f_base.len ) { diff --git a/src/engine/scan.c b/src/engine/scan.c index e9a272e2d..861d3ce04 100644 --- a/src/engine/scan.c +++ b/src/engine/scan.c @@ -1,5 +1,5 @@ /* - * Copyright 1993, 1995 Christopher Seiwald. + * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. * * This file is part of Jam - see jam.c for Copyright information. */ @@ -251,10 +251,9 @@ yylex() else { char *b = buf; - int inquote = 0; - int literal = 0; - int hasquote = 0; struct keyword *k; + int inquote = 0; + int notkeyword; /* Eat white space */ @@ -281,22 +280,44 @@ yylex() yylval.file = incp->fname; yylval.line = incp->line; + /* While scanning the word, disqualify it for (expensive) */ + /* keyword lookup when we can: $anything, "anything", \anything */ + + notkeyword = c == '$'; + /* look for white space to delimit word */ /* "'s get stripped but preserve white space */ + /* \ protects next character */ - while( b < buf + sizeof( buf ) ) + while( + c != EOF && + b < buf + sizeof( buf ) && + ( inquote || !isspace( c ) ) ) { - if( literal ) - *b++ = c, literal = 0; - else if( c == '\\' ) - literal++; - else if( c == '"' ) - inquote = !inquote, hasquote++; - else + if( c == '"' ) + { + /* begin or end " */ + inquote = !inquote; + notkeyword = 1; + } + else if( c != '\\' ) + { + /* normal char */ *b++ = c; - - if( ( c = yychar() ) == EOF || !inquote && isspace( c ) ) + } + else if( ( c = yychar()) != EOF ) + { + /* \c */ + *b++ = c; + notkeyword = 1; + } + else + { + /* \EOF */ break; + } + + c = yychar(); } /* Check obvious errors. */ @@ -319,15 +340,13 @@ yylex() yyprev(); /* scan token table */ - /* don't scan if it's "anything", $anything, */ - /* or an alphabetic when were looking for punctuation */ + /* don't scan if it's obviously not a keyword or if its */ + /* an alphabetic when were looking for punctuation */ *b = 0; yylval.type = ARG; - if( !hasquote && - *buf != '$' && - !( isalpha( *buf ) && scanmode == SCAN_PUNCT ) ) + if( !notkeyword && !( isalpha( *buf ) && scanmode == SCAN_PUNCT ) ) { for( k = keywords; k->word; k++ ) if( *buf == *k->word && !strcmp( k->word, buf ) ) diff --git a/src/engine/search.c b/src/engine/search.c index 35e87f7fc..f41ed34fb 100644 --- a/src/engine/search.c +++ b/src/engine/search.c @@ -1,5 +1,5 @@ /* - * Copyright 1993, 1995 Christopher Seiwald. + * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. * * This file is part of Jam - see jam.c for Copyright information. */ @@ -16,7 +16,7 @@ # include "lists.h" # include "search.h" # include "timestamp.h" -# include "filesys.h" +# include "pathsys.h" # include "variable.h" # include "newstr.h" # include "compile.h" @@ -72,7 +72,7 @@ search( char *target, time_t *time ) { - FILENAME f[1]; + PATHNAME f[1]; LIST *varlist; string buf[1]; int found = 0; @@ -81,7 +81,7 @@ search( string_new( buf ); /* Parse the filename */ - file_parse( target, f ); + path_parse( target, f ); f->f_grist.ptr = 0; f->f_grist.len = 0; @@ -91,7 +91,7 @@ search( f->f_root.ptr = varlist->string; f->f_root.len = strlen( varlist->string ); - file_build( f, buf, 1 ); + path_build( f, buf, 1 ); if( DEBUG_SEARCH ) printf( "locate %s: %s\n", target, buf->value ); @@ -107,7 +107,7 @@ search( f->f_root.len = strlen( varlist->string ); string_truncate( buf, 0 ); - file_build( f, buf, 1 ); + path_build( f, buf, 1 ); if( DEBUG_SEARCH ) printf( "search %s: %s\n", target, buf->value ); @@ -134,7 +134,7 @@ search( f->f_root.len = 0; string_truncate( buf, 0 ); - file_build( f, buf, 1 ); + path_build( f, buf, 1 ); if( DEBUG_SEARCH ) printf( "search %s: %s\n", target, buf->value ); diff --git a/src/engine/timestamp.c b/src/engine/timestamp.c index 4da4f79df..88d2bdc50 100644 --- a/src/engine/timestamp.c +++ b/src/engine/timestamp.c @@ -1,5 +1,5 @@ /* - * Copyright 1993, 1995 Christopher Seiwald. + * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. * * This file is part of Jam - see jam.c for Copyright information. */ @@ -15,6 +15,7 @@ # include "jam.h" # include "hash.h" # include "filesys.h" +# include "pathsys.h" # include "timestamp.h" # include "newstr.h" # include "strings.h" @@ -49,7 +50,7 @@ struct _binding { } ; static struct hash *bindhash = 0; -static void time_enter( char *target, int found, time_t time ); +static void time_enter( void *, char *, int , time_t ); static char *time_progress[] = { @@ -70,7 +71,7 @@ timestamp( char *target, time_t *time ) { - FILENAME f1, f2; + PATHNAME f1, f2; BINDING binding, *b = &binding; string buf[1]; @@ -108,7 +109,7 @@ timestamp( /* Not found - have to scan for it */ - file_parse( target, &f1 ); + path_parse( target, &f1 ); /* Scan directory if not already done so */ @@ -117,8 +118,8 @@ timestamp( f2 = f1; f2.f_grist.len = 0; - file_parent( &f2 ); - file_build( &f2, buf, 0 ); + path_parent( &f2 ); + path_build( &f2, buf, 0 ); b->name = buf->value; b->time = b->flags = 0; @@ -129,7 +130,7 @@ timestamp( if( !( b->flags & BIND_SCANNED ) ) { - file_dirscan( buf->value, time_enter ); + file_dirscan( buf->value, time_enter, bindhash ); b->flags |= BIND_SCANNED; } } @@ -144,7 +145,7 @@ timestamp( f2.f_grist.len = 0; f2.f_member.len = 0; string_truncate( buf, 0 ); - file_build( &f2, buf, 0 ); + path_build( &f2, buf, 0 ); b->name = buf->value; b->time = b->flags = 0; @@ -155,7 +156,7 @@ timestamp( if( !( b->flags & BIND_SCANNED ) ) { - file_archscan( buf->value, time_enter ); + file_archscan( buf->value, time_enter, bindhash ); b->flags |= BIND_SCANNED; } } @@ -179,11 +180,13 @@ timestamp( static void time_enter( + void *closure, char *target, int found, time_t time ) { BINDING binding, *b = &binding; + struct hash *bindhash = (struct hash *)closure; # ifdef DOWNSHIFT_PATHS char path[ MAXJPATH ];