* Copyright (c) 1988 Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* @(#)mkmake.y 1.19 (Berkeley) %G%
* The deal with these is that they exist on various lists.
* First off, they are on a temporary list during the time they
* are in the active focus of the parser.
* Secondly, they live on one of three queues:
* (and, we restrict any given one to live on one and only one such list)
* Also, they may live on the list of values for someone else's variable,
* or as someone's dependancy.
*nexttoken, /* Next pointer */
*lasttoken, /* Back pointer */
*depend_list, /* If target, dependancies */
*action_list, /* If target, actions */
*value_list, /* If variable, value list */
*shell_item; /* If a shell variable, current value */
%token <string> TOKEN QUOTED_STRING
%token <intval> FOR IN DO DONE
%token <intval> MACRO_CHAR NL WHITE_SPACE
%token <intval> ':' '=' '$' '{' '}' ';' '-' '@' '(' ')' ' ' '\t'
%type <same> target target1 assignment assign1 actions action
%type <same> command_list list list_element
%type <same> for_statement maybe_at_minus tokens token
%type <same> maybe_white_space
%type <intval> white_space macro_char
assignment : assign1 tokens NL
assign($1, same_copy(null));
assign1: token maybe_white_space '=' maybe_white_space
target_action: target actions
add_targets_actions($1, $2);
add_targets_actions($1, 0);
target : target1 tokens NL
$$ = add_depends($1, $2);
$$ = add_depends($1, same_copy(null));
target1: tokens maybe_white_space ':' maybe_white_space
$$ = same_cat(same_cat($1, same_copy(newline)), $2);
action: white_space command_list NL
| white_space for_statement do command_list semi_colon done NL
for_statement: maybe_at_minus FOR white_space token
$$ = for_statement($1, $4, ws_merge(expand_variables($6, 0)));
in: white_space IN white_space
do: white_space DO white_space
| '(' list maybe_white_space ')'
$$ = same_cat($2, same_copy(cwd_line));
| list white_space list_element
$$ = same_cat($1, same_cat(same_copy(blank), $3));
maybe_at_minus: /* empty */
$$ = same_item(string_lookup(buffer));
$$ = same_item(string_lookup(buffer));
| tokens maybe_white_space token
$$ = same_cat($1, same_cat($2, $3));
$$ = same_item(string_lookup(buffer));
$$ = shell_variable(same_item($3));
$$ = variable(same_item($3));
$$ = variable(same_item($3));
$$ = variable(same_item($2));
white_space : WHITE_SPACE
| white_space WHITE_SPACE
static int last_char, last_saved = 0;
static int column = 0, lineno = 1;
} visit_stack[20]; /* 20 maximum */
#define visit(what,via) \
(visit_stack[++clock].next = 0, visit_stack[clock].first = via = what)
#define visited(via) (visitcheck(via) || ((via) == 0) \
|| (visit_stack[clock].next && (via == visit_stack[clock].first)))
#define visit_next(via) (visit_stack[clock].next = 1, (via) = (via)->nexttoken)
#define visit_end() (clock--)
fprintf(stderr, "line %d, character %d: %s\n", lineno, column, s);
yyerror("BUG - freed 'same' in use...");
string_hashof(string, length)
i = (i<<3) + *string ^ ((i>>28)&0x7);
if ((s1->hashval == s2->hashval) && (s1->length == s2->length)
&& (memcmp(s1->string, s2->string, s1->length) == 0)) {
ours.length = strlen(string);
ours.hashval = string_hashof(string, ours.length);
for (ptr = strings; ptr; ptr = ptr->next) {
if (string_same(&ours, ptr)) {
if ((ptr = (string_t *)malloc(sizeof *ptr)) == 0) {
fprintf(stderr, "No space to add string *%s*!\n", string);
ptr->hashval = ours.hashval;
ptr->length = ours.length;
if ((ptr->string = malloc(ours.length+1)) == 0) {
fprintf(stderr, "No space to add literal *%s*!\n", string);
memcpy(ptr->string, string, ours.length+1);
#define same_singleton(s) ((s)->nexttoken == (s))
for (visit(list, ptr); !visited(ptr); visit_next(ptr)) {
if (string_same(string, token->string)) {
last = tokens->lasttoken;
tokens->lasttoken = list->lasttoken;
tokens->lasttoken->nexttoken = tokens;
if ((ptr = (same_t *)malloc(sizeof *ptr)) == 0) {
fprintf(stderr, "No more space for tokens!\n");
memset((char *)ptr, 0, sizeof *ptr);
ptr->nexttoken = ptr->lasttoken = ptr;
for (visit(same, copy); !visited(copy); visit_next(copy)) {
ptr = same_item(copy->string);
head = same_cat(head, ptr);
if (same_singleton(t1) && same_singleton(t2)) {
int length = strlen(t1->string->string)+strlen(t2->string->string);
char *buffer = malloc(length+1);
yyerror("No space to merge strings in same_merge!");
strcpy(buffer, t1->string->string);
strcat(buffer, t2->string->string);
value = same_item(string_lookup(buffer));
yyerror("Internal error - same_merge with non-singletons");
(void) free((char *)token);
if ((tmp = token->nexttoken) == token) {
token->lasttoken->nexttoken = token->nexttoken;
token->nexttoken->lasttoken = token->lasttoken;
token->nexttoken = token->lasttoken = token;
new->lasttoken->nexttoken = old->nexttoken;
old->nexttoken->lasttoken = new->lasttoken;
new->lasttoken = old->lasttoken;
* old->lasttoken->nexttoken = new
* we update in place (for the case where there isn't anything else)
return same_item(string_lookup(buffer));
add_target(target, actions)
if ((ptr = same_search(targets, target)) == 0) {
targets = same_cat(targets, target);
ptr->depend_list = same_cat(ptr->depend_list, target->depend_list);
same_free(ptr->action_list);
ptr->action_list = same_copy(actions);
add_targets_actions(target, actions)
ptr = same_unlink(target);
add_target(target, actions);
add_depends(target, depends)
same_t *original = target;
depends = same_cat(depends, same_copy(blank)); /* Separator */
for (visit(original, target); !visited(target); visit_next(target)) {
target->depend_list = same_cat(target->depend_list, same_copy(depends));
* We know that variable is a singleton
if ((ptr = same_search(variables, variable)) != 0) {
same_free(ptr->value_list);
variables = same_unlink(ptr);
variable->value_list = value;
variables = same_cat(variables, variable);
same_t *ptr = same_search(variables, variable);
return same_copy(ptr->value_list);
expand_variables(token, free)
token = same_copy(token); /* Get our private copy */
char *string = token->string->string;
same_t *tmp = same_unlink(token);
if ((string[0] == '$') && (string[1] == '{')) { /* Expand time */
int len = strlen(string);
head = same_cat(head, expand_variables(
value_of(same_item(string_lookup(string+2))), 1));
head = same_cat(head, token);
same_t *newlist = 0, *item;
if (isspace(list->string->string[0])) {
item = same_item(list->string);
if (isspace(list->string->string[0])) {
newlist = same_cat(newlist, item);
item = same_merge(item, same_item(list->string));
list = same_unlink(list);
return same_cat(newlist, item);
int length = strlen(var_name->string->string);
if ((newname = malloc(length+1+3)) == 0) {
fprintf("Out of space for a variable name.\n");
strcpy(newname+2, var_name->string->string);
resolved = same_item(string_lookup(newname));
int length = strlen(var_name->string->string);
if ((newname = malloc(length+1+2)) == 0) {
fprintf("Out of space for a variable name.\n");
strcpy(newname+2, var_name->string->string);
resolved = same_item(string_lookup(newname));
for_statement(special, variable, list)
variable->shell_item = special;
variable->value_list = list;
do_command(forlist, commands)
*value_list = forlist->value_list;
*variable_name = forlist->string->string;
special = forlist->shell_item;
if (same_unlink(forlist->shell_item) != 0) {
yyerror("Unexpected second item in special part of do_command");
while ((shell_item = value_list) != 0) {
value_list = same_unlink(shell_item);
/* Visit each item in commands. For each shell variable which
* matches ours, replace it with ours.
new_commands = same_copy(commands);
for (visit(new_commands, tmp); !visited(tmp); visit_next(tmp)) {
tmpstr = tmp->string->string;
if ((tmpstr[0] == '$') && (tmpstr[1] == '$')) {
if (strcmp(tmpstr+2, variable_name) == 0) {
same_replace(tmp, same_copy(shell_item));
command_list = same_cat(command_list, new_commands);
return same_cat(command_list, same_copy(newline));
if (strcmp(string, "for") == 0) {
if (strcmp(string, "do") == 0) {
} else if (strcmp(string, "done") == 0) {
if (strcmp(string, "in") == 0) {
#define ret_token(c) if (bufptr != buffer) { \
yylval.string = string_lookup(buffer); \
return token_type(buffer); \
#define save(c) { last_char = c; last_saved = 1; }
#define Return(c) if (yydebug) { \
#else /* defined(YYDEBUG) */
#define Return(y,c) { yylval.intval = c; return y; }
#endif /* defined(YYDEBUG) */
static char buffer[500], *bufptr = buffer;
static int eof_found = 0;
fprintf(stderr, "End of file ignored.\n");
while ((c = Getchar()) != EOF) {
while (((c = Getchar()) != EOF) && (c != '\n')) {
if (bufptr[-1] == '\\') {
while (((newc = Getchar()) != EOF) && (newc != c)) {
yylval.string = string_lookup(buffer);
if (bufptr[-1] == '\\') {
if ((c = Getchar()) != '\t') {
yyerror("continuation line doesn't begin with a tab");
static char sccsid[] = "@(#)mkmake.y 1.19 (Berkeley) %G%";
null = same_item(string_lookup(""));
newline = same_item(string_lookup("\n"));
blank = same_item(string_lookup(" "));
cwd_line = same_cat(same_copy(newline),
same_cat(same_item(string_lookup("cd ${CWD}")),
for (visit(same, same2); !visited(same2); visit_next(same2)) {
printf(same2->string->string);
for (string = strings; string; string = string->next) {
printf("\t%s\n", string->string);
printf("# variables...\n");
for (visit(variables, same); !visited(same); visit_next(same)) {
printf("%s =\t", same->string->string);
for (visit(same->value_list, same2); !visited(same2);
printf(same2->string->string);
printf("\n\n#targets...\n");
for (visit(targets, same); !visited(same); visit_next(same)) {
printf("\n%s:\t", same->string->string);
for (visit(same->depend_list, same2); !visited(same2);
printf(same2->string->string);
for (visit(same->action_list, same2); !visited(same2);
printf(same2->string->string);
if (same2->string->string[0] == '\n') {