diff --git a/README b/README new file mode 100755 index 0000000..4e01ee6 --- /dev/null +++ b/README @@ -0,0 +1,28 @@ +The Sbeezg Programming Language v2002.0317 +------------------------------- + +Sbeezg is single-assignment programming taken to the extreme. Each variable +may only be assigned once. There is no scope. When a function is executed, +a new copy of it is made, with all bound variable names altered to fresh ones, +and this is executed instead. Execution is sequential in nature. Arguments +and return value are given explicitly. There are no global names; there are +only lambda function definitions available. There are five built-in operations. +For convenience, there are three data types: atoms, integers, and closures. + +Here is a brief EBNF rundown of the syntax: + +Appl ::= Name "=" Val "(" Val {"," Val} ")". +Val ::= Name | "*" Const | "{" Name {"," Name} "|" Appl {";" Appl} "|" Name "}". + +A program is an application, which consists of an assignment to a new (never +before named in the program) variable, of a value or the result of a function +call. Note that the arguments of a function call may only be simple values; +further nested function calls are disallowed as their implicit 'piping' of +values from one function to the next without an intervening variable name is +counter to the intention of this purely single-assignment language. + +This documentation isn't really complete. + +Chris Pressey +March 17 2002 +Winnipeg, Manitoba diff --git a/doc/sbeezg.html b/doc/sbeezg.html new file mode 100644 index 0000000..a9c4e24 --- /dev/null +++ b/doc/sbeezg.html @@ -0,0 +1,33 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html> +<head> +<title>Module sbeezg</title> +</head> +<body bgcolor="white"> +<h1>Module sbeezg</h1> +<ul><li> +<a href="#index">Function index</a></li><li> +<a href="#exported">Exported functions</a></li></ul> + +<h2>Description</h2> + + +<h2><a name="index">Function Index</a></h2> + +<table width="100%" border="1"><tr><th colspan="2" align="left">Exported Functions</th></tr> +<tr><td><a href="#run-1">run/1</a></td><td/></tr> +<tr><td><a href="#test-1">test/1</a></td><td/></tr> +</table> + +<h2><a name="exported">Exported Functions</a></h2> + +<h3><a name="run-1">run/1</a></h3> + +<p><code>run(Arg1) -> term()</code></p> +<p> </p> + +<h3><a name="test-1">test/1</a></h3> + +<p><code>test(Arg1) -> term()</code></p> +<p> </p></body> +</html> \ No newline at end of file diff --git a/doc/sbeezg_parser.html b/doc/sbeezg_parser.html new file mode 100644 index 0000000..ef635b5 --- /dev/null +++ b/doc/sbeezg_parser.html @@ -0,0 +1,39 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html> +<head> +<title>Module sbeezg_parser</title> +</head> +<body bgcolor="white"> +<h1>Module sbeezg_parser</h1> +<ul><li> +<a href="#index">Function index</a></li><li> +<a href="#exported">Exported functions</a></li></ul> + +<h2>Description</h2> + + +<h2><a name="index">Function Index</a></h2> + +<table width="100%" border="1"><tr><th colspan="2" align="left">Exported Functions</th></tr> +<tr><td><a href="#format_error-1">format_error/1</a></td><td/></tr> +<tr><td><a href="#parse-1">parse/1</a></td><td/></tr> +<tr><td><a href="#parse_and_scan-1">parse_and_scan/1</a></td><td/></tr> +</table> + +<h2><a name="exported">Exported Functions</a></h2> + +<h3><a name="format_error-1">format_error/1</a></h3> + +<p><code>format_error(Arg1) -> term()</code></p> +<p> </p> + +<h3><a name="parse-1">parse/1</a></h3> + +<p><code>parse(Arg1) -> term()</code></p> +<p> </p> + +<h3><a name="parse_and_scan-1">parse_and_scan/1</a></h3> + +<p><code>parse_and_scan(Arg1) -> term()</code></p> +<p> </p></body> +</html> \ No newline at end of file diff --git a/ebin/sbeezg.app b/ebin/sbeezg.app new file mode 100755 index 0000000..dd7b409 --- /dev/null +++ b/ebin/sbeezg.app @@ -0,0 +1,8 @@ +{application,sbeezg, + [{description,"The Sbeezg Programming Language"}, + {vsn,"2002.0317"}, + {modules,[sbeezg, sbeezg_parser]}, + {registered,[]}, + {env,[]}, + {applications,[kernel,stdlib]}]}. + diff --git a/ebin/sbeezg.beam b/ebin/sbeezg.beam new file mode 100755 index 0000000..7af0ed2 Binary files /dev/null and b/ebin/sbeezg.beam differ diff --git a/ebin/sbeezg_parser.beam b/ebin/sbeezg_parser.beam new file mode 100755 index 0000000..b1e6bc4 Binary files /dev/null and b/ebin/sbeezg_parser.beam differ diff --git a/src/sbeezg.erl b/src/sbeezg.erl new file mode 100755 index 0000000..0e15d07 --- /dev/null +++ b/src/sbeezg.erl @@ -0,0 +1,189 @@ +-module(sbeezg). +-vsn('2002.0317'). +-author('cpressey@catseye.mb.ca'). +-copyright('Copyright (c)2002 Cat`s Eye Technologies. All rights reserved.'). + +%%% Redistribution and use in source and binary forms, with or without +%%% modification, are permitted provided that the following conditions +%%% are met: +%%% +%%% Redistributions of source code must retain the above copyright +%%% notice, this list of conditions and the following disclaimer. +%%% +%%% 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. +%%% +%%% Neither the name of Cat's Eye Technologies 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 REGENTS 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. + +-export([run/1, test/1]). + +%%% BEGIN sbeezg.erl %%% + +%%% A simple interpreter for the Sbeezg Programming Language. + +%% Interpreter --------------------------------------------------------- +%% Call sbeezg:run("sbeezg-program") to interpret a Sbeezg program. +%% Empties the process dictionary as a side effect. + +run(String) when list(String) -> + {ok, Toks, N} = erl_scan:string(String), + % io:fwrite("scan: ~s -> ~w~n", [String, Toks]), + erase(), % clear process dictionary for parser + case sbeezg_parser:parse(Toks ++ [{'$end',999}]) of + {ok, Prog} -> + % io:fwrite("parse: ~s -> ~w~n", [String, Prog]), + erase(), % destroy the garbage left in the process dictionary + run(Prog); + {error, {Line, Module, Message}}=Q -> + io:fwrite("Error: ~s~n", [Message]), + Q + end; +run({assign, L, F, A}=C) -> + % io:fwrite("~w~n", [C]), + L0 = get_name(L), + F0 = run(F), + A0 = run(A), + assign(L0, '$placeholder'), + R0 = execute(F0, A0), + assign(L0, R0); +run({assign, L, R}=C) -> + % io:fwrite("~w~n", [C]), + L0 = get_name(L), + R0 = run(R), + assign(L0, R0); +run({vlist, H, T}=C) -> + % io:fwrite("~w~n", [C]), + H0 = run(H), + T0 = run(T), + [H0 | T0]; +run({lambda, N, A, R}=C) -> + % io:fwrite("~w~n", [C]), + {func, N, A, R}; +run({alist, H, T}=C) -> + % io:fwrite("~w~n", [C]), + H0 = run(H), + T0 = run(T), + case T0 of + [] -> H0; + _ -> T0 + end; +run({lit,{atom,Line,Atom}}) -> Atom; +run({lit,{integer,Line,Int}}) -> Int; +run({name, {atom,Line,Atom}}) -> + case get(Atom) of + undefined -> + io:fwrite("~w undefined!~n", [Atom]), + Atom; + N -> + N + end; +run(nil) -> + []; +run(Q) -> + io:fwrite("UNKNOWN ~w~n", [Q]), + unknown. + +get_name({nlist, H, T}=C) -> + % io:fwrite("~w~n", [C]), + H0 = get_name(H), + T0 = get_name(T), + [H0 | T0]; +get_name({name, {atom,Line,Atom}}) -> Atom; +get_name(nil) -> []. + +%% Utility ------------------------------------------------------------- + +assign(Name, Value) -> + % io:fwrite("Assigning ~w to ~w~n", [Value, Name]), + case get(Name) of + NonExist when NonExist == undefined; NonExist == '$placeholder' -> + put(Name, Value); + Exist -> + io:fwrite("ERROR: Multiple Assignment to ~w=~w (~w)~n", + [Name, Exist, Value]) + end, + Value. + +execute(print, [H | T]) -> + io:fwrite("~w", [H]), + execute(print, T); +execute(print, []) -> ok; +execute(is, [A, B, T, F]) -> + % io:fwrite("~w", [C]), + case A of + B -> T; + _ -> F + end; +execute(pred, [X]) -> + % io:fwrite("pred ~w~n", [X]), + X - 1; +execute(succ, [X]) -> X + 1; +execute(Func, Args) when atom(Func) -> + io:fwrite("Unknown built-in '~w(~w)'~n", [Func, Args]), + unknown; +execute({func, P, B, R}, A) -> + P0 = fresh(P), + B0 = fresh(B), + P1 = get_name(P0), + bind(P1, A), + run(B0), + run(R). + +fresh({assign, L, F, A}=C) -> {assign, fresh(L), fresh(F), fresh(A)}; +fresh({assign, L, R}=C) -> {assign, fresh(L), fresh(R)}; +fresh({vlist, H, T}=C) -> {vlist, fresh(H), fresh(T)}; +fresh({lambda, X, A}=C) -> {lambda, fresh(X), fresh(A)}; +fresh({nlist, H, T}=C) -> {nlist, fresh(H), fresh(T)}; +fresh({alist, H, T}=C) -> {alist, fresh(H), fresh(T)}; +fresh({lit,X}=C) -> C; +fresh({name,{atom,Line,Atom}}=C) -> + case get(Atom) of + undefined -> C; + _ -> + fresh({name, {atom, Line, list_to_atom([$_ | atom_to_list(Atom)])}}) + end; +fresh(X) -> X. + +bind([],[]) -> ok; +bind([HN|TN],[HV|TV]) -> + % io:fwrite("bind ~w to ~w~n", [HV,HN]), + assign(HN,HV), + bind(TN,TV). + +%% User interface ------------------------------------------------------ + +test([N]) -> test(list_to_integer(N)); +test(N) -> + R = run(prg(N)), + E = erase(), + {R, E}. + +prg(1) -> "a={b|p=*print;c=p(b)|b};d=a(*foo);e=a(*bar);f=a(*baz)"; +prg(2) -> "a={b|p=*print;c=p(b)|b};d={e,f|g=e(f)|g};h=d(a,*hello)"; +prg(3) -> "p=*print;i=*is;r=i(*a,*b,*troo,*fall);q=p(r)"; +prg(4) -> "f={a,b|p=*print;g=p(a);k=b(a,b)|a};l=f(*hello,f)"; +prg(5) -> "f={a,b|i=*is;s=*pred;p=*print;g=p(*beer);h=s(a);" + "ln={x,m|z=x|x};lg={y,n|q=n(y,n)|y};j=i(h,0,ln,lg);" + "k=j(h,b)|a};l=f(99,f)"; +prg(6) -> "f=*a;f=*b"; % intentionally erroneous +prg(_) -> unknown. + +%%% END of sbeezg.erl %%% diff --git a/src/sbeezg_parser.erl b/src/sbeezg_parser.erl new file mode 100755 index 0000000..48ad812 --- /dev/null +++ b/src/sbeezg_parser.erl @@ -0,0 +1,326 @@ +-module(sbeezg_parser). +-define(THIS_MODULE, sbeezg_parser). +-export([parse/1, parse_and_scan/1, format_error/1]). + +new_name({name,{atom,Line,Name}}=A) -> + case get(A) of + defn -> + return_error(0, io_lib:format("Name '~w' already defined", [Name])); + _ -> + put(A, defn) + end. + +existing_name({name,{atom,Line,Name}}=A) -> + case get(A) of + undefined -> + return_error(0, io_lib:format("Name '~w' is not yet defined", [Name])); + _ -> + ok + end. + +%%% END of sbeezg_parser.yrl %%% + +%% ``The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved via the world wide web at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% The Initial Developer of the Original Code is Ericsson Utvecklings AB. +%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings +%% AB. All Rights Reserved.'' +%% +%% $Id$ +%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% The parser generator will insert appropriate declarations before this line.% + +parse(Tokens) -> + case catch yeccpars1(Tokens, false, 0, [], []) of + error -> + Errorline = + if Tokens == [] -> 0; true -> element(2, hd(Tokens)) end, + {error, + {Errorline, ?THIS_MODULE, "syntax error at or after this line."}}; + Other -> + Other + end. + +parse_and_scan({Mod, Fun, Args}) -> + case apply(Mod, Fun, Args) of + {eof, _} -> + {ok, eof}; + {error, Descriptor, _} -> + {error, Descriptor}; + {ok, Tokens, _} -> + yeccpars1(Tokens, {Mod, Fun, Args}, 0, [], []) + end. + +format_error(Message) -> + case io_lib:deep_char_list(Message) of + true -> + Message; + _ -> + io_lib:write(Message) + end. + +% To be used in grammar files to throw an error message to the parser toplevel. +% Doesn't have to be exported! +return_error(Line, Message) -> + throw({error, {Line, ?THIS_MODULE, Message}}). + + +% Don't change yeccpars1/6 too much, it is called recursively by yeccpars2/8! +yeccpars1([Token | Tokens], Tokenizer, State, States, Vstack) -> + yeccpars2(State, element(1, Token), States, Vstack, Token, Tokens, + Tokenizer); +yeccpars1([], {M, F, A}, State, States, Vstack) -> + case catch apply(M, F, A) of + {eof, Endline} -> + {error, {Endline, ?THIS_MODULE, "end_of_file"}}; + {error, Descriptor, Endline} -> + {error, Descriptor}; + {'EXIT', Reason} -> + {error, {0, ?THIS_MODULE, Reason}}; + {ok, Tokens, Endline} -> + case catch yeccpars1(Tokens, {M, F, A}, State, States, Vstack) of + error -> + Errorline = element(2, hd(Tokens)), + {error, {Errorline, ?THIS_MODULE, + "syntax error at or after this line."}}; + Other -> + Other + end + end; +yeccpars1([], false, State, States, Vstack) -> + yeccpars2(State, '$end', States, Vstack, {'$end', 999999}, [], false). + +% For internal use only. +yeccerror(Token) -> + {error, + {element(2, Token), ?THIS_MODULE, + ["syntax error before: ", yecctoken2string(Token)]}}. + +yecctoken2string({atom, _, A}) -> io_lib:write(A); +yecctoken2string({integer,_,N}) -> io_lib:write(N); +yecctoken2string({float,_,F}) -> io_lib:write(F); +yecctoken2string({char,_,C}) -> io_lib:write_char(C); +yecctoken2string({var,_,V}) -> io_lib:format('~s', [V]); +yecctoken2string({string,_,S}) -> io_lib:write_string(S); +yecctoken2string({reserved_symbol, _, A}) -> io_lib:format('~w', [A]); +yecctoken2string({Cat, _, Val}) -> io_lib:format('~w', [Val]); + +yecctoken2string({'dot', _}) -> io_lib:format('~w', ['.']); +yecctoken2string({'$end', _}) -> + []; +yecctoken2string({Other, _}) when atom(Other) -> + io_lib:format('~w', [Other]); +yecctoken2string(Other) -> + io_lib:write(Other). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +yeccpars2(0, atom, __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 3, [0 | __Ss], [__T | __Stack]); +yeccpars2(0, _, _, _, __T, _, _) -> + yeccerror(__T); +yeccpars2(1, '$end', _, __Stack, _, _, _) -> + {ok, hd(__Stack)}; +yeccpars2(1, _, _, _, __T, _, _) -> + yeccerror(__T); +yeccpars2(2, ';', __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 27, [2 | __Ss], [__T | __Stack]); +yeccpars2(2, __Cat, __Ss, [__1|__Stack], __T, __Ts, __Tzr) -> + __Val = {alist,__1,nil}, + yeccpars2(yeccgoto(alist, hd(__Ss)), __Cat, __Ss, [__Val | __Stack], __T, __Ts, __Tzr); +yeccpars2(3, __Cat, __Ss, [__1|__Stack], __T, __Ts, __Tzr) -> + __Val = {name,__1}, + yeccpars2(yeccgoto(name, hd(__Ss)), __Cat, __Ss, [__Val | __Stack], __T, __Ts, __Tzr); +yeccpars2(4, '=', __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 5, [4 | __Ss], [__T | __Stack]); +yeccpars2(4, _, _, _, __T, _, _) -> + yeccerror(__T); +yeccpars2(5, atom, __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 3, [5 | __Ss], [__T | __Stack]); +yeccpars2(5, integer, __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 7, [5 | __Ss], [__T | __Stack]); +yeccpars2(5, '*', __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 6, [5 | __Ss], [__T | __Stack]); +yeccpars2(5, '{', __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 10, [5 | __Ss], [__T | __Stack]); +yeccpars2(5, _, _, _, __T, _, _) -> + yeccerror(__T); +yeccpars2(6, atom, __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 26, [6 | __Ss], [__T | __Stack]); +yeccpars2(6, _, _, _, __T, _, _) -> + yeccerror(__T); +yeccpars2(7, __Cat, __Ss, [__1|__Stack], __T, __Ts, __Tzr) -> + __Val = {lit,__1}, + yeccpars2(yeccgoto(val, hd(__Ss)), __Cat, __Ss, [__Val | __Stack], __T, __Ts, __Tzr); +yeccpars2(8, __Cat, __Ss, [__1|__Stack], __T, __Ts, __Tzr) -> + __Val = begin + existing_name(__1), __1 + end, + yeccpars2(yeccgoto(val, hd(__Ss)), __Cat, __Ss, [__Val | __Stack], __T, __Ts, __Tzr); +yeccpars2(9, '(', __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 20, [9 | __Ss], [__T | __Stack]); +yeccpars2(9, __Cat, __Ss, [__3,__2,__1|__Stack], __T, __Ts, __Tzr) -> + __Val = begin + new_name(__1), {assign,__1,__3} + end, + __Nss = lists:nthtail(2, __Ss), + yeccpars2(yeccgoto(appl, hd(__Nss)), __Cat, __Nss, [__Val | __Stack], __T, __Ts, __Tzr); +yeccpars2(10, atom, __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 3, [10 | __Ss], [__T | __Stack]); +yeccpars2(10, _, _, _, __T, _, _) -> + yeccerror(__T); +yeccpars2(11, ',', __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 18, [11 | __Ss], [__T | __Stack]); +yeccpars2(11, __Cat, __Ss, [__1|__Stack], __T, __Ts, __Tzr) -> + __Val = begin + new_name(__1), {nlist,__1,nil} + end, + yeccpars2(yeccgoto(nlist, hd(__Ss)), __Cat, __Ss, [__Val | __Stack], __T, __Ts, __Tzr); +yeccpars2(12, '|', __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 13, [12 | __Ss], [__T | __Stack]); +yeccpars2(12, _, _, _, __T, _, _) -> + yeccerror(__T); +yeccpars2(13, atom, __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 3, [13 | __Ss], [__T | __Stack]); +yeccpars2(13, _, _, _, __T, _, _) -> + yeccerror(__T); +yeccpars2(14, '|', __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 15, [14 | __Ss], [__T | __Stack]); +yeccpars2(14, _, _, _, __T, _, _) -> + yeccerror(__T); +yeccpars2(15, atom, __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 3, [15 | __Ss], [__T | __Stack]); +yeccpars2(15, _, _, _, __T, _, _) -> + yeccerror(__T); +yeccpars2(16, '}', __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 17, [16 | __Ss], [__T | __Stack]); +yeccpars2(16, _, _, _, __T, _, _) -> + yeccerror(__T); +yeccpars2(17, __Cat, __Ss, [__7,__6,__5,__4,__3,__2,__1|__Stack], __T, __Ts, __Tzr) -> + __Val = {lambda,__2,__4,__6}, + __Nss = lists:nthtail(6, __Ss), + yeccpars2(yeccgoto(val, hd(__Nss)), __Cat, __Nss, [__Val | __Stack], __T, __Ts, __Tzr); +yeccpars2(18, atom, __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 3, [18 | __Ss], [__T | __Stack]); +yeccpars2(18, _, _, _, __T, _, _) -> + yeccerror(__T); +yeccpars2(19, __Cat, __Ss, [__3,__2,__1|__Stack], __T, __Ts, __Tzr) -> + __Val = begin + new_name(__1), {nlist,__1,__3} + end, + __Nss = lists:nthtail(2, __Ss), + yeccpars2(yeccgoto(nlist, hd(__Nss)), __Cat, __Nss, [__Val | __Stack], __T, __Ts, __Tzr); +yeccpars2(20, atom, __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 3, [20 | __Ss], [__T | __Stack]); +yeccpars2(20, integer, __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 7, [20 | __Ss], [__T | __Stack]); +yeccpars2(20, '*', __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 6, [20 | __Ss], [__T | __Stack]); +yeccpars2(20, '{', __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 10, [20 | __Ss], [__T | __Stack]); +yeccpars2(20, _, _, _, __T, _, _) -> + yeccerror(__T); +yeccpars2(21, ',', __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 24, [21 | __Ss], [__T | __Stack]); +yeccpars2(21, __Cat, __Ss, [__1|__Stack], __T, __Ts, __Tzr) -> + __Val = {vlist,__1,nil}, + yeccpars2(yeccgoto(vlist, hd(__Ss)), __Cat, __Ss, [__Val | __Stack], __T, __Ts, __Tzr); +yeccpars2(22, ')', __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 23, [22 | __Ss], [__T | __Stack]); +yeccpars2(22, _, _, _, __T, _, _) -> + yeccerror(__T); +yeccpars2(23, __Cat, __Ss, [__6,__5,__4,__3,__2,__1|__Stack], __T, __Ts, __Tzr) -> + __Val = begin + new_name(__1), {assign,__1,__3,__5} + end, + __Nss = lists:nthtail(5, __Ss), + yeccpars2(yeccgoto(appl, hd(__Nss)), __Cat, __Nss, [__Val | __Stack], __T, __Ts, __Tzr); +yeccpars2(24, atom, __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 3, [24 | __Ss], [__T | __Stack]); +yeccpars2(24, integer, __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 7, [24 | __Ss], [__T | __Stack]); +yeccpars2(24, '*', __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 6, [24 | __Ss], [__T | __Stack]); +yeccpars2(24, '{', __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 10, [24 | __Ss], [__T | __Stack]); +yeccpars2(24, _, _, _, __T, _, _) -> + yeccerror(__T); +yeccpars2(25, __Cat, __Ss, [__3,__2,__1|__Stack], __T, __Ts, __Tzr) -> + __Val = {vlist,__1,__3}, + __Nss = lists:nthtail(2, __Ss), + yeccpars2(yeccgoto(vlist, hd(__Nss)), __Cat, __Nss, [__Val | __Stack], __T, __Ts, __Tzr); +yeccpars2(26, __Cat, __Ss, [__2,__1|__Stack], __T, __Ts, __Tzr) -> + __Val = {lit,__2}, + __Nss = lists:nthtail(1, __Ss), + yeccpars2(yeccgoto(val, hd(__Nss)), __Cat, __Nss, [__Val | __Stack], __T, __Ts, __Tzr); +yeccpars2(27, atom, __Ss, __Stack, __T, __Ts, __Tzr) -> + yeccpars1(__Ts, __Tzr, 3, [27 | __Ss], [__T | __Stack]); +yeccpars2(27, _, _, _, __T, _, _) -> + yeccerror(__T); +yeccpars2(28, __Cat, __Ss, [__3,__2,__1|__Stack], __T, __Ts, __Tzr) -> + __Val = {alist,__1,__3}, + __Nss = lists:nthtail(2, __Ss), + yeccpars2(yeccgoto(alist, hd(__Nss)), __Cat, __Nss, [__Val | __Stack], __T, __Ts, __Tzr); +yeccpars2(__Other, _, _, _, _, _, _) -> + exit({parser, __Other, missing_state_in_action_table}). + +yeccgoto(alist, 0) -> + 1; +yeccgoto(alist, 13) -> + 14; +yeccgoto(alist, 27) -> + 28; +yeccgoto(appl, 0) -> + 2; +yeccgoto(appl, 13) -> + 2; +yeccgoto(appl, 27) -> + 2; +yeccgoto(name, 0) -> + 4; +yeccgoto(name, 5) -> + 8; +yeccgoto(name, 10) -> + 11; +yeccgoto(name, 13) -> + 4; +yeccgoto(name, 15) -> + 16; +yeccgoto(name, 18) -> + 11; +yeccgoto(name, 20) -> + 8; +yeccgoto(name, 24) -> + 8; +yeccgoto(name, 27) -> + 4; +yeccgoto(nlist, 10) -> + 12; +yeccgoto(nlist, 18) -> + 19; +yeccgoto(val, 5) -> + 9; +yeccgoto(val, 20) -> + 21; +yeccgoto(val, 24) -> + 21; +yeccgoto(vlist, 20) -> + 22; +yeccgoto(vlist, 24) -> + 25; +yeccgoto(__Symbol, __State) -> + exit({__Symbol, __State, missing_in_goto_table}). + + diff --git a/src/sbeezg_parser.yrl b/src/sbeezg_parser.yrl new file mode 100755 index 0000000..9bc2863 --- /dev/null +++ b/src/sbeezg_parser.yrl @@ -0,0 +1,85 @@ +%%% -grammar(sbeezg_parser). +%%% -vsn('2002.0317'). +%%% -author('cpressey@catseye.mb.ca'). +%%% -copyright('Copyright (c)2002 Cat`s Eye Technologies. All rights reserved.'). + +%%% Redistribution and use in source and binary forms, with or without +%%% modification, are permitted provided that the following conditions +%%% are met: +%%% +%%% Redistributions of source code must retain the above copyright +%%% notice, this list of conditions and the following disclaimer. +%%% +%%% 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. +%%% +%%% Neither the name of Cat's Eye Technologies 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 REGENTS 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. + +%%% BEGIN sbeezg_parser.yrl %%% + +Nonterminals vlist val nlist name alist appl. +Terminals '=' '*' '(' ')' '{' '|' '}' ',' ';' atom integer. +Rootsymbol alist. + +%%% EBNF: +%%% Appl ::= Name "=" Val "(" Val {"," Val} ")". +%%% Val ::= Name | "*" Const | "{" Name {"," Name} "|" Appl {";" Appl} "|" Name "}". + +%%% Recursive Version (no {}'s): +%%% Appl ::= Name "=" Val ["(" Vlist ")"]. +%%% Vlist ::= Val ["," Vlist]. +%%% Val ::= Name | "*" Name | "{" Nlist "|" Alist "|" Name "}". +%%% Nlist ::= Name ["," Nlist]. +%%% Alist ::= Appl [";" Alist]. + +appl -> name '=' val '(' vlist ')' : new_name('$1'), {assign, '$1', '$3', '$5'}. +appl -> name '=' val : new_name('$1'), {assign, '$1', '$3'}. +vlist -> val ',' vlist : {vlist, '$1', '$3'}. +vlist -> val : {vlist, '$1', nil}. +val -> '{' nlist '|' alist '|' name '}' : {lambda, '$2', '$4', '$6'}. +val -> '*' atom : {lit, '$2'}. +val -> integer : {lit, '$1'}. +val -> name : existing_name('$1'), '$1'. +nlist -> name ',' nlist : new_name('$1'), {nlist, '$1', '$3'}. +nlist -> name : new_name('$1'), {nlist, '$1', nil}. +alist -> appl ';' alist : {alist, '$1', '$3'}. +alist -> appl : {alist, '$1', nil}. +name -> atom : {name, '$1'}. + +Erlang code. + +new_name({name,{atom,Line,Name}}=A) -> + case get(A) of + defn -> + return_error(0, io_lib:format("Name '~w' already defined", [Name])); + _ -> + put(A, defn) + end. + +existing_name({name,{atom,Line,Name}}=A) -> + case get(A) of + undefined -> + return_error(0, io_lib:format("Name '~w' is not yet defined", [Name])); + _ -> + ok + end. + +%%% END of sbeezg_parser.yrl %%%