NetBSD/usr.bin/tn3270/tools/mkmake.y
1993-08-01 17:54:45 +00:00

1099 lines
20 KiB
Plaintext

%{
/*-
* Copyright (c) 1988 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
/*static char sccsid[] = "from: @(#)mkmake.y 4.2 (Berkeley) 4/26/91";*/
static char rcsid[] = "$Id: mkmake.y,v 1.2 1993/08/01 18:04:51 mycroft Exp $";
#endif /* not lint */
typedef struct string {
int
hashval,
length;
char
*string;
struct string
*next;
} string_t;
/*
* 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:
* 1. Variables
* 2. Targets
* 3. Actions
* (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.
*/
typedef struct same {
string_t
*string; /* My name */
struct same
*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 */
} same_t;
%}
%union {
string_t *string;
same_t *same;
int intval;
}
%start makefile
%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
%%
makefile : lines;
lines : line
| lines line
;
line : NL
| assignment
| target_action
;
assignment : assign1 tokens NL
{
assign($1, $2);
}
| assign1 NL
{
assign($1, same_copy(null));
}
;
assign1: token maybe_white_space '=' maybe_white_space
;
target_action: target actions
{
add_targets_actions($1, $2);
}
| target
{
add_targets_actions($1, 0);
}
;
target : target1 tokens NL
{
$$ = add_depends($1, $2);
}
| target1 NL
{
$$ = add_depends($1, same_copy(null));
}
;
target1: tokens maybe_white_space ':' maybe_white_space
{
$$ = ws_merge($1);
}
;
actions: action
| actions action
{
$$ = same_cat(same_cat($1, same_copy(newline)), $2);
}
;
action: white_space command_list NL
{
$$ = $2;
}
| white_space for_statement do command_list semi_colon done NL
{
$$ = do_command($2, $4);
}
;
for_statement: maybe_at_minus FOR white_space token
in tokens semi_colon
{
$$ = for_statement($1, $4, ws_merge(expand_variables($6, 0)));
}
;
in: white_space IN white_space
do: white_space DO white_space
;
done: white_space DONE
;
semi_colon: ';'
;
command_list: list
| '(' list maybe_white_space ')'
{
$$ = same_cat($2, same_copy(cwd_line));
}
;
list: token
| list list_element
{
$$ = same_cat($1, $2);
}
| list white_space list_element
{
$$ = same_cat($1, same_cat(same_copy(blank), $3));
}
;
list_element: token
| semi_colon
{
$$ = same_copy(newline);
}
;
maybe_at_minus: /* empty */
{
$$ = same_copy(null);
}
| '@'
{
char buffer[2];
buffer[0] = $1;
buffer[1] = 0;
$$ = same_item(string_lookup(buffer));
}
| '-'
{
char buffer[2];
buffer[0] = $1;
buffer[1] = 0;
$$ = same_item(string_lookup(buffer));
}
;
tokens : token
| tokens maybe_white_space token
{
$$ = same_cat($1, same_cat($2, $3));
}
;
token: TOKEN
{
$$ = same_item($1);
}
| QUOTED_STRING
{
$$ = same_item($1);
}
| '$' macro_char
{
char buffer[3];
buffer[0] = '$';
buffer[1] = $2;
buffer[2] = 0;
$$ = same_item(string_lookup(buffer));
}
| '$' '$' TOKEN
{
$$ = shell_variable(same_item($3));
}
| MACRO_CHAR
{
$$ = same_char($1);
}
| '$' '{' TOKEN '}'
{
$$ = variable(same_item($3));
}
| '$' '(' TOKEN ')'
{
$$ = variable(same_item($3));
}
| '$' TOKEN
{
$$ = variable(same_item($2));
}
| '-'
{
$$ = same_char('-');
}
| '@'
{
$$ = same_char('@');
}
;
macro_char: MACRO_CHAR
| '@'
;
maybe_white_space:
{
$$ = same_copy(null);
}
| white_space
{
$$ = same_char($1);
}
;
white_space : WHITE_SPACE
| white_space WHITE_SPACE
;
%%
#include <stdio.h>
#include <ctype.h>
static int last_char, last_saved = 0;
static int column = 0, lineno = 1;
static string_t
*strings = 0;
static same_t
*shell_variables = 0,
*shell_special = 0,
*variables = 0,
*targets = 0,
*actions = 0;
static same_t
*null,
*blank,
*cwd_line,
*newline;
extern char *malloc();
static unsigned int
clock = -1;
struct {
same_t *first;
int next;
} 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--)
yyerror(s)
char *s;
{
fprintf(stderr, "line %d, character %d: %s\n", lineno, column, s);
do_dump();
}
int
visitcheck(same)
same_t *same;
{
if (same->string == 0) {
yyerror("BUG - freed 'same' in use...");
exit(1);
}
return 0;
}
int
string_hashof(string, length)
char *string;
int length;
{
register int i = 0;
while (length--) {
i = (i<<3) + *string ^ ((i>>28)&0x7);
}
return i;
}
int
string_same(s1, s2)
string_t
*s1, *s2;
{
if ((s1->hashval == s2->hashval) && (s1->length == s2->length)
&& (memcmp(s1->string, s2->string, s1->length) == 0)) {
return 1;
} else {
return 0;
}
}
string_t *
string_lookup(string)
char *string;
{
string_t ours;
string_t *ptr;
ours.length = strlen(string);
ours.hashval = string_hashof(string, ours.length);
ours.string = string;
for (ptr = strings; ptr; ptr = ptr->next) {
if (string_same(&ours, ptr)) {
return ptr;
}
}
if ((ptr = (string_t *)malloc(sizeof *ptr)) == 0) {
fprintf(stderr, "No space to add string *%s*!\n", string);
exit(1);
}
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);
exit(1);
}
memcpy(ptr->string, string, ours.length+1);
ptr->next = strings;
strings = ptr;
return ptr;
}
#define same_singleton(s) ((s)->nexttoken == (s))
same_t *
same_search(list, token)
same_t
*list,
*token;
{
same_t *ptr;
ptr = list;
for (visit(list, ptr); !visited(ptr); visit_next(ptr)) {
string_t *string;
string = ptr->string;
if (string_same(string, token->string)) {
visit_end();
return ptr;
}
}
visit_end();
return 0;
}
same_t *
same_cat(list, tokens)
same_t
*list,
*tokens;
{
same_t *last;
if (tokens == 0) {
return list;
}
if (list) {
last = tokens->lasttoken;
tokens->lasttoken = list->lasttoken;
list->lasttoken = last;
tokens->lasttoken->nexttoken = tokens;
last->nexttoken = list;
return list;
} else {
return tokens;
}
}
same_t *
same_item(string)
string_t *string;
{
same_t *ptr;
if ((ptr = (same_t *)malloc(sizeof *ptr)) == 0) {
fprintf(stderr, "No more space for tokens!\n");
exit(1);
}
memset((char *)ptr, 0, sizeof *ptr);
ptr->nexttoken = ptr->lasttoken = ptr;
ptr->string = string;
return ptr;
}
same_t *
same_copy(same)
same_t *same;
{
same_t *head, *copy;
head = 0;
for (visit(same, copy); !visited(copy); visit_next(copy)) {
same_t *ptr;
ptr = same_item(copy->string);
head = same_cat(head, ptr);
}
visit_end();
return head;
}
same_t *
same_merge(t1, t2)
same_t
*t1,
*t2;
{
if (same_singleton(t1) && same_singleton(t2)) {
int length = strlen(t1->string->string)+strlen(t2->string->string);
char *buffer = malloc(length+1);
same_t *value;
if (buffer == 0) {
yyerror("No space to merge strings in same_merge!");
exit(1);
}
strcpy(buffer, t1->string->string);
strcat(buffer, t2->string->string);
value = same_item(string_lookup(buffer));
free(buffer);
return value;
} else {
yyerror("Internal error - same_merge with non-singletons");
exit(1);
}
}
void
same_free(list)
same_t *list;
{
same_t *token, *ptr;
if (list == 0) {
return;
}
token = list;
do {
ptr = token->nexttoken;
token->string = 0;
(void) free((char *)token);
token = ptr;
} while (token != list);
}
same_t *
same_unlink(token)
same_t
*token;
{
same_t *tmp;
if (token == 0) {
return 0;
}
if ((tmp = token->nexttoken) == token) {
tmp = 0;
}
token->lasttoken->nexttoken = token->nexttoken;
token->nexttoken->lasttoken = token->lasttoken;
token->nexttoken = token->lasttoken = token;
return tmp;
}
void
same_replace(old, new)
same_t
*old,
*new;
{
new->lasttoken->nexttoken = old->nexttoken;
old->nexttoken->lasttoken = new->lasttoken;
new->lasttoken = old->lasttoken;
/* rather than
* old->lasttoken->nexttoken = new
* we update in place (for the case where there isn't anything else)
*/
*old = *new;
}
same_t *
same_char(ch)
char ch;
{
char buffer[2];
buffer[0] = ch;
buffer[1] = 0;
return same_item(string_lookup(buffer));
}
void
add_target(target, actions)
same_t
*target,
*actions;
{
same_t *ptr;
if ((ptr = same_search(targets, target)) == 0) {
targets = same_cat(targets, target);
ptr = target;
} else {
ptr->depend_list = same_cat(ptr->depend_list, target->depend_list);
}
if (actions) {
if (ptr->action_list) {
same_free(ptr->action_list);
}
ptr->action_list = same_copy(actions);
}
}
same_t *
add_targets_actions(target, actions)
same_t
*target,
*actions;
{
same_t *ptr;
if (target == 0) {
return 0;
}
do {
ptr = same_unlink(target);
add_target(target, actions);
target = ptr;
} while (target);
same_free(actions);
return 0;
}
same_t *
add_depends(target, depends)
same_t
*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));
}
visit_end();
same_free(depends);
return original;
}
/*
* We know that variable is a singleton
*/
void
assign(variable, value)
same_t
*variable,
*value;
{
same_t *ptr;
if ((ptr = same_search(variables, variable)) != 0) {
same_free(ptr->value_list);
variables = same_unlink(ptr);
same_free(ptr);
}
variable->value_list = value;
variables = same_cat(variables, variable);
}
same_t *
value_of(variable)
same_t *variable;
{
same_t *ptr = same_search(variables, variable);
if (ptr == 0) {
return same_copy(null);
} else {
return same_copy(ptr->value_list);
}
}
same_t *
expand_variables(token, free)
same_t *token;
int free;
{
same_t *head = 0;
if (!free) {
token = same_copy(token); /* Get our private copy */
}
while (token) {
char *string = token->string->string;
same_t *tmp = same_unlink(token);
if ((string[0] == '$') && (string[1] == '{')) { /* Expand time */
int len = strlen(string);
string[len-1] = 0;
head = same_cat(head, expand_variables(
value_of(same_item(string_lookup(string+2))), 1));
string[len-1] = '}';
} else {
head = same_cat(head, token);
}
token = tmp;
}
return head;
}
same_t *
ws_merge(list)
same_t *list;
{
same_t *newlist = 0, *item;
int what = 0;
while (list) {
switch (what) {
case 0:
if (isspace(list->string->string[0])) {
;
} else {
item = same_item(list->string);
what = 1;
}
break;
case 1:
if (isspace(list->string->string[0])) {
newlist = same_cat(newlist, item);
item = 0;
what = 0;
} else {
item = same_merge(item, same_item(list->string));
what = 1;
}
break;
}
list = same_unlink(list);
}
return same_cat(newlist, item);
}
same_t *
variable(var_name)
same_t *var_name;
{
int length = strlen(var_name->string->string);
same_t *resolved;
char *newname;
if ((newname = malloc(length+1+3)) == 0) {
fprintf("Out of space for a variable name.\n");
exit(1);
}
newname[0] = '$';
newname[1] = '{';
strcpy(newname+2, var_name->string->string);
strcat(newname, "}");
resolved = same_item(string_lookup(newname));
free(newname);
return resolved;
}
same_t *
shell_variable(var_name)
same_t *var_name;
{
int length = strlen(var_name->string->string);
same_t *resolved;
char *newname;
if ((newname = malloc(length+1+2)) == 0) {
fprintf("Out of space for a variable name.\n");
exit(1);
}
newname[0] = '$';
newname[1] = '$';
strcpy(newname+2, var_name->string->string);
resolved = same_item(string_lookup(newname));
free(newname);
return resolved;
}
same_t *
for_statement(special, variable, list)
same_t
*special,
*variable,
*list;
{
variable->shell_item = special;
variable->value_list = list;
return variable;
}
same_t *
do_command(forlist, commands)
same_t
*forlist,
*commands;
{
same_t
*special,
*command_list = 0,
*new_commands,
*tmp,
*shell_item,
*value_list = forlist->value_list;
char
*tmpstr,
*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");
exit(1);
}
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));
}
}
}
visit_end();
command_list = same_cat(command_list, new_commands);
}
return same_cat(command_list, same_copy(newline));
}
int
Getchar()
{
if (last_saved) {
last_saved = 0;
return last_char;
} else {
int c;
c = getchar();
switch (c) {
case '\n':
lineno++;
column = 0;
break;
default:
column++;
}
return c;
}
}
int
token_type(string)
char *string;
{
switch (string[0]) {
case 'f':
if (strcmp(string, "for") == 0) {
return FOR;
}
break;
case 'd':
if (string[1] == 'o') {
if (strcmp(string, "do") == 0) {
return DO;
} else if (strcmp(string, "done") == 0) {
return DONE;
}
}
break;
case 'i':
if (strcmp(string, "in") == 0) {
return IN;
}
break;
default:
break;
}
return TOKEN;
}
yylex()
{
#define ret_token(c) if (bufptr != buffer) { \
save(c); \
*bufptr = 0; \
bufptr = buffer; \
yylval.string = string_lookup(buffer); \
return token_type(buffer); \
}
#define save(c) { last_char = c; last_saved = 1; }
#if defined(YYDEBUG)
#define Return(c) if (yydebug) { \
printf("[%d]", c); \
fflush(stdout); \
} \
yyval.intval = c; \
return c;
#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;
int c;
if (eof_found != 0) {
eof_found++;
if (eof_found > 2) {
fprintf(stderr, "End of file ignored.\n");
exit(1);
}
Return(EOF,0);
}
while ((c = Getchar()) != EOF) {
switch (c) {
case '#':
ret_token(c);
while (((c = Getchar()) != EOF) && (c != '\n')) {
;
}
save(c);
break;
case '<':
case '?':
ret_token(c);
Return(MACRO_CHAR, c);
case '\t':
case ' ':
ret_token(c);
Return(WHITE_SPACE, c);
case '-':
case '@':
case ':':
case ';':
case '=':
case '$':
case '{':
case '}':
case '(':
case ')':
ret_token(c);
Return(c,c);
case '\'':
case '"':
if (bufptr != buffer) {
if (bufptr[-1] == '\\') {
bufptr[-1] = c;
}
break;
} else {
int newc;
ret_token(c);
*bufptr++ = c;
while (((newc = Getchar()) != EOF) && (newc != c)) {
*bufptr++ = newc;
}
*bufptr++ = c;
*bufptr = 0;
bufptr = buffer;
yylval.string = string_lookup(buffer);
return QUOTED_STRING;
}
case '\n':
if (bufptr != buffer) {
if (bufptr[-1] == '\\') {
bufptr--;
if ((c = Getchar()) != '\t') {
yyerror("continuation line doesn't begin with a tab");
save(c);
}
ret_token(c);
Return(WHITE_SPACE, c);
}
}
ret_token(c);
Return(NL, 0);
default:
*bufptr++ = c;
break;
}
}
eof_found = 1;
ret_token(' ');
Return(EOF, 0);
}
main()
{
#define YYDEBUG
extern int yydebug;
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}")),
same_copy(newline)));
yyparse();
do_dump();
return 0;
}
#if defined(YYDEBUG)
dump_same(same)
same_t *same;
{
same_t *same2;
for (visit(same, same2); !visited(same2); visit_next(same2)) {
printf(same2->string->string);
}
visit_end();
}
#endif /* YYDEBUG */
do_dump()
{
string_t *string;
same_t *same, *same2;
if (yydebug > 1) {
printf("strings...\n");
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);
visit_next(same2)) {
printf(same2->string->string);
}
visit_end();
printf("\n");
}
visit_end();
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);
visit_next(same2)) {
printf(same2->string->string);
}
visit_end();
printf("\n\t");
for (visit(same->action_list, same2); !visited(same2);
visit_next(same2)) {
printf(same2->string->string);
if (same2->string->string[0] == '\n') {
printf("\t");
}
}
visit_end();
printf("\n");
}
visit_end();
}