-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
commit of Poe v 1.02 from old Sourceforge release
- Loading branch information
0 parents
commit c8ccf84
Showing
47 changed files
with
19,176 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
all: pdata.c puniverse.c pmem.c pdo1.c pdo2.c pexec.c pbc.c pgc.c lex.yy.c y.tab.c pstd.c pio.c pmath.c pstring.c pmain.c | ||
gcc pdata.c puniverse.c pmem.c pdo1.c pdo2.c pexec.c pbc.c pgc.c lex.yy.c y.tab.c pstd.c pio.c pmath.c pstring.c pmain.c -lm -o pint |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
To quickly get started with Poe, simply perform a "make", and then call the | ||
executable pint with the name of one of the example scripts. The given | ||
example scripts are: | ||
|
||
sum.poe: Sums all integers passed to the script as command line options. | ||
try: pint sum.poe 3 4 5 | ||
echo.poe: A simple implementation of the echo command line tool. | ||
try: pint echo.poe hello world | ||
file.poe: Consumes a filename as a command line argument and echoes the | ||
contents of that file, capitalized. | ||
try: pint file.poe pmain.c | ||
|
||
The following files are less useful as command line tools, but are more | ||
interesting to read in terms of the features of the language. | ||
|
||
require.poe: Loads a package for "smart arrays" from smart.poe and does some | ||
operations with it. See smart.poe for the implementation. | ||
try: pint require.poe | ||
scope.poe: Quickly presents some of the more interesting quirks of Poe's | ||
approach to lexical scoping. To understand the program's output, | ||
make sure to follow along with the source code, which is heavily | ||
commented. | ||
try: pint scope.poe | ||
blocks.poe: This script is low on code but heavy on comments; it is a | ||
discussion of Poe's blocks and code objects. | ||
std.poe: The Poe implementation of a number of the standard library's functions | ||
are given here. The compiled bytecode is built-in to the Poe | ||
interpreter, so it would be redundant to execute this as a script; | ||
nevertheless, it may be interesting to browse the source code. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
VERSION INFO: | ||
Poe v. 1.0.2 has been released. There have been numerous bug fixes, | ||
particularly to the garbage collector, and I have included a documentation | ||
file 1000lines.txt which will serve, for now, as non-comprehensive documentation of the language. | ||
|
||
--- | ||
|
||
The Poe programming language is now in the Alpha release stage. As testing | ||
continues, more minor bugs are bound to be caught; I encourage you to | ||
contact me if you do find any. Included in this directory are example | ||
scripts that have demonstrated to work very reliably. | ||
|
||
To quickly get started with Poe, see the included QUICKSTART document. | ||
|
||
The process of building the language should be self-evident: an extremely | ||
simple Makefile is included, which you may edit to serve your needs. | ||
The executable that will be built is called "pint", for "Poe interpreter"; | ||
to execute a script, do | ||
|
||
pint scriptname.poe | ||
|
||
Explicit per-script instructions are given in each script. The scripts | ||
serve to demonstrate a number of the language's features, including | ||
I/O and command line interaction, metatables, and a unique approach | ||
to lexical scoping. More comprehensive documentation of the language and | ||
its operators/features is forthcoming. | ||
|
||
As a side note, be aware that executing a script leaves a "remnant" bytecode | ||
file with a .pbc extension; for example, executing scope.poe will leave a | ||
scope.pbc file after execution. These bytecode files can be safely deleted. | ||
|
||
SOURCE CODE | ||
pdata.h | ||
pdata.c -- Basic functions for keying Poe structures | ||
puniverse.h | ||
puniverse.c -- Basic functions for creating Poe universes | ||
pmem.h | ||
pmem.c -- Basic functions for memory allocation | ||
pbc.h | ||
pbc.c -- Bytecode compilation | ||
pgc.h | ||
pgc.c -- Garbage collector | ||
pexec.h | ||
pexec.c -- Functions for bytecode execution | ||
pdo1.h | ||
pdo1.c -- Instruction execution, pt. 1 | ||
pdo2.h | ||
pdo2.c -- Instruction execution, pt. 2 | ||
y.tab.h | ||
y.tab.c -- Bison-generated parser | ||
lex.yy.h | ||
lex.yy.c -- Flex-generated lexer | ||
pio.h | ||
pio.c -- I/O library | ||
pstd.h | ||
pstd.c -- standard library | ||
pmath.h | ||
pmath.c -- math library | ||
pstring.h | ||
pstring.c -- string library | ||
pmain.c | ||
Makefile | ||
|
||
EXAMPLE SCRIPTS | ||
std.poe -- A script containing definitions for standard library functions. | ||
A pre-compiled copy of the bytecode is built into the interpreter and is | ||
executed during every invocation of it; this does not need to be manually | ||
executed. | ||
sum.poe -- A simple tool to sum the numbers given on the command line (and | ||
in a single line of code, no less). | ||
echo.poe -- A simple implementation of the echo command line tool. | ||
file.poe -- A tool to open a file and print its contents, with all letters | ||
capitalized. | ||
smart.poe -- A small library containing a definition for "smart arrays", | ||
which are arrays that throw errors when an attempt is made to access | ||
an element outside of the array's "size". Tests for this script are | ||
included in the require.poe file. | ||
require.poe -- A small script demonstrating file inclusion; it loads and | ||
executes some of the functions in the smart.poe file. | ||
scope.poe -- A long script demonstrating some of the unique lexical scoping | ||
features which Poe provides. | ||
blocks.poe -- A discussion of Poe's blocks and some of the unique situations they present. | ||
|
||
DOCUMENTATION | ||
1000lines.txt -- An introduction to the Poe programming language, for | ||
the seasoned programmer, in less than 1000 lines. | ||
standard_library.txt -- A list of the currently implemented and to-be- | ||
implemented standard library functions. | ||
TODO -- An ongoing list of tasks which need to be completed. | ||
QUICKSTART -- A list of instructions to quickly execute some Poe scripts |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
1) Finish up the standard library; this information is contained in the | ||
pstd.h and standard_library.txt files. | ||
2) Implement runtime error messages; currently, the interpreter exits | ||
silently if it encounters an error, which is far from acceptable. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
/* blocks.poe: a demonstration of Poe blocks */ | ||
|
||
/* usage: pint blocks.poe */ | ||
|
||
/* Poe blocks are inspired by Ruby blocks, but they are not identical. In Ruby, | ||
blocks are just anonymous functions with a more elegant syntax. Poe offers | ||
anonymous functions, so everything that can be done with a Ruby block | ||
can be done quite simply with an anonymous function. However, I have not | ||
seen a Ruby construct that can do everything Poe blocks can do -- in fact, | ||
Poe blocks are very unique. | ||
|
||
Essentially, a Poe block is a block of compiled code that can be invoked | ||
anywhere with the do statement. A Poe block is like a function in a lot | ||
of ways, except: | ||
1) A block cannot be called or passed arguments. | ||
2) A block does not have a parent table. | ||
3) A new symbol table is not created when a block is invoked. | ||
4) A block cannot return a value, and a block invocation can only be | ||
used as an independent statement, not in the middle of an expression. | ||
|
||
The following code will define and execute a block called b. */ | ||
|
||
b = block: | ||
unless local a: a = 0; end; | ||
print("hello from block b"); | ||
a = a+1; | ||
print(a); | ||
end; | ||
print(b); #! Notice that the block's type is "code" | ||
do b; | ||
|
||
/* Evidently, invoking the block executed the block's statements; it is as | ||
if the block's statements were pasted in place of the block invocation | ||
"do b;". Now, a global variable a exists, and it has the value 1. | ||
Now: */ | ||
|
||
exec_blk = func(blk): | ||
do blk; | ||
end; | ||
|
||
exec_blk(b); | ||
print(a); | ||
|
||
/* Notice that even though the block was defined in the global scope, the | ||
block does not operate on the global a, instead operating on a variable | ||
local to the exec_blk function. The global a is unchanged, until we | ||
execute the block in the global scope: */ | ||
|
||
do b; | ||
do b; | ||
|
||
/* So blocks have dynamic scope; exactly what actions they carry out is | ||
dependent on where they are invoked. | ||
|
||
Further, blocks can be read from files. Calling compile() with a file | ||
or string containing Poe source code returns a code object, whose | ||
lexical rules are exactly like those that we've observed here. | ||
|
||
This is a fundamental trait of Poe bytecode objects: a string of code will | ||
have different behavior depending on the context. Poe identifiers are never | ||
bound to a particular scope; a symbol like "print" might lose its meaning if | ||
we move to a context which doesn't have any conception of "print" (see | ||
scope.poe for an example). | ||
|
||
This approach is unconvential, but interesting: for example, say we want | ||
to execute some bytecode from an unknown source. It may be prudent to | ||
"sandbox" this code by executing it in a context which doesn't have | ||
access to more sensitive functions, like I/O functions. As an artificial | ||
example, say we had a function | ||
delete_everything() | ||
which automatically deletes everything on disk. Say we had some compiled | ||
bytecode which may or may not contain a reference to delete_everything | ||
in it. Then we could execute the bytecode with a do instruction from | ||
within the local scope of a sandbox, whose access to certain global | ||
variables has been restricted. For example, if we wanted to make | ||
a sandbox function where only the print function and string library | ||
are accessible, we could do something like this: */ | ||
|
||
sandbox = func(blk): | ||
print = print; | ||
string = string; | ||
locals.^ = undef; #! Set the local table's parent to undef | ||
do blk; | ||
end; | ||
|
||
/* The sandbox function grabs local copies of print and string (notice that | ||
by default, assignment is local, so the assignment "print = print;" is | ||
equivalent to "local print = print;"). Now, if blk attempts to access | ||
any other global function, delete_everything() or otherwise, the result | ||
will be undef. There is no way for the code in blk to access any | ||
function but print and the string functions -- as far as blk is | ||
concerned, it is executing within the global scope. | ||
|
||
As a final note, I will discuss how I dealt with the problem of scoping | ||
when implementing the standard library functions load and require. Load | ||
and require compile and execute bytecode, like so: | ||
require("example.poe"); | ||
However, the result of compiling example.poe is bytecode, and immediately, | ||
we run into scoping problems. Keep in mind that require is a function, so | ||
all of example.poe's assignments would be operating on require's symbol | ||
table rather than the global symbol table; without a workaround, this | ||
would make it very difficult to create libraries. As a concrete example, | ||
take the function | ||
max = func(a,b): | ||
if a>b: return(a); | ||
else: return(b); end; | ||
end; | ||
Say this were included in example.poe, which is a larger library that | ||
we intend to include in many scripts. However, if we simply executed the | ||
bytecode in require, max would be defined in *require's local scope* | ||
rather than globally, which is where we want it. | ||
|
||
The key is the standard library function export, which copies the | ||
contents of a table into another table. The require problem can be | ||
solved by calling export(locals), which exports the contents of the local | ||
symbol table into the global table. So require executes example.poe's | ||
bytecode as normal, and then exports the definitions into the global scope. | ||
If you plan to play with Poe's scope, export will probably be a very | ||
useful function for you. */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
/* echo.poe: a simple Poe implementation of echo, without command line | ||
argument implementation */ | ||
|
||
/* usage: pint echo.poe ... */ | ||
|
||
/* join: concatenate all the string members of an array with delim interspersed | ||
between each */ | ||
join = func(delim, arr): | ||
acc = ""; | ||
for key, str in arr: | ||
string.concat(acc,str,acc); | ||
if key<@arr: string.concat(acc,delim,acc); end; | ||
end; | ||
return(acc); | ||
end; | ||
|
||
print(join(" ",argv)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
/* file.poe: echoes the contents of a file to the terminal, capitalizing | ||
all lowercase characters. The name of the file to be echoed is given as | ||
a command line argument: for instance, | ||
pint file.poe pmain.c | ||
to capitalize and echo the contents of pmain.c. */ | ||
|
||
f = io.open(argv[0],"r"); | ||
|
||
a = io.tostr(f); #! convert the file f to an array of strings | ||
|
||
capitalize = func(c): | ||
if c>='a' and c<='z': | ||
return(c-'a'+'A'); | ||
end; | ||
return(c); | ||
end; | ||
|
||
print(map!(capitalize,a)); | ||
|
||
io.close(f); |
Oops, something went wrong.