1. Cat's Eye Technologies
  2. GraNoLa/M

Commits

catseye  committed 0ffef79

Don't ship with (old) .beams, Markdownify, subdirs, add script.

  • Participants
  • Parent commits e7f533e
  • Branches default

Comments (0)

Files changed (10)

File .gitignore

View file
  • Ignore whitespace
+*.beam

File .hgignore

View file
  • Ignore whitespace
+syntax: glob
+
+*.beam

File BLURB

  • Ignore whitespace
-granolam.erl - GraNoLa/M interpreter in Erlang
-----------------------------------------------
-
-GraNoLa/M is a programming language in which the directed graph is the
-only data type.  See granolam.txt for a more complete description of the
-GraNoLa/M language.  granolam.erl is an interpreter for this language.
-
-You need an Erlang compiler at least at language version 4.4 to compile
-granola.erl.  This program was developed with OTP/R8B, so that is the
-recommended platform for using it.  R8B can be obtained from:
-
-  http://www.erlang.org/download.html
-
-Usage:
-
-  erlc granolam.erl
-  erl -noshell -run granolam shell
-
-Or, to run the built-in tests:
-
-  erl
-  granolam:test(N).           (where N is 1-7)
-
-The contents of the files in this archive BLURB, granolam.txt and
-granolam.erl are parts of the public domain.

File README.markdown

View file
  • Ignore whitespace
+GraNoLa/M
+=========
+
+This is the reference distribution for the esoteric programming language
+_GraNoLa/M_.
+
+GraNoLa/M is a programming language in which the directed graph is the
+only data type.  See the file `GraNoLa-M.markdown` in the `doc` directory
+for a more complete description of the GraNoLa/M language.
+
+This distribution also contains an interpreter for GraNoLa/M written in
+Erlang, as `granolam.erl` in the `src` directory.
+
+You need an Erlang compiler at least at language version 4.4 to compile
+granola.erl.  This program was developed with OTP/R8B, so that is the
+recommended platform for using it, although more recent versions should
+work as well.
+
+To build the `granolam` module, run the script `make.sh`.
+
+After the module is built, run the script `granolam` in the `bin` directory
+to start a GraNoLa/M shell.
+
+To run the built-in test cases, start an Erlang shell and run
+
+    granolam:test(N).
+
+where N is an integer from 1 to 7.

File bin/granolam

View file
  • Ignore whitespace
+#!/bin/sh
+ERL_LIBS=`dirname $0`/../../ erl -noshell -run granolam shell -run init stop

File doc/GraNoLa-M.markdown

View file
  • Ignore whitespace
+GraNoLa/M - Graph Node Language Mark "M"
+========================================
+
+Introduction
+------------
+
+GraNoLa/M is a programming language that owes much of its heritage to
+Tamerlane and Q-BAL, but hints of BASIC, LISP, FORTH, SETL, Muriel, and
+Aardappel can be detected in faint outline.  It widely believed to be a
+subset of a much larger, PL/I-like language called 'GraNoLa/88800'.
+
+Data Types
+----------
+
+The basic data type in GraNoLa/M is the directed graph.  Each vertex of
+the graph (called a node) can be labelled and can contain a datum.  This
+datum is itself a graph, and thus graphs (and the namespaces which their
+labels make up) can be nested.  A graph is not the same thing as a drum.
+
+Each node is defined by its name, which must not be used elsewhere in
+this graph, and by a list of edges, connecting to either further new
+node definitions, or backreferences to previous node definitions.  Note
+that each node has an (ordered) list of edges and not just a set of
+edges; we make no pretense of these being 'proper' graphs.
+
+Actually, that different nodes have unique names and that backreferences
+must be to existing nodes are mere convention, as well.  However, we
+define here that a graph in which two nodes share the same label will
+produce undefined behaviour.  A single backreference to a non-existent
+node is a legal graph though, and this special case (called a nub) is
+regarded differently in certain roles, usually something akin to an
+'atom' in certain other languages.
+
+Syntax
+------
+
+The following EBNF exemplifies the simplicity of the grammar for this
+data type:
+
+    Graph ::= "^" ExtantName | NewName ["=" Graph] "(" {Graph} ")".
+
+That is, the syntactic representation of a graph starts with either a
+caret followed by an existing label in the graph, or it starts with a
+new label, optionally followed by an equals sign and a graph (to be
+embedded,) followed by an open paren, any number of graphs (to connect
+to), and a close paren.
+
+So, some example GraNoLa/M graphs are:
+
+    a(b(^a)c(^a)d(^a)e(^a))
+    a(b(c(d(e(^a)))))
+    a=a()(b=a(b())(^a))
+    a=b=c=d=e()()()()(^a)
+    ^potrzebie
+    a=^#potrzebie(b=^uwaming(^a))
+
+Semantics
+---------
+
+All GraNoLa/M operations work on graphs.  Actually they work on an
+internal stack of graphs - actually the stack is nothing more than a
+graph, but to avoid (and cause) confusion, we will call it a stack,
+because mainly we are concerned with putting things into it and getting
+things off of it.
+
+In truth, there is a cursor which tells us where, in graph, we should be
+pushing and popping things.
+
+Pushing a graph onto the stack entails that we add the graph, as a node,
+to a new edge in the current node in the stack, named by the cursor.
+
+Popping a graph from the stack entails that we remove the last edge
+(remember, it's an ordered list) from the current node named by the
+cursor.
+
+Execution
+---------
+
+A GraNoLa/M program is a graph.  For this reason the syntax of a legal
+GraNoLa/M program is the same as the syntax for a graph, already given.
+
+Embedded graphs within a program graph can be thought of as subprograms
+or data, depending on whether they are executed or not.
+
+Execution of a graph begins at the outermost (first defined) node. (That
+would be node `a` in most of the examples given above.)
+
+At each node, if there is an embedded graph, it is executed (in its own
+context - it uses the same stack but it has it's own set of labels.)
+
+When a nub is embedded in a node, it specifies an operation to perform
+when executed, as in the case of the example `b=^uwaming(...)` above.
+
+Execution then passes to another node.  An edge is picked by the
+traversal method (random, first, or last) and the node at the other end
+of the edge becomes the new current node.  The process repeats until a
+degenerate node (with no outgoing edges) is encountered - this halts
+execution of this (sub)program, returning to the parent program (if
+there is one.)
+
+Operations
+----------
+
+* #label - push a nub onto the stack
+* 0label - push an empty graph (node) onto the stack
+* 1label - copy node with label from program onto stack
+* @label - set the cursor to label
+* whebong - push current (sub)program onto stack
+* duronilt - pop graph and replace current (sub)program with it
+* chehy - pop graph off of stack and use it as new stack
+* taug - push stack onto stack embedded into a new node
+* soduv - pop a graph, set execution order to first if it is empty, last if not
+* rehohur - pop and discard graph
+* bimodang - pop label and jump to it as subroutine in current program graph
+* ubewic - return from current subroutine (jump back to last bimodang)
+* chuwakagathaz - switch to nondeterministic execution order (default)
+* sajalom - deterministic execution order - use first edge
+* grangnum - deterministic execution order - use last edge 
+* uwaming - pop a graph off the stack and print it
+* bejadoz - input a graph (in GraNoLa/M syntax) and push it on the stack
+

File granolam.erl

  • Ignore whitespace
--module(granolam).
--vsn('2002.0314').  % This work is a part of the public domain.
-
--export([parse/1, interpret/1, run/1, test/1, shell/0]).
-
--define(g0(X),X++S)->" "++X++" "++sub(S).
--define(g1(X),X|R0])->{Q,R1}=).
--define(g2(X),{S0,X}=pop(C,S)).
--define(g3(X),S0=push(C,S,X)).
--define(g9,++K->S0=push(C,S).
--define(y,S,C,CS).
--define(t,C,CS,M).
--define(t0,L,P,S0).
--define(l(X),list_to_atom(X)).
-
-%% Parser --------------------------------------------------------------
-
-sub(?g0("("));sub(?g0(")"));sub(?g0("^"));sub(?g0("="));
-sub([C|S])->[C]++sub(S);sub([])->[].
-lta([])->[];lta([H|T])->[?l(H)|lta(T)].
-parse(S)->{P,R}=graph(lta(string:tokens(sub(S)," "))),P.
-graph(['^',N|R0])->{N,R0};
-graph([N,?g1('=')graph(R0),['('|R2]=R1,{Q2,R3}=
-graph2(R2,[]),{{N,Q,Q2},R3};
-graph([N,?g1('(')graph2(R0,[]),{{N,nil,Q},R1}.
-graph2([')'|R0],A)->{A,R0};
-graph2(R,A)->{Q,R0}=graph(R),graph2(R0,A++[Q]).
-
-%% Interpreter ---------------------------------------------------------
-
-interpret(P)->interpret(first(P),P,{stack,nil,[]},stack,[],random).
-interpret(nil,  P,?y,M)->{?y};
-interpret(stop, P,?y,M)->{?y};
-interpret(N, P,?y,M)->
-  case find(N,P) of
-    {N,nil,L} ->
-      interpret(pick(L,M),P,?y,M);
-    {N,V,L} when atom(V)->
-      {N0,P0,S0,C0,CS0,M0} = do(N,V,P,?y,M),
-      {N1,V1,L1}=find(N0,P0),
-      case N0 of
-        N->interpret(pick(L1,M0),P0,S0,C0,CS0,M0);
-	_->interpret(N0,P0,S0,C0,CS0,M0)
-      end;	
-    {N,V,L} ->
-      {S0,C0,CS0}=interpret(first(V),V,?y,M),
-      interpret(pick(L,M),P,S0,C0,CS0,M);
-    _ ->
-      {?y}
-  end.
-
-do(L,V,P,?y,M) ->
-  case V of
-    uwaming->?g2(Q),io:fwrite("~s ",[format(Q)]),{?t0,?t};
-    bejadoz->?g3(input()),{?t0,?t};
-    duronilt->?g2(Q),{L,Q,S0,?t};
-    whebong->?g3(P),{?t0,?t};
-    taug->?g3({embed,S,[]}),{?t0,?t};
-    chehy->?g2(Q),{L,P,Q,?t};
-    bimodang->?g2(Q),case Q of
-        skip->{?t0,?t};
-	   _->{Q,P,S0,C,[L|CS],M}end;
-    ubewic->?g3(skip),[H|T]=CS,{H,P,S0,C,T,M};
-    rehohur->?g2(Q),{?t0,?t};
-    soduv->?g2(Q),case Q of
-        {_,_,[]}   ->{?t0,C,CS,first};
-	{_,_,[_|_]}->{?t0,C,CS,last};
-	          _->{?t0,?t}end;
-    chuwakagathaz->{L,P,?y,random};
-    sajalom->{L,P,?y,first};
-    grangnum->{L,P,?y,last};
-    _ ->
-      case atom_to_list(V) of
-        "#"?g9,?l(K)),{?t0,?t};
-        "0"?g9,{?l(K),nil,[]}),{?t0,?t};
-        "1"?g9,find(?l(K),P)),{?t0,?t};
-        "@"++C0->{L,P,S,?l(C0),CS,M};
-	_->{L,P,?y,M}
-      end
-  end.
-
-%% Utilities ------------------------------------------------------------
-
-first({N,S,L})->N;first(A)->A. pick([],_)->stop;pick([H|_],first)->first(H);
-pick(L,last)->first(lists:nth(length(L),L));pick(L,random)->first(lists:nth(
-random:uniform(length(L)),L)). find(N,[])->false;find(N,[H|T])->case find(N,H)
-of false->find(N,T);V->V end;find(N,{N,S,L}=P)->P;find(N,{O,S,L})->find(N,L);
-find(N,_)->false. replace(N,[],G)->[];replace(N,[H|T],G)->[replace(N,H,G)|
-replace(N,T,G)];replace(N,{N,S,L}=P,G)->G;replace(N,{O,S,L},G)->replace(N,L,G);
-replace(N,V,G)->V. push(C,S,G)->{N,D,L}=find(C,S),replace(C,S,{N,D,[G|L]}). pop
-(C, S)->case find(C,S) of{N,D,[]}->{S,nil};{N,D,[H|T]}->{replace(C,S,{N,D,T}),
-H}end. format([])->"";format(A) when atom(A)->"^"++atom_to_list(A);format([H|T])
-->format(H)++format(T);format({N,nil,L})->io_lib:format("~w(~s)",[N,format(L)])
-;format({N,V,L})->io_lib:format("~w=~s(~s)",[N,format(V),format(L)]);format(_)
-
-                                  ->"?".
-
-%% User Interface ------------------------------------------------------
-
-input()->parse(lib:nonl(io:get_line('GraNoLa/M> '))).
-run(S)->interpret(parse(S)).
-test(1)->run("a=^#cthulhu(b=^uwaming(^a))");
-test(2)->run("a=^whebong(b=^uwaming(^a))");
-test(4)->run("a=^0hello(b=^@hello(c=^taug(d=^uwaming(^a))))");
-test(5)->run("a=^1hello(b=^uwaming(end=() hello=(world())))");
-test(6)->run("a=^sajalom(b=^#d(c=^bimodang(^a))"
-             "d(e=^#sakura(f=^uwaming(g=^ubewic()))))");
-test(7)->run("a=^sajalom(b=^bejadoz(c=^soduv(^a d())))");
-test(_)->unknown_test.
-shell()->{?y}=interpret(input()),io:fwrite("~s@~w~n",[format(S),C]),
-shell().

File granolam.txt

  • Ignore whitespace
-GraNoLa/M - Graph Node Language Mark "M"
-----------------------------------------
-
-Introduction
-------------
-
-GraNoLa/M is a programming language that owes much of its heritage to
-Tamerlane and Q-BAL, but hints of BASIC, LISP, FORTH, SETL, Muriel, and
-Aardappel can be detected in faint outline.  It widely believed to be a
-subset of a much larger, PL/I-like language called 'GraNoLa/88800'.
-
-Data Types
-----------
-
-The basic data type in GraNoLa/M is the directed graph.  Each vertex of
-the graph (called a node) can be labelled and can contain a datum.  This
-datum is itself a graph, and thus graphs (and the namespaces which their
-labels make up) can be nested.  A graph is not the same thing as a drum.
-
-Each node is defined by its name, which must not be used elsewhere in
-this graph, and by a list of edges, connecting to either further new
-node definitions, or backreferences to previous node definitions.  Note
-that each node has an (ordered) list of edges and not just a set of
-edges; we make no pretense of these being 'proper' graphs.
-
-Actually, that different nodes have unique names and that backreferences
-must be to existing nodes are mere convention, as well.  However, we
-define here that a graph in which two nodes share the same label will
-produce undefined behaviour.  A single backreference to a non-existent
-node is a legal graph though, and this special case (called a nub) is
-regarded differently in certain roles, usually something akin to an
-'atom' in certain other languages.
-
-Syntax
-------
-
-The following EBNF exemplifies the simplicity of the grammar for this
-data type:
-
-  Graph ::= "^" ExtantName | NewName ["=" Graph] "(" {Graph} ")".
-
-That is, the syntactic representation of a graph starts with either a
-caret followed by an existing label in the graph, or it starts with a
-new label, optionally followed by an equals sign and a graph (to be
-embedded,) followed by an open paren, any number of graphs (to connect
-to), and a close paren.
-
-So, some example GraNoLa/M graphs are:
-
-  a(b(^a)c(^a)d(^a)e(^a))
-  a(b(c(d(e(^a)))))
-  a=a()(b=a(b())(^a))
-  a=b=c=d=e()()()()(^a)
-  ^potrzebie
-  a=^#potrzebie(b=^uwaming(^a))
-
-Semantics
----------
-
-All GraNoLa/M operations work on graphs.  Actually they work on an
-internal stack of graphs - actually the stack is nothing more than a
-graph, but to avoid (and cause) confusion, we will call it a stack,
-because mainly we are concerned with putting things into it and getting
-things off of it.
-
-In truth, there is a cursor which tells us where, in graph, we should be
-pushing and popping things.
-
-Pushing a graph onto the stack entails that we add the graph, as a node,
-to a new edge in the current node in the stack, named by the cursor.
-
-Popping a graph from the stack entails that we remove the last edge
-(remember, it's an ordered list) from the current node named by the
-cursor.
-
-Execution
----------
-
-A GraNoLa/M program is a graph.  For this reason the syntax of a legal
-GraNoLa/M program is the same as the syntax for a graph, already given.
-
-Embedded graphs within a program graph can be thought of as subprograms
-or data, depending on whether they are executed or not.
-
-Execution of a graph begins at the outermost (first defined) node. (That
-would be node 'a' in most of the examples given above.)
-
-At each node, if there is an embedded graph, it is executed (in its own
-context - it uses the same stack but it has it's own set of labels.)
-
-When a nub is embedded in a node, it specifies an operation to perform
-when executed, as in the case of the example "b=^uwaming(...)" above.
-
-Execution then passes to another node.  An edge is picked by the
-traversal method (random, first, or last) and the node at the other end
-of the edge becomes the new current node.  The process repeats until a
-degenerate node (with no outgoing edges) is encountered - this halts
-execution of this (sub)program, returning to the parent program (if
-there is one.)
-
-Operations
-----------
-
-* #label - push a nub onto the stack
-* 0label - push an empty graph (node) onto the stack
-* 1label - copy node with label from program onto stack
-* @label - set the cursor to label
-* whebong - push current (sub)program onto stack
-* duronilt - pop graph and replace current (sub)program with it
-* chehy - pop graph off of stack and use it as new stack
-* taug - push stack onto stack embedded into a new node
-* soduv - pop a graph, set execution order to first if it is empty, last if not
-* rehohur - pop and discard graph
-* bimodang - pop label and jump to it as subroutine in current program graph
-* ubewic - return from current subroutine (jump back to last bimodang)
-* chuwakagathaz - switch to nondeterministic execution order (default)
-* sajalom - deterministic execution order - use first edge
-* grangnum - deterministic execution order - use last edge 
-* uwaming - pop a graph off the stack and print it
-* bejadoz - input a graph (in GraNoLa/M syntax) and push it on the stack
-

File make.sh

View file
  • Ignore whitespace
+#!/bin/sh
+
+if [ ! -d ebin ]; then
+  mkdir ebin
+fi
+for FILE in src/*.erl; do
+  erlc -o ebin $FILE
+done

File src/granolam.erl

View file
  • Ignore whitespace
+-module(granolam).
+-vsn('2002.0314').  % This work is a part of the public domain.
+
+-export([parse/1, interpret/1, run/1, test/1, shell/0]).
+
+-define(g0(X),X++S)->" "++X++" "++sub(S).
+-define(g1(X),X|R0])->{Q,R1}=).
+-define(g2(X),{S0,X}=pop(C,S)).
+-define(g3(X),S0=push(C,S,X)).
+-define(g9,++K->S0=push(C,S).
+-define(y,S,C,CS).
+-define(t,C,CS,M).
+-define(t0,L,P,S0).
+-define(l(X),list_to_atom(X)).
+
+%% Parser --------------------------------------------------------------
+
+sub(?g0("("));sub(?g0(")"));sub(?g0("^"));sub(?g0("="));
+sub([C|S])->[C]++sub(S);sub([])->[].
+lta([])->[];lta([H|T])->[?l(H)|lta(T)].
+parse(S)->{P,R}=graph(lta(string:tokens(sub(S)," "))),P.
+graph(['^',N|R0])->{N,R0};
+graph([N,?g1('=')graph(R0),['('|R2]=R1,{Q2,R3}=
+graph2(R2,[]),{{N,Q,Q2},R3};
+graph([N,?g1('(')graph2(R0,[]),{{N,nil,Q},R1}.
+graph2([')'|R0],A)->{A,R0};
+graph2(R,A)->{Q,R0}=graph(R),graph2(R0,A++[Q]).
+
+%% Interpreter ---------------------------------------------------------
+
+interpret(P)->interpret(first(P),P,{stack,nil,[]},stack,[],random).
+interpret(nil,  P,?y,M)->{?y};
+interpret(stop, P,?y,M)->{?y};
+interpret(N, P,?y,M)->
+  case find(N,P) of
+    {N,nil,L} ->
+      interpret(pick(L,M),P,?y,M);
+    {N,V,L} when atom(V)->
+      {N0,P0,S0,C0,CS0,M0} = do(N,V,P,?y,M),
+      {N1,V1,L1}=find(N0,P0),
+      case N0 of
+        N->interpret(pick(L1,M0),P0,S0,C0,CS0,M0);
+	_->interpret(N0,P0,S0,C0,CS0,M0)
+      end;	
+    {N,V,L} ->
+      {S0,C0,CS0}=interpret(first(V),V,?y,M),
+      interpret(pick(L,M),P,S0,C0,CS0,M);
+    _ ->
+      {?y}
+  end.
+
+do(L,V,P,?y,M) ->
+  case V of
+    uwaming->?g2(Q),io:fwrite("~s ",[format(Q)]),{?t0,?t};
+    bejadoz->?g3(input()),{?t0,?t};
+    duronilt->?g2(Q),{L,Q,S0,?t};
+    whebong->?g3(P),{?t0,?t};
+    taug->?g3({embed,S,[]}),{?t0,?t};
+    chehy->?g2(Q),{L,P,Q,?t};
+    bimodang->?g2(Q),case Q of
+        skip->{?t0,?t};
+	   _->{Q,P,S0,C,[L|CS],M}end;
+    ubewic->?g3(skip),[H|T]=CS,{H,P,S0,C,T,M};
+    rehohur->?g2(Q),{?t0,?t};
+    soduv->?g2(Q),case Q of
+        {_,_,[]}   ->{?t0,C,CS,first};
+	{_,_,[_|_]}->{?t0,C,CS,last};
+	          _->{?t0,?t}end;
+    chuwakagathaz->{L,P,?y,random};
+    sajalom->{L,P,?y,first};
+    grangnum->{L,P,?y,last};
+    _ ->
+      case atom_to_list(V) of
+        "#"?g9,?l(K)),{?t0,?t};
+        "0"?g9,{?l(K),nil,[]}),{?t0,?t};
+        "1"?g9,find(?l(K),P)),{?t0,?t};
+        "@"++C0->{L,P,S,?l(C0),CS,M};
+	_->{L,P,?y,M}
+      end
+  end.
+
+%% Utilities ------------------------------------------------------------
+
+first({N,S,L})->N;first(A)->A. pick([],_)->stop;pick([H|_],first)->first(H);
+pick(L,last)->first(lists:nth(length(L),L));pick(L,random)->first(lists:nth(
+random:uniform(length(L)),L)). find(N,[])->false;find(N,[H|T])->case find(N,H)
+of false->find(N,T);V->V end;find(N,{N,S,L}=P)->P;find(N,{O,S,L})->find(N,L);
+find(N,_)->false. replace(N,[],G)->[];replace(N,[H|T],G)->[replace(N,H,G)|
+replace(N,T,G)];replace(N,{N,S,L}=P,G)->G;replace(N,{O,S,L},G)->replace(N,L,G);
+replace(N,V,G)->V. push(C,S,G)->{N,D,L}=find(C,S),replace(C,S,{N,D,[G|L]}). pop
+(C, S)->case find(C,S) of{N,D,[]}->{S,nil};{N,D,[H|T]}->{replace(C,S,{N,D,T}),
+H}end. format([])->"";format(A) when atom(A)->"^"++atom_to_list(A);format([H|T])
+->format(H)++format(T);format({N,nil,L})->io_lib:format("~w(~s)",[N,format(L)])
+;format({N,V,L})->io_lib:format("~w=~s(~s)",[N,format(V),format(L)]);format(_)
+
+                                  ->"?".
+
+%% User Interface ------------------------------------------------------
+
+input()->parse(lib:nonl(io:get_line('GraNoLa/M> '))).
+run(S)->interpret(parse(S)).
+test(1)->run("a=^#cthulhu(b=^uwaming(^a))");
+test(2)->run("a=^whebong(b=^uwaming(^a))");
+test(4)->run("a=^0hello(b=^@hello(c=^taug(d=^uwaming(^a))))");
+test(5)->run("a=^1hello(b=^uwaming(end=() hello=(world())))");
+test(6)->run("a=^sajalom(b=^#d(c=^bimodang(^a))"
+             "d(e=^#sakura(f=^uwaming(g=^ubewic()))))");
+test(7)->run("a=^sajalom(b=^bejadoz(c=^soduv(^a d())))");
+test(_)->unknown_test.
+shell()->{?y}=interpret(input()),io:fwrite("~s@~w~n",[format(S),C]),
+shell().