1. Cat's Eye Technologies
  2. Bhuna

Commits

catseye  committed cf5cb99

Initial import of Bhuna 0.1 sources.

  • Participants
  • Branches default
  • Tags rel_0_1

Comments (0)

Files changed (57)

File doc/bhuna.txt

View file
  • Ignore whitespace
+Program		::= {Statement}.
+Block		::= Statement | "{" {Statement} "}".
+Statement	::= (Control | Command | Assignment | Block) [";"].
+
+Control		::= "if" Expr<0> Block ["else" Block]
+		  | "while" Expr<0> Block.
+
+Command		::= VarExpr Expr<0> {"," Expr<0>}
+Assignment	::= ["local"] VarExpr "=" Expr<0>.
+
+Expr<N>		::= Expr<N+1> {Op<N> Expr<N+1>}.
+Expr<4>		::= Primitive.
+
+Op<0>		::= "&" | "|".
+Op<1>		::= ">" | "<" | ">=" | "<=" | "=" | "!=".
+Op<2>		::= "+" | "-".
+Op<3>		::= "*" | "/" | "%".
+
+Primitive	::= "(" Expr<0> ")"
+		  | "!" Primitive
+		  | VarExpr
+		  | Block						[[2]]
+		  | FunName "(" [Expr<0> {"," Expr<0>}] ")"
+		  | Literal.
+
+Literal		::= "[" [Literal {"," Literal}] "]"
+		  | <<symbol>>						[[3]]
+		  | <<number>>.
+
+VarExpr		::= Var {"[" Expr<0> "]"}.
+Var		::= <<symbol>>.						[[4]]
+
+Footnotes:
+
+[[2]]:  Only blocks enclosed in braces are valid here.
+[[3]]:	Must start with lowercase letter.
+[[4]]:	Must start with Uppercase letter.

File eg/1bottle.bhu

View file
  • Ignore whitespace
+Bottles = 99
+if Bottles > 0 {
+  print Bottles, " bottles of beer on the wall,", EoL,
+        Bottles, " bottles of beer,", EoL,
+        "Take one down, pass it around,", EoL,
+        Bottles - 1, " bottles of beer on the wall.", EoL, EoL
+  Bottles = Bottles - 1
+}
+

File eg/99bottles.bhu

View file
  • Ignore whitespace
+Bottles = 9999
+while Bottles > 0 {
+  Print Bottles, " bottles of beer on the wall,", EoL,
+        Bottles, " bottles of beer,", EoL,
+        "Take one down, pass it around,", EoL,
+        Bottles - 1, " bottles of beer on the wall.", EoL, EoL
+  Bottles = Bottles - 1
+}
+

File eg/99bottles.lua

View file
  • Ignore whitespace
+#!/usr/local/bin/lua
+
+bottles = 9999
+while (bottles > 0) do
+	print(bottles, "bottles of beer on the wall,")
+	print(bottles, "bottles of beer,")
+	print("Take none down, pass none around,")
+	print(bottles - 1, "bottles of beer on the wall.");
+	print("");
+	bottles = bottles - 1
+end

File eg/99bottles.pl

View file
  • Ignore whitespace
+#!/usr/bin/perl
+
+$bottles = 9999;
+while ($bottles > 0) {
+	print "$bottles bottles of beer on the wall,\n";
+	print "$bottles bottles of beer,\n";
+	print "Take none down, pass none around,\n";
+	$bottles = $bottles - 1;
+	print "$bottles bottles of beer on the wall.\n";
+	print "\n";
+}

File eg/bad1.bhu

View file
  • Ignore whitespace
+{

File eg/fun.bhu

View file
  • Ignore whitespace
+F = {
+  Print "hello from f", EoL
+  Print Arg, EoL
+  Print "goodbye from f", EoL
+  Return [119,123] // Index(Arg, 1)
+}
+
+G = F([1,2,3],[4,5,6])
+Print G, EoL
+

File eg/fun0.bhu

View file
  • Ignore whitespace
+G = {
+  Q = "hello"
+  F = {
+    Print Q
+  }
+  F
+}
+
+G

File eg/fun2.bhu

View file
  • Ignore whitespace
+F = {
+  T = 123
+  Return { Return 17 }
+}
+
+Print F, EoL
+Print F(), EoL
+Print F()(), EoL
+Print F()()(), EoL

File eg/fun3.bhu

View file
  • Ignore whitespace
+F = {
+  Q = 17
+  Return { Return Q }
+}
+Print F()()

File eg/fun4.bhu

View file
  • Ignore whitespace
+F = {
+  Level = Index(Arg, 1)
+  Print "Level is ", Level, EoL
+  Q = {
+    QLev = Index(Arg, 1)
+    Print "QLev is ", QLev, EoL
+    Print "(And Q thinks Level is ", Level, ")", EoL
+    if (QLev < 3)
+      Q QLev + 1
+    else
+      Print "This is as far as we go.", EoL
+  }
+  if Level < 3 {
+    F Level + 1
+  } else {
+    Print "At level three, woo!", EoL
+    Q(0)
+  }
+}
+
+F(0)

File eg/fun5.bhu

View file
  • Ignore whitespace
+F = {
+  C = Index(Arg, 1)
+  C Index(Arg, 2)
+  C "cheese"
+}
+
+R = {
+  Print "R was called with ", Index(Arg, 1), EoL
+}
+
+F R, "Spam Spam Spam Spam wonderful Spam!"
+

File eg/fun6.bhu

View file
  • Ignore whitespace
+
+Q = {}
+P = {
+  Level = Arg[1]
+  if (Level > 0) {
+    Print "Calling Q at level ", Level, EoL
+    Q Level - 1
+    Print "Called Q, Exiting P at level ", Level, EoL
+  }
+}
+Q = {
+  Level = Arg.1
+  if (Level > 0) {
+    Print "Calling P at level ", Level, EoL
+    P Level - 1
+    Print "Called P, Exiting Q at level ", Level, EoL
+  }
+}
+
+P 10

File eg/funny.bhu

View file
  • Ignore whitespace
+F = {
+  Q = 17
+  G = {
+    Print "Q is ", Q, EoL
+  }
+  G;
+  Return G
+}
+
+G = F()
+G;
+
+

File eg/funny2.bhu

View file
  • Ignore whitespace
+F = {
+  Q = 17
+  G = {
+    Print "Q is ", Q, EoL
+  }
+  G;
+  Q = 23;
+  G;
+  Return G
+}
+
+G = F()
+G;
+
+

File eg/happy.bhu

View file
  • Ignore whitespace
+F = 19
+
+Foo = {
+ local F = 23
+ print F
+}
+
+Print F
+Foo;
+Print F

File eg/happy2.bhu

View file
  • Ignore whitespace
+Foo = {
+ Print Arg
+}
+
+Foo 19, 23, 76;

File eg/infc.bhu

View file
  • Ignore whitespace
+Song = {
+  Bottles = 99
+
+  Sing = {
+    Print Bottles, " bottles of beer on the wall,", EoL,
+          Bottles, " bottles of beer,", EoL,
+          "Take none down, pass none around,", EoL,
+          Bottles, " bottles of beer on the wall.", EoL, EoL
+  }
+
+  while True Sing
+
+}
+
+Song

File eg/infc2.bhu

View file
  • Ignore whitespace
+F = {
+  Q = 17
+  Return { Print Q }
+}
+
+while True {
+  G = F()
+  G;
+}
+

File eg/infinite.bhu

View file
  • Ignore whitespace
+Bottles = 99
+while True {
+  Print Bottles, " bottles of beer on the wall,", EoL,
+        Bottles, " bottles of beer,", EoL,
+        "Take none down, pass none around,", EoL,
+        Bottles, " bottles of beer on the wall.", EoL, EoL
+}

File eg/list.bhu

View file
  • Ignore whitespace
+A = ["moe","larry","curly"]
+
+B = Index(A, 1)
+
+Print B
+
+// B = [1,"hello","there"]
+// Print A, EoL
+// Print B, EoL
+// B = A
+// Print A, EoL
+// Print B, EoL
+

File eg/lost-clos.bhu

View file
  • Ignore whitespace
+
+F = {
+  Print "hello!"
+}
+
+G = {
+  Print "naff!"
+}
+
+H = G		// does not dup the AST...
+G = F		// lost one ref to the AST...
+F = G		// my fears were unfounded
+

File eg/rec2.bhu

View file
  • Ignore whitespace
+G = 3
+
+R = {
+  if G > 0 {
+    G = G - 1
+    R
+  }
+}
+
+R

File eg/recur.bhu

View file
  • Ignore whitespace
+
+R = {
+  P = Arg[1]
+  Print "P is ", P, EoL
+  if (P > 0) R P - 1
+  Print "P is still ", P, EoL
+}
+
+R 2

File eg/ref.bhu

View file
  • Ignore whitespace
+A = 1
+B = 2
+A = B
+// debug
+

File eg/screw.bhu

View file
  • Ignore whitespace
+local F = 100
+while F > 20 {
+  local F = 10
+  print F
+  // global f = 3
+}
+print F
+

File eg/simple.bhu

View file
  • Ignore whitespace
+B = 100
+Print B
+B = B * 5
+Print B

File eg/while.c

View file
  • Ignore whitespace
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+	int f = 100;
+
+	while (f > 20) {
+		int f = 10;
+		printf("%d", f);
+	}
+	printf("%d", f);
+	
+	exit(0);
+}

File src/Makefile

View file
  • Ignore whitespace
+PROG=	bhuna
+SRCS=	scan.c parse.c \
+	symbol.c ast.c \
+	mem.c \
+	list.c atom.c buffer.c closure.c dict.c value.c \
+	activation.c eval.c \
+	builtin.c \
+	main.c
+
+CFLAGS+=-Wall -I/usr/local/include
+.ifndef NODEBUG
+CFLAGS+=-g -DDEBUG
+.else
+CFLAGS+=-DNDEBUG
+.endif
+
+NOMAN=	y
+
+# DESTDIR=/usr/local/sbin
+strip: bhuna
+	strip bhuna
+	ls -lah bhuna
+	ls -la bhuna
+
+.include <bsd.prog.mk>

File src/activation.c

View file
  • Ignore whitespace
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "activation.h"
+
+#include "mem.h"
+#include "symbol.h"
+#include "value.h"
+
+#ifdef DEBUG
+extern int trace_activations;
+#endif
+
+struct activation *
+activation_new(struct symbol_table *stab, struct activation *enclosing)
+{
+	struct activation *a;
+	struct symbol *sym;
+
+	a = bhuna_malloc(sizeof(struct activation));
+	a->alist = NULL;
+	activation_grab(enclosing);
+	a->enclosing = enclosing;
+	a->refcount = 1;
+
+	for (sym = stab->head; sym != NULL; sym = sym->next) {
+		struct alist *al;
+
+		al = bhuna_malloc(sizeof(struct alist));
+		al->next = a->alist;
+		al->sym = sym;
+		al->value = NULL;
+		a->alist = al;
+	}
+
+#ifdef DEBUG
+	if (trace_activations > 1) {
+		printf("[ARC] created ");
+		activation_dump(a, -1);
+		printf("\n");
+	}
+#endif
+
+	return(a);
+}
+
+void
+activation_free(struct activation *a)
+{
+	struct alist *next;
+
+#ifdef DEBUG
+	if (trace_activations > 1) {
+		printf("[ARC] freeing ");
+		activation_dump(a, -1);
+		printf("\n");
+	}
+#endif
+
+	assert(a->refcount == 0);
+	while (a->alist != NULL) {
+		next = a->alist->next;
+		value_release(a->alist->value);
+		bhuna_free(a->alist);
+		a->alist = next;
+	}
+	activation_release(a->enclosing);
+	bhuna_free(a);
+}
+
+/*** REFCOUNTERS ***/
+
+void
+activation_grab(struct activation *a)
+{
+	if (a == NULL)
+		return;
+	a->refcount++;
+#ifdef DEBUG
+	if (trace_activations > 1) {
+		printf("[ARC] ");
+		activation_dump(a, -1);
+		printf(" grabbed, refcount now %d\n", a->refcount);
+	}
+#endif
+}
+
+void
+activation_release(struct activation *a)
+{
+	if (a == NULL)
+		return;
+	a->refcount--;
+#ifdef DEBUG
+	if (trace_activations > 1) {
+		printf("[ARC] ");
+		activation_dump(a, -1);
+		printf(" released, refcount now %d\n", a->refcount);
+	}
+#endif
+	if (a->refcount == 0)
+		activation_free(a);	
+}
+
+static struct alist *
+activation_find_sym(struct activation *a, struct symbol *sym)
+{
+	struct alist *al;
+
+	for (al = a->alist; al != NULL; al = al->next) {
+		if (al->sym == sym)
+			return(al);
+	}
+
+	if (a->enclosing != NULL)
+		return(activation_find_sym(a->enclosing, sym));
+
+	return(NULL);
+}
+
+struct value *
+activation_get_value(struct activation *a, struct symbol *sym)
+{
+	struct alist *al;
+
+	al = activation_find_sym(a, sym);
+	assert(al != NULL);
+
+	return(al->value);
+}
+
+void
+activation_set_value(struct activation *a, struct symbol *sym, struct value *v)
+{
+	struct alist *al;
+
+	if ((al = activation_find_sym(a, sym)) == NULL) {
+#ifdef DEBUG
+	if (trace_activations > 1) {
+		printf("WARNING: ");
+		symbol_dump(sym, 0);
+		printf(" (=");
+		value_print(v);
+		printf(") not found in ");
+		activation_dump(a, -1);
+		printf(", adding\n");
+	}
+#endif
+
+		al = bhuna_malloc(sizeof(struct alist));
+		al->next = a->alist;
+		al->sym = sym;
+		al->value = NULL;
+		a->alist = al;
+	}
+
+	value_release(al->value);
+	value_grab(v);
+	al->value = v;
+}
+
+void
+activation_dump(struct activation *a, int detail)
+{
+#ifdef DEBUG
+	struct alist *al;
+
+	printf("Activation/");
+	if (a == NULL) {
+		printf("(NULL)/");
+		return;
+	}
+	if (detail == -1) {
+		printf("%08lx", (unsigned long)a);
+	} else {
+		for (al = a->alist; al != NULL; al = al->next) {
+			symbol_dump(al->sym, 0);
+			if (detail) {
+				printf("=");
+				value_print(al->value);
+			}
+			printf("  ");
+		}
+	}
+	if (a->enclosing != NULL) {
+		printf(" --> ");
+		activation_dump(a->enclosing, detail);
+	}
+	printf("/");
+#endif
+}

File src/activation.h

View file
  • Ignore whitespace
+struct symbol_table;
+struct symbol;
+struct value;
+
+struct activation {
+	int			 refcount;
+	struct alist		*alist;
+	struct activation	*enclosing;	/* lexically enclosing activation record */
+};
+
+struct alist {
+	struct alist	*next;
+	struct symbol	*sym;
+	struct value	*value;
+};
+
+
+struct activation	*activation_new(struct symbol_table *, struct activation *);
+void			 activation_free(struct activation *);
+
+void			 activation_grab(struct activation *);
+void			 activation_release(struct activation *);
+	
+struct value		*activation_get_value(struct activation *, struct symbol *);
+void			 activation_set_value(struct activation *, struct symbol *, struct value *);
+
+void			 activation_dump(struct activation *, int);

File src/ast.c

View file
  • Ignore whitespace
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ast.h"
+#include "list.h"
+#include "symbol.h"
+#include "value.h"
+
+/***** constructors *****/
+
+struct ast *
+ast_new_sym(struct symbol *s)
+{
+	struct ast *a;
+
+	a = malloc(sizeof(struct ast));
+	a->type = AST_SYM;
+
+	a->u.sym.sym = s;
+
+	return(a);
+}
+
+struct ast *
+ast_new_value(struct value *v)
+{
+	struct ast *a;
+
+	a = malloc(sizeof(struct ast));
+	a->type = AST_VALUE;
+
+	value_grab(v);
+	a->u.value.value = v;
+
+	return(a);
+}
+
+struct ast *
+ast_new_scope(struct ast *body, struct symbol_table *local)
+{
+	struct ast *a;
+
+	a = malloc(sizeof(struct ast));
+	a->type = AST_SCOPE;
+
+	a->u.scope.body = body;
+
+	a->u.scope.local = local;
+
+	return(a);
+}
+
+struct ast *
+ast_new_apply(struct ast *fn, struct ast *args)
+{
+	struct ast *a;
+
+	a = malloc(sizeof(struct ast));
+	a->type = AST_APPLY;
+
+	a->u.apply.left = fn;
+	a->u.apply.right = args;
+
+	return(a);
+}
+
+struct ast *
+ast_new_arg(struct ast *left, struct ast *right)
+{
+	struct ast *a;
+
+	a = malloc(sizeof(struct ast));
+	a->type = AST_ARG;
+
+	a->u.arg.left = left;
+	a->u.arg.right = right;
+
+	return(a);
+}
+
+struct ast *
+ast_new_statement(struct ast *left, struct ast *right)
+{
+	struct ast *a;
+
+	/*
+	if (left == NULL && right == NULL)
+		return(NULL);
+	if (left == NULL)
+		return(right);
+	if (right == NULL)
+		return(left);
+	*/
+
+	a = malloc(sizeof(struct ast));
+	a->type = AST_STATEMENT;
+
+	a->u.statement.left = left;
+	a->u.statement.right = right;
+
+	return(a);
+}
+
+struct ast *
+ast_new_assignment(struct ast *left, struct ast *right)
+{
+	struct ast *a;
+
+	a = malloc(sizeof(struct ast));
+	a->type = AST_ASSIGNMENT;
+
+	a->u.assignment.left = left;
+	a->u.assignment.right = right;
+
+	return(a);
+}
+
+struct ast *
+ast_new_conditional(struct ast *test, struct ast *yes, struct ast *no)
+{
+	struct ast *a;
+
+	a = malloc(sizeof(struct ast));
+	a->type = AST_CONDITIONAL;
+
+	a->u.conditional.test = test;
+	a->u.conditional.yes = yes;
+	a->u.conditional.no = no;
+
+	return(a);
+}
+
+struct ast *
+ast_new_while_loop(struct ast *test, struct ast *body)
+{
+	struct ast *a;
+
+	a = malloc(sizeof(struct ast));
+	a->type = AST_WHILE_LOOP;
+
+	a->u.while_loop.test = test;
+	a->u.while_loop.body = body;
+
+	return(a);
+}
+
+void
+ast_free(struct ast *a)
+{
+	if (a == NULL) {
+		return;
+	}
+	switch (a->type) {
+	case AST_SYM:
+		break;
+	case AST_VALUE:
+		value_release(a->u.value.value);
+		break;
+	case AST_SCOPE:
+		ast_free(a->u.scope.body);
+		break;
+	case AST_APPLY:
+		ast_free(a->u.apply.left);
+		ast_free(a->u.apply.right);
+		break;
+	case AST_ARG:
+		ast_free(a->u.arg.left);
+		ast_free(a->u.arg.right);
+		break;
+	case AST_STATEMENT:
+		ast_free(a->u.statement.left);
+		ast_free(a->u.statement.right);
+		break;
+	case AST_ASSIGNMENT:
+		ast_free(a->u.assignment.left);
+		ast_free(a->u.assignment.right);
+		break;
+	case AST_CONDITIONAL:
+		ast_free(a->u.conditional.test);
+		ast_free(a->u.conditional.yes);
+		ast_free(a->u.conditional.no);
+		break;
+	case AST_WHILE_LOOP:
+		ast_free(a->u.while_loop.test);
+		ast_free(a->u.while_loop.body);
+		break;
+	}
+	free(a);
+}
+
+char *
+ast_name(struct ast *a)
+{
+#ifdef DEBUG
+	if (a == NULL)
+		return("(null)");
+	switch (a->type) {
+	case AST_SYM:
+		return("AST_SYM");
+	case AST_VALUE:
+		return("AST_VALUE");
+	case AST_SCOPE:
+		return("AST_SCOPE");
+	case AST_APPLY:
+		return("AST_APPLY");
+	case AST_ARG:
+		return("AST_ARG");
+	case AST_STATEMENT:
+		return("AST_STATEMENT");
+	case AST_ASSIGNMENT:
+		return("AST_ASSIGNMENT");
+	case AST_CONDITIONAL:
+		return("AST_CONDITIONAL");
+	case AST_WHILE_LOOP:
+		return("AST_WHILE_LOOP");
+	}
+#endif
+	return("AST_UNKNOWN??!?");
+}
+
+void
+ast_dump(struct ast *a, int indent)
+{
+#ifdef DEBUG
+	int i;
+
+	if (a == NULL) {
+		return;
+	}
+	for (i = 0; i < indent; i++) printf("  ");
+	switch (a->type) {
+	case AST_SYM:
+		printf("symbol(");
+		symbol_dump(a->u.sym.sym, 0);
+		printf(")\n");
+		break;
+	case AST_VALUE:
+		printf("value(");
+		value_print(a->u.value.value);
+		printf(")\n");
+		break;
+	case AST_SCOPE:
+		printf("scope {\n");
+		symbol_table_dump(a->u.scope.local, 0);
+		/*symbol_table_dump(a->u.scope.trap, 0);*/
+		ast_dump(a->u.scope.body, indent + 1);
+		for (i = 0; i < indent; i++) printf("  "); printf("}\n");
+		break;
+	case AST_APPLY:
+		printf("apply {\n");
+		ast_dump(a->u.apply.left, indent + 1);
+		ast_dump(a->u.apply.right, indent + 1);
+		for (i = 0; i < indent; i++) printf("  "); printf("}\n");
+		break;
+	case AST_ARG:
+		printf("arg {\n");
+		ast_dump(a->u.arg.left, indent + 1);
+		ast_dump(a->u.arg.right, indent + 1);
+		for (i = 0; i < indent; i++) printf("  "); printf("}\n");
+		break;
+	case AST_STATEMENT:
+		printf("statement {\n");
+		ast_dump(a->u.statement.left, indent + 1);
+		ast_dump(a->u.statement.right, indent + 1);
+		for (i = 0; i < indent; i++) printf("  "); printf("}\n");
+		break;
+	case AST_ASSIGNMENT:
+		printf("assign {\n");
+		ast_dump(a->u.assignment.left, indent + 1);
+		ast_dump(a->u.assignment.right, indent + 1);
+		for (i = 0; i < indent; i++) printf("  "); printf("}\n");
+		break;
+	case AST_CONDITIONAL:
+		printf("conditional {\n");
+		ast_dump(a->u.conditional.test, indent + 1);
+		ast_dump(a->u.conditional.yes, indent + 1);
+		if (a->u.conditional.no != NULL)
+			ast_dump(a->u.conditional.no, indent + 1);
+		for (i = 0; i < indent; i++) printf("  "); printf("}\n");
+		break;
+	case AST_WHILE_LOOP:
+		printf("while {\n");
+		ast_dump(a->u.while_loop.test, indent + 1);
+		ast_dump(a->u.while_loop.body, indent + 1);
+		break;
+	}
+#endif
+}

File src/ast.h

View file
  • Ignore whitespace
+#ifndef __AST_H_
+#define __AST_H_
+
+struct value;
+struct symbol;
+struct list;
+
+struct ast_sym {
+	struct symbol		*sym;
+};
+
+struct ast_value {
+	struct value		*value;
+};
+
+struct ast_scope {
+	struct symbol_table	*local;
+	struct ast		*body;
+};
+
+struct ast_apply {
+	struct ast		*left;		/* ISA var(/...?)  (fn/cmd) */
+	struct ast		*right;		/* ISA arg */
+};
+
+struct ast_arg {
+	struct ast		*left;		/* ISA arg/apply/var */
+	struct ast		*right;		/* ISA arg/apply/var */
+};
+
+struct ast_statement {
+	struct ast		*left;		/* ISA statement/apply */
+	struct ast		*right;		/* ISA statement/apply */
+};
+
+struct ast_assignment {
+	struct ast		*left;		/* ISA var */
+	struct ast		*right;		/* ISA apply/var */
+};
+
+struct ast_conditional {
+	struct ast		*test;		/* ISA apply/var */
+	struct ast		*yes;		/* ISA statement/apply */
+	struct ast		*no;		/* ISA statement/apply/NULL */
+};
+
+struct ast_while_loop {
+	struct ast		*test;		/* ISA apply/var */
+	struct ast		*body;		/* ISA statement/apply */
+};
+
+#define AST_SYM		1
+#define AST_VALUE	2
+#define AST_SCOPE	3
+#define	AST_APPLY	4
+#define	AST_ARG		5
+#define	AST_STATEMENT	6
+#define	AST_ASSIGNMENT	7
+#define	AST_CONDITIONAL	8
+#define	AST_WHILE_LOOP	9
+
+union ast_union {
+	struct ast_sym		sym;
+	struct ast_value	value;
+	struct ast_scope	scope;
+	struct ast_apply	apply;
+	struct ast_arg		arg;
+	struct ast_statement	statement;
+	struct ast_assignment	assignment;
+	struct ast_conditional	conditional;
+	struct ast_while_loop	while_loop;
+};
+
+struct ast {
+	int				type;
+	union ast_union			u;
+};
+
+struct ast		*ast_new_sym(struct symbol *);
+struct ast		*ast_new_value(struct value *);
+struct ast		*ast_new_scope(struct ast *, struct symbol_table *);
+struct ast		*ast_new_apply(struct ast *, struct ast *);
+struct ast		*ast_new_arg(struct ast *, struct ast *);
+struct ast		*ast_new_statement(struct ast *, struct ast *);
+struct ast		*ast_new_assignment(struct ast *, struct ast *);
+struct ast		*ast_new_conditional(struct ast *, struct ast *, struct ast *);
+struct ast		*ast_new_while_loop(struct ast *, struct ast *);
+void			 ast_free(struct ast *);
+
+void			 ast_dump(struct ast *, int);
+char			*ast_name(struct ast *);
+
+void			 ast_eval(struct ast *, struct value **);
+
+#endif /* !__AST_H_ */

File src/atom.c

View file
  • Ignore whitespace
+#include <string.h>
+#include <stdlib.h>
+
+#include "mem.h"
+#include "atom.h"
+
+static struct atom_entry *atom_entry_head = NULL;
+static int next_atom = 0;
+
+int
+atom_resolve(char *lexeme)
+{
+	struct atom_entry *ae;
+
+	/* find lexeme in atom table */
+	for (ae = atom_entry_head; ae != NULL; ae = ae->next) {
+		if (strcmp(ae->lexeme, lexeme) == 0)
+			return(ae->atom);
+	}
+	/* create new atom */
+	ae = bhuna_malloc(sizeof(struct atom_entry));
+	ae->next = atom_entry_head;
+	ae->lexeme = strdup(lexeme);
+	ae->atom = next_atom++;
+	atom_entry_head = ae;
+
+	return(ae->atom);
+}

File src/atom.h

View file
  • Ignore whitespace
+#ifndef __ATOM_H_
+#define __ATOM_H_
+
+struct atom_entry {
+	struct atom_entry *next;
+	char *lexeme;
+	int atom;
+};
+
+int atom_resolve(char *);
+
+#endif /* !__ATOM_H_ */

File src/buffer.c

View file
  • Ignore whitespace
+/*
+ * Copyright (c) 2004 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Chris Pressey <cpressey@catseye.mine.nu>.
+ *
+ * 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. Neither the name of The DragonFly Project 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDERS 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.
+ */
+
+/*
+ * extbuf.c
+ * $Id: buffer.c,v 1.1 2004/07/21 19:52:35 cpressey Exp $
+ * Routines to manipulate extensible buffers.
+ *
+ * Aura buffers are buffers that attempt to automatically expand
+ * when more data is written to them than they can initially hold.
+ * In addition, each extensible buffer contains a cursor from which
+ * its contents may be incrementally scanned.
+ */
+
+#include <err.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+
+#include "buffer.h"
+
+/*
+ * Create a new extensible buffer with the given initial size.
+ */
+struct aura_buffer *
+aura_buffer_new(size_t size)
+{
+	struct aura_buffer *e;
+
+	e = malloc(sizeof(struct aura_buffer));
+
+	e->len = 0;
+	e->size = size;
+	e->pos = 0;
+
+	e->buf = malloc(size);
+	e->buf[0] = '\0';
+
+	return(e);
+}
+
+/*
+ * Deallocate the memory used for an extensible buffer.
+ */
+void
+aura_buffer_free(struct aura_buffer *e)
+{
+	if (e != NULL) {
+		if (e->buf != NULL)
+			free(e->buf);
+		free(e);
+	}
+}
+
+/*
+ * Return the underlying (static) buffer of an extensible buffer.
+ *
+ * NOTE that you should NEVER cache the returned pointer anywhere,
+ * as any further manipulation of the extensible buffer may cause
+ * it to be invalidated.
+ *
+ * ALSO NOTE that the buffer may contain embedded NULs, but will
+ * also be guaranteed to be NUL-terminated.
+ */
+char *
+aura_buffer_buf(struct aura_buffer *e)
+{
+	return(e->buf);
+}
+
+/*
+ * Return the current length of the extensible buffer.
+ */
+size_t
+aura_buffer_len(struct aura_buffer *e)
+{
+	return(e->len);
+}
+
+/*
+ * Return the current size of the extensible buffer.  This is how
+ * big it's length may grow to before expanded.
+ */
+size_t
+aura_buffer_size(struct aura_buffer *e)
+{
+	return(e->size);
+}
+
+/*
+ * Ensure that an extensible buffer's size is at least the given
+ * size.  If it is not, it will be internally grown to that size.
+ * This does not affect the contents of the buffer in any way.
+ */
+void
+aura_buffer_ensure_size(struct aura_buffer *e, size_t size)
+{
+	if (e->size >= size) return;
+	e->size = size;
+	if ((e->buf = realloc(e->buf, e->size)) == NULL) {
+		err(EX_UNAVAILABLE, "realloc()");
+	}
+}
+
+/*
+ * Set the contents of an extensible buffer from a regular (char *)
+ * buffer.  The extensible buffer will grow if needed.  Any existing
+ * contents of the extensible buffer are destroyed in this operation.
+ * Note that, because this requires that the length of the
+ * regular buffer be specified, it may safely contain NUL bytes.
+ */
+void
+aura_buffer_set(struct aura_buffer *e, char *buf, size_t length)
+{
+	while ((length + 1) > e->size) {
+		e->size *= 2;
+	}
+	if ((e->buf = realloc(e->buf, e->size)) == NULL) {
+		err(EX_UNAVAILABLE, "realloc()");
+	}
+	memcpy(e->buf, buf, length);
+	e->len = length;
+	e->buf[e->len] = '\0';
+}
+
+/*
+ * Append the contents of a regular buffer to the end of the existing
+ * contents of an extensible buffer.  The extensible buffer will grow
+ * if needed.  Note that, because this requires that the length of the
+ * regular buffer be specified, it may safely contain NUL bytes.
+ */
+void
+aura_buffer_append(struct aura_buffer *e, char *buf, size_t length)
+{
+	while (e->len + (length + 1) > e->size) {
+		e->size *= 2;
+	}
+	if ((e->buf = realloc(e->buf, e->size)) == NULL) {
+		err(EX_UNAVAILABLE, "realloc()");
+	}
+	memcpy(e->buf + e->len, buf, length);
+	e->len += length;
+	e->buf[e->len] = '\0';
+}
+
+/*
+ * Set the contents of an extensible buffer from an ASCIIZ string.
+ * This is identical to aura_buffer_set except that the length need not
+ * be specified, and the ASCIIZ string may not contain embedded NUL's.
+ */
+void
+aura_buffer_cpy(struct aura_buffer *e, char *s)
+{
+	aura_buffer_set(e, s, strlen(s));
+}
+
+/*
+ * Append the contents of an ASCIIZ string to an extensible buffer.
+ * This is identical to aura_buffer_append except that the length need not
+ * be specified, and the ASCIIZ string may not contain embedded NUL's.
+ */
+void
+aura_buffer_cat(struct aura_buffer *e, char *s)
+{
+	aura_buffer_append(e, s, strlen(s));
+}
+
+/*
+ * Append the entire contents of a text file to an extensible buffer.
+ */
+int
+aura_buffer_cat_file(struct aura_buffer *e, char *fmt, ...)
+{
+	va_list args;
+	char *filename, line[1024];
+	FILE *f;
+
+	va_start(args, fmt);
+	vasprintf(&filename, fmt, args);
+	va_end(args);
+
+	if ((f = fopen(filename, "r")) == NULL)
+		return(0);
+
+	free(filename);
+
+	while (fgets(line, 1023, f) != NULL) {
+		aura_buffer_cat(e, line);
+	}
+
+	fclose(f);
+
+	return(1);
+}
+
+/*
+ * Append the entire output of a shell command to an extensible buffer.
+ */
+int
+aura_buffer_cat_pipe(struct aura_buffer *e, char *fmt, ...)
+{
+	va_list args;
+	char *command, line[1024];
+	FILE *p;
+
+	va_start(args, fmt);
+	vasprintf(&command, fmt, args);
+	va_end(args);
+
+	if ((p = popen(command, "r")) == NULL)
+		return(0);
+
+	free(command);
+
+	while (fgets(line, 1023, p) != NULL) {
+		aura_buffer_cat(e, line);
+	}
+
+	pclose(p);
+
+	return(1);
+}
+
+/*** CURSORED FUNCTIONS ***/
+
+/*
+ * Note that the cursor can be anywhere from the first character to
+ * one position _beyond_ the last character in the buffer.
+ */
+
+int
+aura_buffer_seek(struct aura_buffer *e, size_t pos)
+{
+	if (pos <= e->size) {
+		e->pos = pos;
+		return(1);
+	} else {
+		return(0);
+	}
+}
+
+size_t
+aura_buffer_tell(struct aura_buffer *e)
+{
+	return(e->pos);
+}
+
+int
+aura_buffer_eof(struct aura_buffer *e)
+{
+	return(e->pos >= e->size);
+}
+
+char
+aura_buffer_peek_char(struct aura_buffer *e)
+{
+	return(e->buf[e->pos]);
+}
+
+char
+aura_buffer_scan_char(struct aura_buffer *e)
+{
+	return(e->buf[e->pos++]);
+}
+
+int
+aura_buffer_compare(struct aura_buffer *e, char *s)
+{
+	int i, pos;
+
+	for (i = 0, pos = e->pos; s[i] != '\0' && pos < e->size; i++, pos++) {
+		if (e->buf[pos] != s[i])
+			return(0);
+	}
+
+	if (pos <= e->size) {
+		return(pos);
+	} else {
+		return(0);
+	}
+}
+
+int
+aura_buffer_expect(struct aura_buffer *e, char *s)
+{
+	int pos;
+
+	if ((pos = aura_buffer_compare(e, s)) > 0) {
+		e->pos = pos;
+		return(1);
+	} else {
+		return(0);
+	}
+}
+
+void
+aura_buffer_push(struct aura_buffer *e, void *src, size_t len)
+{
+	aura_buffer_ensure_size(e, e->pos + len);
+	memcpy(e->buf + e->pos, src, len);
+	e->pos += len;
+}
+
+int
+aura_buffer_pop(struct aura_buffer *e, void *dest, size_t len)
+{
+	if (e->pos - len > 0) {
+		e->pos -= len;
+		memcpy(dest, e->buf + e->pos, len);
+		return(1);
+	} else {
+		return(0);
+	}
+}

File src/buffer.h

View file
  • Ignore whitespace
+/*
+ * Copyright (c) 2004 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Chris Pressey <cpressey@catseye.mine.nu>.
+ *
+ * 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. Neither the name of The DragonFly Project 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDERS 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.
+ */
+
+/*
+ * buffer.h
+ * $Id: buffer.h,v 1.1 2004/07/21 19:52:35 cpressey Exp $
+ */
+
+#ifndef __AURA_BUFFER_H_
+#define	__AURA_BUFFER_H_
+
+#include <stdlib.h>
+
+struct aura_buffer {
+	char	*buf;
+	size_t	 len;
+	size_t	 size;
+	size_t	 pos;
+};
+
+struct aura_buffer	*aura_buffer_new(size_t);
+void			 aura_buffer_free(struct aura_buffer *);
+char			*aura_buffer_buf(struct aura_buffer *);
+size_t			 aura_buffer_len(struct aura_buffer *);
+size_t			 aura_buffer_size(struct aura_buffer *);
+
+void			 aura_buffer_ensure_size(struct aura_buffer *, size_t);
+void			 aura_buffer_set(struct aura_buffer *, char *, size_t);
+void			 aura_buffer_append(struct aura_buffer *, char *, size_t);
+
+void			 aura_buffer_cpy(struct aura_buffer *, char *);
+void			 aura_buffer_cat(struct aura_buffer *, char *);
+int			 aura_buffer_cat_file(struct aura_buffer *, char *, ...);
+int			 aura_buffer_cat_pipe(struct aura_buffer *, char *, ...);
+
+int			 aura_buffer_seek(struct aura_buffer *, size_t);
+size_t			 aura_buffer_tell(struct aura_buffer *);
+int			 aura_buffer_eof(struct aura_buffer *);
+char			 aura_buffer_peek_char(struct aura_buffer *);
+char			 aura_buffer_scan_char(struct aura_buffer *);
+int			 aura_buffer_compare(struct aura_buffer *, char *);
+int			 aura_buffer_expect(struct aura_buffer *, char *);
+
+void			 aura_buffer_push(struct aura_buffer *, void *, size_t);
+int			 aura_buffer_pop(struct aura_buffer *, void *, size_t);
+
+#endif /* !__AURA_BUFFER_H_ */

File src/builtin.c

View file
  • Ignore whitespace
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "builtin.h"
+#include "value.h"
+#include "list.h"
+#include "closure.h"
+
+#include "symbol.h"
+
+/*
+ * Built-in operations.
+ * Each of these allocates a new value and returns it,
+ * leaving the passed values untouched.
+ * The single parameter `arg' is always a value of type VALUE_LIST.
+ */
+
+struct builtin_desc builtins[] = {
+	{"Print",	builtin_print},
+	{"Return",	builtin_return},
+	{"!",		builtin_not},
+	{"&",		builtin_and},
+	{"|",		builtin_or},
+	{"=",		builtin_equ},
+	{"!=",		builtin_neq},
+	{">",		builtin_gt},
+	{"<",		builtin_lt},
+	{">=",		builtin_gte},
+	{"<=",		builtin_lte},
+	{"+",		builtin_add},
+	{"-",		builtin_sub},
+	{"*",		builtin_mul},
+	{"/",		builtin_div},
+	{"%",		builtin_mod},
+	{"Index",	builtin_index},
+	{NULL,		NULL}
+};
+
+void
+builtin_return(struct value **arg)
+{
+	/* Deref the list. */
+	value_set_from_value(arg, (*arg)->v.l->value);
+}
+
+void
+builtin_print(struct value **arg)
+{
+	struct list *l;
+	struct value *v;
+
+	for (l = (*arg)->v.l; l != NULL; l = l->next) {
+		v = l->value;
+		switch (v->type) {
+		case VALUE_INTEGER:
+			printf("%d", v->v.i);
+			break;
+		case VALUE_BOOLEAN:
+			printf("%s", v->v.b ? "true" : "false");
+			break;
+		case VALUE_STRING:
+			printf("%s", v->v.s);
+			break;
+		case VALUE_LIST:
+			builtin_print(&v);
+			break;
+		case VALUE_STAB:
+			symbol_table_dump(v->v.stab, 1);
+			break;
+		case VALUE_ERROR:
+			printf("#ERR<%s>", v->v.e);
+			break;
+		case VALUE_BUILTIN:
+			printf("#FN<%08lx>", (unsigned long)v->v.f);
+			break;
+		case VALUE_CLOSURE:
+			closure_dump(v->v.k);
+			break;
+		case VALUE_SYMBOL:
+			symbol_dump(v->v.sym, 0);
+			break;
+		default:
+			printf("???unknown(%d)???", v->type);
+			break;
+		}
+	}
+}
+
+/*** logical ***/
+
+void
+builtin_not(struct value **arg)
+{
+	struct value *v;
+
+	v = (*arg)->v.l->value;
+
+	if (v->type == VALUE_BOOLEAN) {
+		value_set_boolean(arg, !v->v.b);
+	} else {
+		value_set_error(arg, "type mismatch");
+	}
+}
+
+void
+builtin_and(struct value **arg)
+{
+	struct value *l, *r;
+
+	l = (*arg)->v.l->value;
+	r = (*arg)->v.l->next->value;
+
+	if (l->type == VALUE_BOOLEAN && r->type == VALUE_BOOLEAN) {
+		value_set_boolean(arg, l->v.b && r->v.b);
+	} else {
+		value_set_error(arg, "type mismatch");
+	}
+}
+
+void
+builtin_or(struct value **arg)
+{
+	struct value *l, *r;
+
+	l = (*arg)->v.l->value;
+	r = (*arg)->v.l->next->value;
+
+	if (l->type == VALUE_BOOLEAN && r->type == VALUE_BOOLEAN) {
+		value_set_boolean(arg, l->v.b || r->v.b);
+	} else {
+		value_set_error(arg, "type mismatch");
+	}
+}
+
+/*** comparison ***/
+
+void
+builtin_equ(struct value **arg)
+{
+	struct value *l, *r;
+
+	l = (*arg)->v.l->value;
+	r = (*arg)->v.l->next->value;
+
+	if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) {
+		value_set_boolean(arg, l->v.i == r->v.i);
+	} else {
+		value_set_error(arg, "type mismatch");
+	}
+}
+
+void
+builtin_neq(struct value **arg)
+{
+	struct value *l, *r;
+
+	l = (*arg)->v.l->value;
+	r = (*arg)->v.l->next->value;
+
+	if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) {
+		value_set_boolean(arg, l->v.i != r->v.i);
+	} else {
+		value_set_error(arg, "type mismatch");
+	}
+}
+
+void
+builtin_gt(struct value **arg)
+{
+	struct value *l, *r;
+
+	l = (*arg)->v.l->value;
+	r = (*arg)->v.l->next->value;
+
+	if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) {
+		value_set_boolean(arg, l->v.i > r->v.i);
+	} else {
+		value_set_error(arg, "type mismatch");
+	}
+}
+
+void
+builtin_lt(struct value **arg)
+{
+	struct value *l, *r;
+
+	l = (*arg)->v.l->value;
+	r = (*arg)->v.l->next->value;
+
+	if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) {
+		value_set_boolean(arg, l->v.i < r->v.i);
+	} else {
+		value_set_error(arg, "type mismatch");
+	}
+}
+
+void
+builtin_gte(struct value **arg)
+{
+	struct value *l, *r;
+
+	l = (*arg)->v.l->value;
+	r = (*arg)->v.l->next->value;
+
+	if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) {
+		value_set_boolean(arg, l->v.i >= r->v.i);
+	} else {
+		value_set_error(arg, "type mismatch");
+	}
+}
+
+void
+builtin_lte(struct value **arg)
+{
+	struct value *l, *r;
+
+	l = (*arg)->v.l->value;
+	r = (*arg)->v.l->next->value;
+
+	if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) {
+		value_set_boolean(arg, l->v.i <= r->v.i);
+	} else {
+		value_set_error(arg, "type mismatch");
+	}
+}
+
+/*** arithmetic ***/
+
+void
+builtin_add(struct value **arg)
+{
+	struct value *l, *r;
+
+	l = (*arg)->v.l->value;
+	r = (*arg)->v.l->next->value;
+
+	if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) {
+		value_set_integer(arg, l->v.i + r->v.i);
+	} else {
+		value_set_error(arg, "type mismatch");
+	}
+}
+
+void
+builtin_mul(struct value **arg)
+{
+	struct value *l, *r;
+
+	l = (*arg)->v.l->value;
+	r = (*arg)->v.l->next->value;
+
+	if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) {
+		value_set_integer(arg, l->v.i * r->v.i);
+	} else {
+		value_set_error(arg, "type mismatch");
+	}
+}
+
+void
+builtin_sub(struct value **arg)
+{
+	struct value *l, *r;
+
+	l = (*arg)->v.l->value;
+	r = (*arg)->v.l->next->value;
+
+	if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) {
+		value_set_integer(arg, l->v.i - r->v.i);
+	} else {
+		value_set_error(arg, "type mismatch");
+	}
+}
+
+void
+builtin_div(struct value **arg)
+{
+	struct value *l, *r;
+
+	l = (*arg)->v.l->value;
+	r = (*arg)->v.l->next->value;
+
+	if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) {
+		if (r->v.i == 0)
+			value_set_error(arg, "division by zero");
+		else
+			value_set_integer(arg, l->v.i / r->v.i);
+	} else {
+		value_set_error(arg, "type mismatch");
+	}
+}
+
+void
+builtin_mod(struct value **arg)
+{
+	struct value *l, *r;
+
+	l = (*arg)->v.l->value;
+	r = (*arg)->v.l->next->value;
+
+	if (l->type == VALUE_INTEGER && r->type == VALUE_INTEGER) {
+		if (r->v.i == 0)
+			value_set_error(arg, "modulo by zero");
+		else
+			value_set_integer(arg, l->v.i % r->v.i);
+	} else {
+		value_set_error(arg, "type mismatch");
+	}
+}
+
+/*** list ***/
+
+void
+builtin_index(struct value **arg)
+{
+	struct value *l, *r;
+	int count;
+	struct list *li;
+
+	l = (*arg)->v.l->value;
+	r = (*arg)->v.l->next->value;
+
+	if (l->type == VALUE_LIST && r->type == VALUE_INTEGER) {
+		li = l->v.l;
+		for (count = 1; l != NULL && count < r->v.i; count++)
+			li = li->next;
+		if (li == NULL)
+			value_set_error(arg, "no such element");
+		else
+			value_set_from_value(arg, li->value);
+	} else {
+		value_set_error(arg, "type mismatch");
+	}
+}

File src/builtin.h

View file
  • Ignore whitespace
+#ifndef __BUILTIN_H_
+#define __BUILTIN_H_
+
+struct value;
+
+struct builtin_desc {
+	char *name;
+	void (*fn)(struct value **);
+};
+
+extern struct builtin_desc builtins[];
+
+void	builtin_print(struct value **);
+
+void	builtin_return(struct value **);
+
+void	builtin_not(struct value **);
+void	builtin_and(struct value **);
+void	builtin_or(struct value **);
+
+void	builtin_equ(struct value **);
+void	builtin_neq(struct value **);
+void	builtin_gt(struct value **);
+void	builtin_lt(struct value **);
+void	builtin_gte(struct value **);
+void	builtin_lte(struct value **);
+
+void	builtin_add(struct value **);
+void	builtin_mul(struct value **);
+void	builtin_sub(struct value **);
+void	builtin_div(struct value **);
+void	builtin_mod(struct value **);
+
+void	builtin_index(struct value **);
+
+#endif

File src/closure.c

View file
  • Ignore whitespace
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mem.h"
+#include "closure.h"
+#include "symbol.h"
+#include "ast.h"
+#include "activation.h"
+
+struct closure *
+closure_new(struct ast *a, struct activation *ar)
+{
+	struct closure *c;
+
+	assert(a->type == AST_SCOPE);
+
+	c = bhuna_malloc(sizeof(struct closure));
+	c->ast = a;
+	c->ar = ar;
+
+	return(c);
+}
+
+void
+closure_free(struct closure *c)
+{
+	activation_release(c->ar);
+	bhuna_free(c);
+}
+
+void
+closure_dump(struct closure *c)
+{
+#ifdef DEBUG
+	printf("closure{");
+	ast_dump(c->ast, 0);
+	activation_dump(c->ar, 0);
+	printf("}");
+#endif
+}

File src/closure.h

View file
  • Ignore whitespace
+#ifndef __CLOSURE_H_
+#define __CLOSURE_H_
+
+struct activation;
+struct ast;
+
+struct closure {
+	struct ast		*ast;
+	struct activation	*ar;	/* env in which we were created */
+};
+
+struct closure	*closure_new(struct ast *, struct activation *);
+void		 closure_free(struct closure *);
+void		 closure_dump(struct closure *);
+
+#endif

File src/dict.c

View file
  • Ignore whitespace
+/*
+ * Copyright (c) 2004 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Chris Pressey <cpressey@catseye.mine.nu>.
+ *
+ * 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. Neither the name of The DragonFly Project 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 COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDERS 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.
+ */
+
+/*
+ * dict.c
+ * $Id$
+ * Routines to manipulate Bhuna dictionaries.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mem.h"
+
+#include "dict.h"
+#include "value.h"
+
+/*** CONSTRUCTOR ***/
+
+/*
+ * Create a new dictionary.
+ */
+struct dict *
+dict_new(void)
+{
+	struct dict *d;
+	int i;
+
+	d = bhuna_malloc(sizeof(struct dict));
+	d->num_buckets = 31;
+	d->bucket = bhuna_malloc(sizeof(struct chain *) * d->num_buckets);
+	for (i = 0; i < d->num_buckets; i++) {
+		d->bucket[i] = NULL;
+	}
+	d->cursor = NULL;
+	d->cur_bucket = 0;
+
+	return(d);
+}
+
+/*** DESTRUCTORS ***/
+
+static void
+chain_free(struct chain *c)
+{
+	assert(c != NULL);
+
+	value_release(c->key);
+	value_release(c->value);
+
+	bhuna_free(c);
+}
+
+void
+dict_free(struct dict *d)
+{
+	struct chain *c;
+	size_t bucket_no;
+
+	for (bucket_no = 0; bucket_no < d->num_buckets; bucket_no++) {
+		c = d->bucket[bucket_no];
+		while (c != NULL) {
+			d->bucket[bucket_no] = c->next;
+			chain_free(c);
+			c = d->bucket[bucket_no];
+		}
+	}
+	bhuna_free(d);
+}
+
+/*** UTILITIES ***/
+
+/*
+ * Hash function, taken from "Compilers: Principles, Techniques, and Tools"
+ * by Aho, Sethi, & Ullman (a.k.a. "The Dragon Book", 2nd edition.)
+ */
+static size_t
+hashpjw(struct value *key, size_t table_size) {
+	char *p;
+	unsigned long int h = 0, g;
+
+	/*
+	 * XXX ecks ecks ecks XXX
+	 * This is naff... for cer