rc

[fork] interactive rc shell
git clone https://hhvn.uk/rc
git clone git://hhvn.uk/rc
Log | Files | Refs | README | LICENSE

tree.c (5863B)


      1 /* tree.c: functions for manipulating parse-trees. (create, copy, delete) */
      2 
      3 #include "rc.h"
      4 
      5 #include "develop.h"
      6 
      7 /* convert if followed by ifnot to else */
      8 static Node *desugar_ifnot(Node *n) {
      9 	if (n->type == nBody && n->u[1].p && n->u[1].p->type == nIfnot) {
     10 		/* (body (if c x) (if-not y)) => (body (if c (else x y))) */
     11 		if (n->u[0].p->type == nIf &&
     12 				n->u[0].p->u[1].p->type != nElse) {
     13 			Node *yes = n->u[0].p;
     14 			Node *no = n->u[1].p;
     15 			Node *els = nalloc(offsetof(Node, u[2]));
     16 			els->type = nElse;
     17 			els->u[1].p = no->u[0].p;
     18 			els->u[0].p = yes->u[1].p;
     19 			yes->u[1].p = els;
     20 			n->u[1].p = NULL;
     21 		} else goto fail;
     22 	} else if (n->type == nBody &&
     23 			n->u[1].p && n->u[1].p->type == nBody &&
     24 			n->u[1].p->u[0].p &&
     25 				n->u[1].p->u[0].p->type == nIfnot) {
     26 		/* (body (if c x) (body (if-not y) z)) =>
     27 			(body (if c (else x y)) z) */
     28 		if (n->u[0].p->type == nIf &&
     29 				n->u[0].p->u[1].p->type != nElse) {
     30 			Node *yes = n->u[0].p;
     31 			Node *no = n->u[1].p->u[0].p;
     32 			Node *els = nalloc(offsetof(Node, u[2]));
     33 			els->type = nElse;
     34 			els->u[1].p = no->u[0].p;
     35 			els->u[0].p = yes->u[1].p;
     36 			yes->u[1].p = els;
     37 			n->u[1].p = n->u[1].p->u[1].p;
     38 		} else goto fail;
     39 	}
     40 
     41 	return n;
     42 fail:
     43 	rc_error("`if not' must follow `if'");
     44 	return NULL;
     45 }
     46 
     47 /* make a new node, pass it back to yyparse. Used to generate the parsetree. */
     48 
     49 extern Node *mk(enum nodetype t,...) {
     50 	va_list ap;
     51 	Node *n;
     52 	va_start(ap, t);
     53 	switch (t) {
     54 	default:
     55 		panic("unexpected node in mk");
     56 		/* NOTREACHED */
     57 	case nDup:
     58 		n = nalloc(offsetof(Node, u[3]));
     59 		n->u[0].i = va_arg(ap, int);
     60 		n->u[1].i = va_arg(ap, int);
     61 		n->u[2].i = va_arg(ap, int);
     62 		break;
     63 	case nWord:
     64 		n = nalloc(offsetof(Node, u[3]));
     65 		n->u[0].s = va_arg(ap, char *);
     66 		n->u[1].s = va_arg(ap, char *);
     67 		n->u[2].i = va_arg(ap, int);
     68 		break;
     69 	case nBang: case nNowait:
     70 	case nCount: case nFlat: case nRmfn: case nSubshell:
     71 	case nVar: case nCase: case nIfnot:
     72 		n = nalloc(offsetof(Node, u[1]));
     73 		n->u[0].p = va_arg(ap, Node *);
     74 		break;
     75 	case nAndalso: case nAssign: case nBackq: case nBody: case nBrace: case nConcat:
     76 	case nElse: case nEpilog: case nIf: case nNewfn: case nCbody:
     77 	case nOrelse: case nPre: case nArgs: case nSwitch:
     78 	case nMatch: case nVarsub: case nWhile: case nLappend:
     79 		n = nalloc(offsetof(Node, u[2]));
     80 		n->u[0].p = va_arg(ap, Node *);
     81 		n->u[1].p = va_arg(ap, Node *);
     82 		break;
     83 	case nForin:
     84 		n = nalloc(offsetof(Node, u[3]));
     85 		n->u[0].p = va_arg(ap, Node *);
     86 		n->u[1].p = va_arg(ap, Node *);
     87 		n->u[2].p = va_arg(ap, Node *);
     88 		break;
     89 	case nPipe:
     90 		n = nalloc(offsetof(Node, u[4]));
     91 		n->u[0].i = va_arg(ap, int);
     92 		n->u[1].i = va_arg(ap, int);
     93 		n->u[2].p = va_arg(ap, Node *);
     94 		n->u[3].p = va_arg(ap, Node *);
     95 		break;
     96 	case nRedir:
     97 	case nNmpipe:
     98 		n = nalloc(offsetof(Node, u[3]));
     99 		n->u[0].i = va_arg(ap, int);
    100 		n->u[1].i = va_arg(ap, int);
    101 		n->u[2].p = va_arg(ap, Node *);
    102 		break;
    103 	}
    104 	n->type = t;
    105 
    106 	if (0 && RC_DEVELOP) {
    107 		tree_dump(n);
    108 		fprint(2, "---\n");
    109 	}
    110 	n = desugar_ifnot(n);
    111 	va_end(ap);
    112 	return n;
    113 }
    114 
    115 /* copy a tree to malloc space. Used when storing the definition of a function */
    116 
    117 extern Node *treecpy(Node *s, void *(*alloc)(size_t)) {
    118 	Node *n;
    119 	if (s == NULL)
    120 		return NULL;
    121 	switch (s->type) {
    122 	default:
    123 		panic("unexpected node in treecpy");
    124 		/* NOTREACHED */
    125 	case nDup:
    126 		n = (*alloc)(offsetof(Node, u[3]));
    127 		n->u[0].i = s->u[0].i;
    128 		n->u[1].i = s->u[1].i;
    129 		n->u[2].i = s->u[2].i;
    130 		break;
    131 	case nWord:
    132 		n = (*alloc)(offsetof(Node, u[3]));
    133 		n->u[0].s = strcpy((char *) (*alloc)(strlen(s->u[0].s) + 1), s->u[0].s);
    134 		if (s->u[1].s != NULL) {
    135 			size_t i = strlen(s->u[0].s);
    136 			n->u[1].s = (*alloc)(i);
    137 			memcpy(n->u[1].s, s->u[1].s, i);
    138 		} else
    139 			n->u[1].s = NULL;
    140 		n->u[2].i = s->u[2].i;
    141 		break;
    142 	case nBang: case nNowait: case nCase:
    143 	case nCount: case nFlat: case nRmfn: case nSubshell: case nVar:
    144 		n = (*alloc)(offsetof(Node, u[1]));
    145 		n->u[0].p = treecpy(s->u[0].p, alloc);
    146 		break;
    147 	case nAndalso: case nAssign: case nBackq: case nBody: case nBrace: case nConcat:
    148 	case nElse: case nEpilog: case nIf: case nNewfn: case nCbody:
    149 	case nOrelse: case nPre: case nArgs: case nSwitch:
    150 	case nMatch: case nVarsub: case nWhile: case nLappend:
    151 		n = (*alloc)(offsetof(Node, u[2]));
    152 		n->u[0].p = treecpy(s->u[0].p, alloc);
    153 		n->u[1].p = treecpy(s->u[1].p, alloc);
    154 		break;
    155 	case nForin:
    156 		n = (*alloc)(offsetof(Node, u[3]));
    157 		n->u[0].p = treecpy(s->u[0].p, alloc);
    158 		n->u[1].p = treecpy(s->u[1].p, alloc);
    159 		n->u[2].p = treecpy(s->u[2].p, alloc);
    160 		break;
    161 	case nPipe:
    162 		n = (*alloc)(offsetof(Node, u[4]));
    163 		n->u[0].i = s->u[0].i;
    164 		n->u[1].i = s->u[1].i;
    165 		n->u[2].p = treecpy(s->u[2].p, alloc);
    166 		n->u[3].p = treecpy(s->u[3].p, alloc);
    167 		break;
    168 	case nRedir:
    169 	case nNmpipe:
    170 		n = (*alloc)(offsetof(Node, u[3]));
    171 		n->u[0].i = s->u[0].i;
    172 		n->u[1].i = s->u[1].i;
    173 		n->u[2].p = treecpy(s->u[2].p, alloc);
    174 		break;
    175 	}
    176 	n->type = s->type;
    177 	return n;
    178 }
    179 
    180 /* free a function definition that is no longer needed */
    181 
    182 extern void treefree(Node *s) {
    183 	if (s == NULL)
    184 		return;
    185 	switch (s->type) {
    186 	default:
    187 		panic("unexpected node in treefree");
    188 		/* NOTREACHED */
    189 	case nDup:
    190 		break;
    191 	case nWord:
    192 		efree(s->u[0].s);
    193 		efree(s->u[1].s);
    194 		break;
    195 	case nBang: case nNowait:
    196 	case nCount: case nFlat: case nRmfn:
    197 	case nSubshell: case nVar: case nCase:
    198 		treefree(s->u[0].p);
    199 		break;
    200 	case nAndalso: case nAssign: case nBackq: case nBody: case nBrace: case nConcat:
    201 	case nElse: case nEpilog: case nIf: case nNewfn:
    202 	case nOrelse: case nPre: case nArgs: case nCbody:
    203 	case nSwitch: case nMatch:  case nVarsub: case nWhile:
    204 	case nLappend:
    205 		treefree(s->u[1].p);
    206 		treefree(s->u[0].p);
    207 		break;
    208 	case nForin:
    209 		treefree(s->u[2].p);
    210 		treefree(s->u[1].p);
    211 		treefree(s->u[0].p);
    212 		break;
    213 	case nPipe:
    214 		treefree(s->u[2].p);
    215 		treefree(s->u[3].p);
    216 		break;
    217 	case nRedir:
    218 	case nNmpipe:
    219 		treefree(s->u[2].p);
    220 	}
    221 	efree(s);
    222 }