Skip to content

Commit

Permalink
Merge pull request #17 from SinclairGurny/scoping
Browse files Browse the repository at this point in the history
Version 1.0
  • Loading branch information
SinclairGurny authored Jul 19, 2019
2 parents 86ff6d7 + e50ab2a commit 595e77e
Show file tree
Hide file tree
Showing 29 changed files with 657 additions and 382 deletions.
99 changes: 63 additions & 36 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,81 +1,108 @@


# All .o files
OBJ = build/parser.o build/eval.o build/exec.o build/funcs.o build/bool.o build/comp.o \
build/list.o build/math.o build/types.o build/repl.o

DEBUG_OBJ = build/dparser.o build/deval.o build/dexec.o build/dfuncs.o build/dbool.o build/dcomp.o \
build/dlist.o build/dmath.o build/dtypes.o build/drepl.o

# Parsing Library
PARSE_H = src/psil_parser.h
PARSE_CPP = src/psil_parser.cpp

# Evaluation Library
EVAL_H = src/psil_eval.h
EVAL_CPP = src/psil_eval.cpp

# Execution Library
EXEC_H = src/psil_exec.h
EXEC_CPP = src/psil_exec.cpp src/psil_exec_funcs.cpp src/psil_exec_bool.cpp src/psil_exec_comp.cpp \
src/psil_exec_list.cpp src/psil_exec_math.cpp src/psil_exec_types.cpp

# Main Code
MAIN_H = src/psil.h
MAIN_CPP = src/repl.cpp

# All header and cpp files
ALL_H = $(PARSE_H) $(EVAL_H) $(EXEC_H) $(MAIN_H)
ALL_CPP = $(PARSE_CPP) $(EVAL_CPP) $(EXEC_CPP) $(MAIN_CPP)



ifdef DEBUG
EXTRAS = -g -DDEBUG_MODE
OUTPUT = psil_debug
else
EXTRAS = -O3
OUTPUT = psil
endif

FLAGS = -Wall -std=c++17 $(EXTRAS)
FLAGS = -Wall -std=c++17
OPT_FLAGS = -O3
DEBUG_FLAGS = -g

LIBS = -lreadline

all: $(OUTPUT)
@echo '... Finished Compiling PSIL ...'

psil: $(OBJ)
g++ $(OBJ) $(LIBS) -o $(OUTPUT)
normal: $(OBJ)
g++ $(OBJ) $(LIBS) -o psil
@echo "... Finished Building PSIL ..."

psil_debug: $(OBJ)
g++ $(OBJ) $(LIBS) -o $(OUTPUT)

debug:
rm -f build/*o
$(MAKE) DEBUG=1
debug: $(DEBUG_OBJ)
g++ $(DEBUG_OBJ) $(LIBS) -o psil_debug
@echo "... Finished Building DEBUG PSIL ..."

# Normal Building rules
build/parser.o: $(PARSE_H) $(PARSE_CPP)
mkdir -p build
g++ $(FLAGS) -c $(PARSE_CPP) -o build/parser.o
g++ $(FLAGS) $(OPT_FLAGS) -c $(PARSE_CPP) -o build/parser.o

build/eval.o: $(EVAL_H) $(EVAL_CPP) $(PARSE_H) $(PARSE_CPP)
g++ $(FLAGS) -c $(EVAL_CPP) -o build/eval.o
g++ $(FLAGS) $(OPT_FLAGS) -c $(EVAL_CPP) -o build/eval.o

build/exec.o: $(EXEC_H) $(EXEC_CPP) $(EVAL_H) $(EVAL_CPP) $(PARSE_H) $(PARSE_CPP)
g++ $(FLAGS) -c src/psil_exec.cpp -o build/exec.o
g++ $(FLAGS) $(OPT_FLAGS) -c src/psil_exec.cpp -o build/exec.o

build/funcs.o: $(EXEC_H) $(EXEC_CPP) $(EVAL_H) $(EVAL_CPP) $(PARSE_H) $(PARSE_CPP)
g++ $(FLAGS) -c src/psil_exec_funcs.cpp -o build/funcs.o
g++ $(FLAGS) $(OPT_FLAGS) -c src/psil_exec_funcs.cpp -o build/funcs.o

build/bool.o: $(EXEC_H) $(EXEC_CPP) $(EVAL_H) $(EVAL_CPP) $(PARSE_H) $(PARSE_CPP)
g++ $(FLAGS) -c src/psil_exec_bool.cpp -o build/bool.o
g++ $(FLAGS) $(OPT_FLAGS) -c src/psil_exec_bool.cpp -o build/bool.o

build/comp.o: $(EXEC_H) $(EXEC_CPP) $(EVAL_H) $(EVAL_CPP) $(PARSE_H) $(PARSE_CPP)
g++ $(FLAGS) -c src/psil_exec_comp.cpp -o build/comp.o
g++ $(FLAGS) $(OPT_FLAGS) -c src/psil_exec_comp.cpp -o build/comp.o

build/list.o: $(EXEC_H) $(EXEC_CPP) $(EVAL_H) $(EVAL_CPP) $(PARSE_H) $(PARSE_CPP)
g++ $(FLAGS) -c src/psil_exec_list.cpp -o build/list.o
g++ $(FLAGS) $(OPT_FLAGS) -c src/psil_exec_list.cpp -o build/list.o

build/math.o: $(EXEC_H) $(EXEC_CPP) $(EVAL_H) $(EVAL_CPP) $(PARSE_H) $(PARSE_CPP)
g++ $(FLAGS) -c src/psil_exec_math.cpp -o build/math.o
g++ $(FLAGS) $(OPT_FLAGS) -c src/psil_exec_math.cpp -o build/math.o

build/types.o: $(EXEC_H) $(EXEC_CPP) $(EVAL_H) $(EVAL_CPP) $(PARSE_H) $(PARSE_CPP)
g++ $(FLAGS) -c src/psil_exec_types.cpp -o build/types.o
g++ $(FLAGS) $(OPT_FLAGS) -c src/psil_exec_types.cpp -o build/types.o

build/repl.o: $(ALL_H) $(ALL_CPP)
g++ $(FLAGS) -c src/repl.cpp $(LIBS) -o build/repl.o
g++ $(FLAGS) $(OPT_FLAGS) -c src/repl.cpp $(LIBS) -o build/repl.o


# DEBUG Building rules
build/dparser.o: $(PARSE_H) $(PARSE_CPP)
mkdir -p build
g++ $(FLAGS) $(DEBUG_FLAGS) -c $(PARSE_CPP) -o build/dparser.o

build/deval.o: $(EVAL_H) $(EVAL_CPP) $(PARSE_H) $(PARSE_CPP)
g++ $(FLAGS) $(DEBUG_FLAGS) -c $(EVAL_CPP) -o build/deval.o

build/dexec.o: $(EXEC_H) $(EXEC_CPP) $(EVAL_H) $(EVAL_CPP) $(PARSE_H) $(PARSE_CPP)
g++ $(FLAGS) $(DEBUG_FLAGS) -c src/psil_exec.cpp -o build/dexec.o

build/dfuncs.o: $(EXEC_H) $(EXEC_CPP) $(EVAL_H) $(EVAL_CPP) $(PARSE_H) $(PARSE_CPP)
g++ $(FLAGS) $(DEBUG_FLAGS) -c src/psil_exec_funcs.cpp -o build/dfuncs.o

build/dbool.o: $(EXEC_H) $(EXEC_CPP) $(EVAL_H) $(EVAL_CPP) $(PARSE_H) $(PARSE_CPP)
g++ $(FLAGS) $(DEBUG_FLAGS) -c src/psil_exec_bool.cpp -o build/dbool.o

build/dcomp.o: $(EXEC_H) $(EXEC_CPP) $(EVAL_H) $(EVAL_CPP) $(PARSE_H) $(PARSE_CPP)
g++ $(FLAGS) $(DEBUG_FLAGS) -c src/psil_exec_comp.cpp -o build/dcomp.o

build/dlist.o: $(EXEC_H) $(EXEC_CPP) $(EVAL_H) $(EVAL_CPP) $(PARSE_H) $(PARSE_CPP)
g++ $(FLAGS) $(DEBUG_FLAGS) -c src/psil_exec_list.cpp -o build/dlist.o

build/dmath.o: $(EXEC_H) $(EXEC_CPP) $(EVAL_H) $(EVAL_CPP) $(PARSE_H) $(PARSE_CPP)
g++ $(FLAGS) $(DEBUG_FLAGS) -c src/psil_exec_math.cpp -o build/dmath.o

build/dtypes.o: $(EXEC_H) $(EXEC_CPP) $(EVAL_H) $(EVAL_CPP) $(PARSE_H) $(PARSE_CPP)
g++ $(FLAGS) $(DEBUG_FLAGS) -c src/psil_exec_types.cpp -o build/dtypes.o

build/drepl.o: $(ALL_H) $(ALL_CPP)
g++ $(FLAGS) $(DEBUG_FLAGS) -c src/repl.cpp $(LIBS) -o build/drepl.o


clean:
$(RM) psil psil_debug *~ src/*~ docs/*~ examples/*~
Expand Down
33 changes: 23 additions & 10 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -16,38 +16,51 @@ PSIL:
Stands for Programming Some Idiotic Lisp.
(It's actually based on Scheme Syntax)

PSIL is a WIP interpreter for my own version of a LISP like language
PSIL is a interpreter for my own version of a LISP like language

Current version 0.9
-- Missing scoping of defined variables
Current version 1.0
For more information in docs/

written by Sinclair Gurny
Starting in July 2019
July 2019

================================================================================================
=====================================================================

Compiling:
make - for normal
make debug - full parsing output
make debug_slow - full parsing output with delay
make debug - for debugger friendly compilation
make clean - delete unnecessary files

Running:
./psil
./psil_debug
./psil or ./psil_debug
Runs PSIL in REPL mode
Executes any code or command given.
./psil <code.psil> or ./psil_debug <code.psil>
Runs PSIL in file mode,
PSIL executes the code in the given .psil file, then exits.

REPL Commands:
quit - exits
exit - also exits
help - displays commands
psil - displays syntax of current version of PSIL

=======================================================
=====================================================================

Examples:
See examples/ for more.
For explanations of the examples see docs/EXAMPLES.

Hello World Program:
>> (print #\H #\e #\l #\l #\o #\, #\space #\W #\o #\r #\l #\d #\!)

Hello, World!

>> (begin
(define fact (lambda (n)
(if (equal? n 1)
1
(* n (fact (- n 1))))))
(fact 10))

3628800
69 changes: 69 additions & 0 deletions docs/EXAMPLES
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
==============================================================================================
=== Code Example Explanations ==============================================================
==============================================================================================

closure.psil
Addtwo returns a closure, the closure is saved to the name addone.
The result of the code is 15.

count.psil
Counts from 0 to 9, then prints Done.

echo.psil
Prints whatever the user enters.
Program exits upon entering "quit".
Val is used to store the user's input, but remains in scope
throughout the recursion, so must be updated.
str_print is used to print a list of characters without the '().

factorial.psil
Determines the factorial of several numbers.
Running factorial on numbers higher than 20 produces integer
overflow.

fast_fib.psil
Determines the fibonacci value at specific indices.
Uses a faster recursive method than fibonacci.psil,
Runs in less than 0.25s, on my computer in debug mode.

fibonacci.psil
Determines the fibonacci value at specific indices.
Uses the common recursive method, very slow.
Runs in > 3.5s, on my computer in debug mode.

first_order_procs.psil
Shows several examples of first order procedures.
Uses operators, global procedures, and local procedures (lambdas).

hello.psil
Prints "Hello, World!".

metapgrogramming.psil
Show examples of metaprogramming.
The code takes the procedure f, and switches the order of the
expressions in the body, and calls the result g. Then takes
the procedure f, and switches the order of the arguments,
and calls the result h.
Therefore the original function, given the arguments #\H #\i outputs
1 H
2 i
g outputs
2 i
1 H
h outputs
1 i
2 H

quoting.psil
Shows examples of quoting and unquoting.

quoting2.psil
Shows more examples of quoting and unquoting.

scoping.psil
Shows examples of valid scopings of variables.

test_math.psil
Complete test of every case of the arithmetic operators (+, -, *, /).
+, -, *: When ANY argument is a decimal the result is a decimal
/: Always returns a decimal
31 changes: 30 additions & 1 deletion docs/EXEC
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,33 @@ The library is split into many different sections.
The general abstract syntax tree execution code is implemented in psil_exec.cpp
The other exec files are used to split up the related global procedure implementations.

...
Symbol table is the stack_t struct. The global procedures are stores within the global_table.
The variables defined at runtime are stored in table. Table is a vector of symbol_table_t's.
Each symbol_table_t is a map that lookups the information and value of a variable given its name.

The stack is added to any time there is a (begin ...) statement. In begin statements variables can
be defined and expressions can use them.

The base exec function runs the abstract syntax tree. With smaller functions to run the different
types of statements within the tree.
For example: exec_if, exec_cond, exec_def, exec_var, exec_app, and apply_lambda.

Each one of these functions performs a lazy evaluation of the code.

PSIL is based on lambda functions and any form of repeated computation requires recursion.
For example an infinite loop:
(begin
(define f (lambda () (f)))
(f))

==========================================

When applying functions, if the function is globally defined then the corresponding function
is called to perform the proper operations on the AST. However, if the function is locally defined,
the lambda expression is applied. Lambda function in PSIL are not curried and will error if the correct
arguments are not received.

====
Note:
The full AST can be viewed easily using any tokens print() function, which displays the tree
traversed breadth first.
Loading

0 comments on commit 595e77e

Please sign in to comment.