Use gperf to save memory.

We check terms to see if they're in the wordlist, if they are we reuse
the string from the wordlist instead of allocating a new one.

(I've always wanted to use Gperf so I'm pretty stoked about this!)
This commit is contained in:
Simon Forman 2023-02-02 16:58:44 -08:00
parent 0a66f2b804
commit 4be1cc5767
5 changed files with 47 additions and 53 deletions

View File

@ -1,3 +1,5 @@
%compare-strncmp
%%
!=
"%"
*

View File

@ -9,6 +9,8 @@ GPERF_OPTS = --readonly-tables --enum --includes --global-table
joy: ${OBJS} $(STATIC_GCLIB)
keywords.c: KEYWORDS.txt
keywords.c: KEYWORDS.txt keywords.h
gperf --output-file=$@ --hash-function-name=keyword_hash $(GPERF_OPTS) KEYWORDS.txt
# keywords.c doesn't strictly depend on keywords.h, but I want make to
# remake if keywords.h is touched.

View File

@ -16,41 +16,6 @@
You should have received a copy of the GNU General Public License
along with Thun. If not see <http://www.gnu.org/licenses/>.
This program implements an interpreter for a dialect of Joy.
Joy is a programming language created by Manfred von Thun that is easy to
use and understand and has many other nice properties. This Python
package implements an interpreter for a dialect of Joy that attempts to
stay very close to the spirit of Joy but does not precisely match the
behaviour of the original version(s) written in C. The main difference
between Thun and the originals, other than being written in Python, is
that it works by the Continuation-Passing Style.
Here is an example of Joy code:
[ [[abs] ii <=]
[
[<>] [pop !-] ||
] &&
]
[[ !-] [[++]] [[--]] ifte dip]
[[pop !-] [--] [++] ifte ]
ifte
This function accepts two integers on the stack and increments or
decrements one of them such that the new pair of numbers is the next
coordinate pair in a square spiral (like the kind used to construct an
Ulam Spiral).
*/
#include <stddef.h>
#include <stdlib.h>
@ -60,6 +25,8 @@ Ulam Spiral).
#include <gc.h>
#include <gmp.h>
# include "keywords.h"
const char *BLANKS = " \t";
const char *FALSE = "false";
@ -92,6 +59,9 @@ struct list_node {
} JoyList;
#define EMPTY_LIST (struct list_node*)NULL
void*
reallocate_function (void *ptr, __attribute__((unused)) size_t old_size, size_t new_size) {
return GC_REALLOC(ptr, new_size);
@ -184,12 +154,20 @@ make_non_list_node(char *text, size_t size)
{
struct list_node *node;
char *sym;
const char *interned;
node = GC_malloc(sizeof(struct list_node));
interned = in_word_set(text, size);
if (interned) {
node->head.kind = joySymbol;
node->head.value.symbol = (char *)interned;
return node;
}
sym = GC_malloc(size + 1); /* one more for the zero, right? */
strncat(sym, text, size);
node = GC_malloc(sizeof(struct list_node));
if (!strncmp(sym, FALSE, 6)) { /* I know it's wrong to hardcode the length here. Sorry. */
/* If head was a pointer we could reuse Boolean singletons... */
node->head.kind = joyFalse;
@ -225,14 +203,23 @@ make_list_node(struct list_node *el)
return node;
}
#define EMPTY_LIST (struct list_node*)NULL
/*
Extract terms from the text until a closing bracket is found.
*/
struct list_node*
parse_list(char **text)
{
/*
Extract terms from the text until a closing bracket is found.
*/
char *rest;
ptrdiff_t diff;
struct list_node *result = NULL;

View File

@ -144,7 +144,7 @@ in_word_set (register const char *str, register size_t len)
{
register const char *s = wordlist[key];
if (*str == *s && !strcmp (str + 1, s + 1))
if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
return s;
}
}

View File

@ -0,0 +1,3 @@
const char *
in_word_set (register const char *str, register size_t len);