Install sccs headers and copyright notices.
[unix-history] / usr / src / usr.bin / tn3270 / tools / mkmake.y
index eb8a765..1e27b35 100644 (file)
@@ -1,4 +1,26 @@
 %{
 %{
+
+/*
+ *     Copyright (c) 1984-1987 by the Regents of the
+ *     University of California and by Gregory Glenn Minshall.
+ *
+ *     Permission to use, copy, modify, and distribute these
+ *     programs and their documentation for any purpose and
+ *     without fee is hereby granted, provided that this
+ *     copyright and permission appear on all copies and
+ *     supporting documentation, the name of the Regents of
+ *     the University of California not be used in advertising
+ *     or publicity pertaining to distribution of the programs
+ *     without specific prior permission, and notice be given in
+ *     supporting documentation that copying and distribution is
+ *     by permission of the Regents of the University of California
+ *     and by Gregory Glenn Minshall.  Neither the Regents of the
+ *     University of California nor Gregory Glenn Minshall make
+ *     representations about the suitability of this software
+ *     for any purpose.  It is provided "as is" without
+ *     express or implied warranty.
+ */
+
 typedef struct string {
     int
        hashval,
 typedef struct string {
     int
        hashval,
@@ -9,163 +31,814 @@ typedef struct string {
        *next;
 } string_t;
 
        *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 {
 typedef struct same {
-    int
-       myname,
-       values,         /* If a variable, the values */
-       action;         /* If a target, the action number */
-    struct same
-       *moretokens,
-       *depends;
     string_t
     string_t
-       *string;
+       *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;
 
 } same_t;
 
-same_t
-    *add_depends(),
-    *assign(),
-    *token_cat(),
-    *token_item();
 %}
 
 %union {
     string_t *string;
     same_t *same;
 %}
 
 %union {
     string_t *string;
     same_t *same;
+    int        intval;
     }
 
     }
 
-%token <string> TOKEN
-%token END_OF_FILE NL
-%type <same> target assignment actions action tokens token
+%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 END_OF_FILE;
+
+makefile : lines;
 
 lines : line
     | lines line
     ;
 
 line : NL
 
 lines : line
     | lines line
     ;
 
 line : NL
-    | target NL
-    | assignment NL
-    | actions NL
+    | assignment
+    | target_action
     ;
 
     ;
 
-target : tokens ':' tokens
+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, $3);
+       $$ = add_depends($1, same_copy(null));
     }
     ;
 
     }
     ;
 
-assignment : token '=' tokens
+target1: tokens maybe_white_space ':' maybe_white_space
     {
     {
-       $$ = assign($1, $3);
+       $$ = ws_merge($1);
     }
     ;
 
 actions: action
     | actions action
     {
     }
     ;
 
 actions: action
     | actions action
     {
-       $$ = token_cat($1, $2);
+       $$ = same_cat(same_cat($1, same_copy(newline)), $2);
     }
     ;
 
     }
     ;
 
-action:        '\t' tokens
+action:        white_space command_list NL
     {
        $$ = $2;
     }
     {
        $$ = $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 : token
-    | tokens token
+    | tokens maybe_white_space token
     {
     {
-       $$ = token_cat($1, $2);
+       $$ = same_cat($1, same_cat($2, $3));
     }
     ;
     }
     ;
+
 token: TOKEN
     {
 token: TOKEN
     {
-       $$ = token_item($1);
+       $$ = 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 <stdio.h>
+#include <ctype.h>
 
 static int last_char, last_saved = 0;
 static int column = 0, lineno = 1;
 
 
 
 static int last_char, last_saved = 0;
 static int column = 0, lineno = 1;
 
 
-static string_t *strings = 0;
+static string_t
+    *strings = 0;
+
 static same_t
 static same_t
+    *shell_variables = 0,
+    *shell_special = 0,
     *variables = 0,
     *targets = 0,
     *actions = 0;
 
     *variables = 0,
     *targets = 0,
     *actions = 0;
 
+static same_t
+    *null,
+    *blank,
+    *cwd_line,
+    *newline;
+
 extern char *malloc();
 
 extern char *malloc();
 
-main()
-{
-#define        YYDEBUG
-    extern int yydebug;
+static unsigned int
+       clock = -1;
 
 
-    return yyparse();
-}
+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;
 {
 
 yyerror(s)
 char *s;
 {
-    fprintf(stderr, "line %d, column %d: %s\n", lineno, column, 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_t *
-add_depends(list1, list2)
+same_search(list, token)
 same_t
 same_t
-    *list1,
-    *list2;
+    *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_t *
-assign(variable, value)
+same_cat(list, tokens)
 same_t
 same_t
-    *variable,
-    *value;
+    *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_t *
-token_cat(tokens, token)
+same_unlink(token)
 same_t
 same_t
-    *tokens,
     *token;
     *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;
 
 {
     same_t *ptr;
 
-    if (tokens->moretokens == 0) {
-       tokens->moretokens = token;
+    if ((ptr = same_search(targets, target)) == 0) {
+       targets = same_cat(targets, target);
+       ptr = target;
     } else {
     } else {
-       for (ptr = tokens; ptr->moretokens; ptr = ptr->moretokens) {
-           ;
+       ptr->depend_list = same_cat(ptr->depend_list, target->depend_list);
+    }
+    if (actions) {
+       if (ptr->action_list) {
+           same_free(ptr->action_list);
        }
        }
-       ptr->moretokens = token;
+       ptr->action_list = same_copy(actions);
     }
     }
-    return tokens;
 }
 
 }
 
+
 same_t *
 same_t *
-token_item(string)
-string_t *string;
+add_targets_actions(target, actions)
+same_t
+    *target,
+    *actions;
 {
     same_t *ptr;
 
 {
     same_t *ptr;
 
-    if ((ptr = (same_t *)malloc(sizeof *ptr)) == 0) {
-       fprintf(stderr, "No more space for tokens!\n");
+    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);
     }
        exit(1);
     }
+    newname[0] = '$';
+    newname[1] = '{';
+    strcpy(newname+2, var_name->string->string);
+    strcat(newname, "}");
+    resolved = same_item(string_lookup(newname));
+    free(newname);
 
 
-    ptr->string = string;
-    ptr->moretokens = 0;
-    return ptr;
+    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()
 {
 int
 Getchar()
 {
@@ -187,50 +860,35 @@ Getchar()
     }
 }
 
     }
 }
 
-int
-hashof(string, length)
-char *string;
-int length;
-{
-    register int i = 0;
-
-    while (length--) {
-       i = (i<<3) + *string ^ ((i>>28)&0x7);
-    }
-    return i;
-}
 
 
-string_t *
-lookup(string)
+int
+token_type(string)
 char *string;
 {
 char *string;
 {
-    int hashval;
-    int length = strlen(string);
-    string_t *ptr;
-
-    hashval = hashof(string, length);
-
-    for (ptr = strings; ptr; ptr = ptr->next) {
-       if ((ptr->hashval == hashval) && (ptr->length == length)) {
-           if (memcmp(string, ptr->string, length) == 0) {
-               return ptr;
+    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;
     }
     }
-    if ((ptr = (string_t *)malloc(sizeof *ptr)) == 0) {
-       fprintf(stderr, "No space to add string *%s*!\n", string);
-       exit(1);
-    }
-    ptr->hashval = hashval;
-    ptr->length = length;
-    if ((ptr->string = malloc(length+1)) == 0) {
-       fprintf(stderr, "No space to add literal *%s*!\n", string);
-       exit(1);
-    }
-    memcpy(ptr->string, string, length+1);
-    ptr->next = strings;
-    strings = ptr;
-    return ptr;
+    return TOKEN;
 }
 
 
 }
 
 
@@ -240,17 +898,23 @@ yylex()
                            save(c); \
                            *bufptr = 0; \
                            bufptr = buffer; \
                            save(c); \
                            *bufptr = 0; \
                            bufptr = buffer; \
-                           yylval.string = lookup(buffer); \
-                           return TOKEN; \
+                           yylval.string = string_lookup(buffer); \
+                           return token_type(buffer); \
                        }
 #define        save(c) { last_char = c; last_saved = 1; }
                        }
 #define        save(c) { last_char = c; last_saved = 1; }
+#if    defined(YYDEBUG)
 #define        Return(c)       if (yydebug) { \
                            printf("[%d]", c); \
                            fflush(stdout); \
                        } \
 #define        Return(c)       if (yydebug) { \
                            printf("[%d]", c); \
                            fflush(stdout); \
                        } \
+                       yyval.intval = c; \
                        return c;
                        return c;
+#else  /* defined(YYDEBUG) */
+#define        Return(y,c)     { yylval.intval = c; return y; }
+#endif /* defined(YYDEBUG) */
+
 
 
-    static char buffer[100], *bufptr = buffer;
+    static char buffer[500], *bufptr = buffer;
     static int eof_found = 0;
     int c;
 
     static int eof_found = 0;
     int c;
 
@@ -260,7 +924,7 @@ yylex()
            fprintf(stderr, "End of file ignored.\n");
            exit(1);
        }
            fprintf(stderr, "End of file ignored.\n");
            exit(1);
        }
-       Return(END_OF_FILE);
+       Return(EOF,0);
     }
     while ((c = Getchar()) != EOF) {
        switch (c) {
     }
     while ((c = Getchar()) != EOF) {
        switch (c) {
@@ -271,28 +935,61 @@ yylex()
            }
            save(c);
            break;
            }
            save(c);
            break;
-       case ' ':
-           ret_token(' ');
-           break;
+       case '<':
+       case '?':
+           ret_token(c);
+           Return(MACRO_CHAR, c);
        case '\t':
        case '\t':
+       case ' ':
            ret_token(c);
            ret_token(c);
-           if (column == 1) {
-               Return(c);
-           }
-           break;
+           Return(WHITE_SPACE, c);
+       case '-':
+       case '@':
        case ':':
        case ':':
+       case ';':
        case '=':
        case '=':
+       case '$':
+       case '{':
+       case '}':
+       case '(':
+       case ')':
            ret_token(c);
            ret_token(c);
-           Return(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--;
        case '\n':
            if (bufptr != buffer) {
                if (bufptr[-1] == '\\') {
                    bufptr--;
-                   break;
+                   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);
                }
            }
            ret_token(c);
-           Return(NL);
+           Return(NL, 0);
        default:
            *bufptr++ = c;
            break;
        default:
            *bufptr++ = c;
            break;
@@ -302,5 +999,83 @@ yylex()
     eof_found = 1;
 
     ret_token(' ');
     eof_found = 1;
 
     ret_token(' ');
-    Return(END_OF_FILE);
+    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();
 }
 }