tree.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. /*
  2. ** tree.c
  3. ** TecCGraf - PUC-Rio
  4. */
  5. char *rcs_tree="$Id: $";
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include "lua.h"
  9. #include "tree.h"
  10. #define lua_strcmp(a,b) (a[0]<b[0]?(-1):(a[0]>b[0]?(1):strcmp(a,b)))
  11. typedef struct TreeNode
  12. {
  13. struct TreeNode *right;
  14. struct TreeNode *left;
  15. Word index;
  16. char str[1]; /* \0 byte already reserved */
  17. } TreeNode;
  18. static TreeNode *string_root = NULL;
  19. static TreeNode *constant_root = NULL;
  20. static TreeNode *variable_root = NULL;
  21. /*
  22. ** Insert a new string/constant/variable at the tree.
  23. */
  24. static char *tree_create (TreeNode **node, char *str)
  25. {
  26. if (*node == NULL)
  27. {
  28. *node = (TreeNode *) malloc (sizeof(TreeNode)+strlen(str));
  29. if (*node == NULL)
  30. lua_error ("memoria insuficiente\n");
  31. (*node)->left = (*node)->right = NULL;
  32. strcpy((*node)->str, str);
  33. (*node)->index = UNMARKED_STRING;
  34. return (*node)->str;
  35. }
  36. else
  37. {
  38. int c = lua_strcmp(str, (*node)->str);
  39. if (c < 0)
  40. return tree_create(&(*node)->left, str);
  41. else if (c > 0)
  42. return tree_create(&(*node)->right, str);
  43. else
  44. return (*node)->str;
  45. }
  46. }
  47. char *lua_strcreate (char *str)
  48. {
  49. return tree_create(&string_root, str);
  50. }
  51. char *lua_constcreate (char *str)
  52. {
  53. return tree_create(&constant_root, str);
  54. }
  55. char *lua_varcreate (char *str)
  56. {
  57. return tree_create(&variable_root, str);
  58. }
  59. /*
  60. ** Free a node of the tree
  61. */
  62. static TreeNode *lua_strfree (TreeNode *parent)
  63. {
  64. if (parent->left == NULL && parent->right == NULL) /* no child */
  65. {
  66. free (parent);
  67. return NULL;
  68. }
  69. else if (parent->left == NULL) /* only right child */
  70. {
  71. TreeNode *p = parent->right;
  72. free (parent);
  73. return p;
  74. }
  75. else if (parent->right == NULL) /* only left child */
  76. {
  77. TreeNode *p = parent->left;
  78. free (parent);
  79. return p;
  80. }
  81. else /* two children */
  82. {
  83. TreeNode *p = parent, *r = parent->right;
  84. while (r->left != NULL)
  85. {
  86. p = r;
  87. r = r->left;
  88. }
  89. if (p == parent)
  90. {
  91. r->left = parent->left;
  92. parent->left = NULL;
  93. parent->right = r->right;
  94. r->right = lua_strfree(parent);
  95. }
  96. else
  97. {
  98. TreeNode *t = r->right;
  99. r->left = parent->left;
  100. r->right = parent->right;
  101. parent->left = NULL;
  102. parent->right = t;
  103. p->left = lua_strfree(parent);
  104. }
  105. return r;
  106. }
  107. }
  108. /*
  109. ** Traverse tree for garbage collection
  110. */
  111. static TreeNode *lua_travcollector (TreeNode *r)
  112. {
  113. if (r == NULL) return NULL;
  114. r->right = lua_travcollector(r->right);
  115. r->left = lua_travcollector(r->left);
  116. if (r->index == UNMARKED_STRING)
  117. return lua_strfree(r);
  118. else
  119. {
  120. r->index = UNMARKED_STRING;
  121. return r;
  122. }
  123. }
  124. /*
  125. ** Garbage collection function.
  126. ** This function traverse the tree freening unindexed strings
  127. */
  128. void lua_strcollector (void)
  129. {
  130. string_root = lua_travcollector(string_root);
  131. }
  132. /*
  133. ** Return next variable.
  134. */
  135. static TreeNode *tree_next (TreeNode *node, char *str)
  136. {
  137. #if 0
  138. if (node == NULL) return NULL;
  139. if (str == NULL || lua_strcmp(str, node->str) < 0)
  140. {
  141. TreeNode *result = tree_next(node->left, str);
  142. return result == NULL ? node : result;
  143. }
  144. else
  145. {
  146. return tree_next(node->right, str);
  147. }
  148. #else
  149. if (node == NULL) return NULL;
  150. else if (str == NULL) return node;
  151. else
  152. {
  153. int c = lua_strcmp(str, node->str);
  154. if (c == 0)
  155. return node->left != NULL ? node->left : node->right;
  156. else if (c < 0)
  157. {
  158. TreeNode *result = tree_next(node->left, str);
  159. return result != NULL ? result : node->right;
  160. }
  161. else
  162. return tree_next(node->right, str);
  163. }
  164. #endif
  165. }
  166. char *lua_varnext (char *n)
  167. {
  168. TreeNode *result = tree_next(variable_root, n);
  169. return result != NULL ? result->str : NULL;
  170. }
  171. /*
  172. ** Given an id, find the string with exaustive search
  173. */
  174. static char *tree_name (TreeNode *node, Word index)
  175. {
  176. if (node == NULL) return NULL;
  177. if (node->index == index) return node->str;
  178. else
  179. {
  180. char *result = tree_name(node->left, index);
  181. return result != NULL ? result : tree_name(node->right, index);
  182. }
  183. }
  184. char *lua_varname (Word index)
  185. {
  186. return tree_name(variable_root, index);
  187. }