diff --git a/fluids/Post.tex b/fluids/Post.tex index 019ac11..705efc0 100644 --- a/fluids/Post.tex +++ b/fluids/Post.tex @@ -2,7 +2,7 @@ % Created: Tue Nov 09 06:00 PM 2010 E % Last Change: Tue Nov 09 06:00 PM 2010 E % -\documentclass[a4paper,twocolumn]{article} +\documentclass[a4paper]{article} \usepackage{graphicx} \usepackage{amsmath} diff --git a/old/lisp-lang/Arithmetic.c b/old/lisp-lang/Arithmetic.c new file mode 100644 index 0000000..e7bc7bb --- /dev/null +++ b/old/lisp-lang/Arithmetic.c @@ -0,0 +1,420 @@ +#include "Vyion.h" + +/* Retrieving values from number structs */ +inline int GetInt(VyNumber** num){ + return ((IntNum*) NumberToSubtype(num))->i; +} +inline double GetDouble(VyNumber** num){ + return ((RealNum*) NumberToSubtype(num))->d; +} +inline VyNumber** GetImaginary(VyNumber** num){ + return ((ComplexNum*) NumberToSubtype(num))->imaginary; +} +inline VyNumber** GetReal(VyNumber** num){ + return ((ComplexNum*) NumberToSubtype(num))->real; +} +inline int GetDenominator(VyNumber** num){ + return ((RatioNum*) NumberToSubtype(num))->denominator; +} +inline int GetNumerator(VyNumber** num){ + return ((RatioNum*) NumberToSubtype(num))->numerator; +} + +/* Clone a number */ +VyNumber** CloneNumber(VyNumber** num){ + switch(num[0]->type){ + case INT: + return CreateInt(GetInt(num)); + case REAL: + return CreateReal(GetDouble(num)); + case COMPLEX: + return CreateComplex(CloneNumber(GetReal(num)), CloneNumber(GetImaginary(num))); + default: + return NULL; + } +} + +/* Negate a number */ +VyNumber** NegateNumber(VyNumber** num){ + /* Use the number type to decide what to do */ + num = CloneNumber(num); + + int numType = num[0]->type; + + /* Negate the number */ + if(numType == INT){ + IntNum* i = NumberToSubtype(num); + i->i *= -1; + } + if(numType == REAL){ + RealNum* rNum = NumberToSubtype(num); + rNum->d *= -1; + } + if(numType == COMPLEX){ + ComplexNum* cNum = NumberToSubtype(num); + cNum->real = NegateNumber(GetReal(num)); + cNum->imaginary = NegateNumber(GetImaginary(num)); + } + if(numType == RATIO){ + RatioNum* ratNum = NumberToSubtype(num); + ratNum->numerator *= -1; + } + + return num; +} + +/* Check whether the number equals 0 */ +int EqualsZero(VyNumber** num){ + /* Use ANDS and ORS to check */ + if((num[0]->type == INT && GetInt(num) == 0) + ||(num[0]->type == REAL && GetDouble(num) == 0) + ||(num[0]->type == COMPLEX && EqualsZero(GetReal(num)) && EqualsZero(GetImaginary(num))) + ||(num[0]->type == RATIO && GetNumerator(num) == 0)){ + return 1; + } + else { + return 0; + } +} + +/* Reduce a number to its best type (i.e. no complex numbers with 0i, no doubles with 0's after the decimal point, etc */ +void ReduceNumber(VyNumber** num){ + /* Check that, if it is a double, it isnt an int in disguise */ + if(num[0]->type == REAL){ + double d = GetDouble(num); + /* If it is, change it to an int */ + if(d == (int)(d)){ + num[0]->type = INT; + + IntNum* iNum = NumberToSubtype(num); + iNum->i = (int)(d); + } + } + + /* Check that, if it is a complex number, the imaginary part isn't 0 */ + else if(num[0]->type == COMPLEX){ + if(EqualsZero(GetImaginary(num))){ + /* Make it equal the real part */ + VyNumber** realPart = GetReal(num); + num[0]->type = realPart[0]->type; + + switch(num[0]->type){ + case INT: + ((IntNum*)(NumberToSubtype(num)))->i = GetInt(realPart); + break; + case REAL: + ((RealNum*)(NumberToSubtype(num)))->d = GetDouble(realPart); + break; + } + + + } + } +} + +/* A utility function for multiplying two numbers known to be complex */ +VyNumber** MultiplyComplexNumbers(VyNumber** c1, VyNumber** c2){ + /* Multiplying complex numbers: + * (a + bi)(x + yi) = + * = ax + ayi + xbi + byi^2 + * = ax - by + ayi + xbi + * = (ax - by) + (ay + xb)i + */ + + /* Get the components */ + VyNumber** realOne = GetReal(c1); // a + VyNumber** imaginaryOne = GetImaginary(c1); // b + VyNumber** realTwo = GetReal(c2); // x + VyNumber** imaginaryTwo = GetImaginary(c2); // y + + /* Multiply them to get the new components */ + VyNumber** realResult = SubtractNumbers(MultiplyNumbers(realOne, realTwo), MultiplyNumbers(imaginaryOne, imaginaryTwo)); // (ax - by) + VyNumber** imaginaryResult = AddNumbers(MultiplyNumbers(realOne, imaginaryTwo), MultiplyNumbers(realTwo, imaginaryOne)); // (ay + xb) + + /* Return the complex number */ + VyNumber** ret = CreateComplex(realResult, imaginaryResult); // (ax - by) + (ay + xb)i + return ret; +} + +/* Get the complex conjugate of a number */ +VyNumber** ComplexConjugate(VyNumber** num){ + VyNumber** conjugate = CreateComplex(GetReal(num), NegateNumber(GetImaginary(num))); + return conjugate; +} + +/* Divide a number by a complex number */ +VyNumber** DivideByComplex(VyNumber** one, VyNumber** two){ + /* We know that two (the denominator) is complex */ + + /* To get rid of it, multiply by it's conjugate */ + VyNumber** conjugate = ComplexConjugate(two); + VyNumber** denominator = MultiplyNumbers(two, conjugate); + + /* Reduce the complex number to a real one */ + ReduceNumber(denominator); + + + /* Now multiply the first number by the conjugate to get the numerator */ + VyNumber** numerator = MultiplyNumbers(one, conjugate); + + /* Now divide using conventional methods */ + return DivideNumbers(numerator, denominator); +} + +/* Raise a complex number to a power */ +VyNumber** ComplexExponent(VyNumber** cmplex, VyNumber** exp){ + /* Not yet implemented */ + return NULL; +} + +/* Add two numbers */ +VyNumber** AddNumbers(VyNumber** one, VyNumber** two){ + /* Type conversions (in order of precedence): + * Complex + Anything = Complex, unless imaginary part = 0 + * Real + Anything = Real + * Ratio + Ratio or Ratio + Int = Ratio + * Int + Anything = Anything + */ + + int typeOne = one[0]->type; + int typeTwo = two[0]->type; + + VyNumber** num; + + /* Use the number's types to decide what to do */ + if(typeOne == INT){ + int oneInt = GetInt(one); + switch(typeTwo){ + case INT: + /* Int + Int = Int */ + num = CreateInt(oneInt + GetInt(two)); + break; + case REAL: + /* Int + Real = Real */ + num = CreateReal(oneInt + GetDouble(two)); + break; + case COMPLEX: + /* Int + Complex = Complex */ + num = CreateComplex(AddNumbers(one, GetReal(two)), GetImaginary(two)); + break; + } + + } + else if(typeOne == REAL){ + double oneDouble = GetDouble(one); + switch(typeTwo){ + case INT: + /* Real + Int = Real */ + num = CreateReal(oneDouble + GetInt(two)); + break; + case REAL: + /* Real + Real = Real */ + num = CreateReal(oneDouble + GetDouble(two)); + break; + case COMPLEX: + /* Real + Complex = Real */ + num = CreateComplex(AddNumbers(one, GetReal(two)), GetImaginary(two)); + break; + } + } + else if(typeOne == COMPLEX){ + VyNumber** oneReal = GetReal(one); + VyNumber** oneImaginary = GetImaginary(one); + switch(typeTwo){ + /* If both are complex, add the real and imaginary parts */ + case COMPLEX: + /* Complex + Complex = Complex */ + num = CreateComplex(AddNumbers(oneReal, GetReal(two)), AddNumbers(oneImaginary, GetImaginary(two))); + break; + /* If only the first one is complex, then add the second one to the real part of the complex number */ + case INT: + case REAL: + /* Complex + (Int|Real) = Complex */ + num = CreateComplex(AddNumbers(oneReal, two), oneImaginary); + break; + } + } + + return num; +} + +/* Subtract two numbers */ +VyNumber** SubtractNumbers(VyNumber** one, VyNumber** two){ + /* Just add the first number and the negated second number */ + return AddNumbers(one, NegateNumber(two)); +} + +/* Multiply two numbers */ +VyNumber** MultiplyNumbers(VyNumber** one, VyNumber** two){ + /* Type conversions (in order of precedence): + * Complex * Anything = Complex, unless imaginary part = 0 + * Real * Anything = Real + * Ratio * Ratio or Ratio * Int = Ratio + * Int * Anything = Anything + */ + + int oneType = one[0]->type; + int twoType = two[0]->type; + + VyNumber** num; + + /* Determine what to do based on the types of the numbers */ + if(oneType == INT){ + switch(twoType){ + case INT: + /* Int * Int = Int */ + num = CreateInt(GetInt(one) * GetInt(two)); + break; + case REAL: + /* Int * Real = Real */ + num = CreateReal(GetInt(one) * GetDouble(two)); + break; + case COMPLEX: + /* Int * Complex = Complex */ + num = CreateComplex(MultiplyNumbers(one, GetReal(two)), MultiplyNumbers(one, GetImaginary(two))); + break; + } + } + else if(oneType == REAL){ + switch(twoType){ + case INT: + /* Real * Int = Real */ + num = CreateReal(GetDouble(one) * GetInt(two)); + break; + case REAL: + /* Real * Real = Real */ + num = CreateReal(GetDouble(one) * GetDouble(two)); + break; + case COMPLEX: + /* Real * Complex = Complex */ + num = CreateComplex(MultiplyNumbers(one, GetReal(two)), MultiplyNumbers(one, GetImaginary(two))); + break; + } + } + else if(oneType == COMPLEX){ + switch(twoType){ + case INT: + case REAL: + /* (Int|Real) * Complex = Complex */ + num = CreateComplex(MultiplyNumbers(GetReal(one), two), MultiplyNumbers(GetImaginary(one), two)); + break; + case COMPLEX: + /* Call the utility function */ + /* Complex * Complex = Complex */ + num = MultiplyComplexNumbers(one, two); + break; + } + } + + /* Multiplication may induce some wrong types, so reduce the number to its best type: */ + ReduceNumber(num); + + return num; + +} + +/* Divide two numbers */ +VyNumber** DivideNumbers(VyNumber** one, VyNumber** two){ + /* Type conversions (in order of precedence): + * Complex / Anything = Complex, unless imaginary part = 0 + * Real / Anything = Real + * Ratio / Ratio or Ratio / Int = Ratio + * Int / Int = Ratio + * Int / Anything = Real + */ + + int oneType = one[0]->type; + int twoType = two[0]->type; + + VyNumber** num; + + /* Determine what to do based on the types of the numbers */ + if(oneType == INT){ + switch(twoType){ + case INT: + /* Int / Int = Real */ + num = RatioToReal(CreateRatio(GetInt(one) , GetInt(two))); + break; + case REAL: + /* Int / Real = Real */ + num = CreateReal(GetInt(one) / GetDouble(two)); + break; + case COMPLEX: + /* Int / Complex = Complex */ + num = DivideByComplex(one, two); + break; + } + } + else if(oneType == REAL){ + switch(twoType){ + case INT: + /* Real / Int = Real */ + num = CreateReal(GetDouble(one) / GetInt(two)); + break; + case REAL: + /* Real / Real = Real */ + num = CreateReal(GetDouble(one) / GetDouble(two)); + break; + case COMPLEX: + /* Real / Complex = Complex */ + num = DivideByComplex(one, two); + break; + } + } + else if(oneType == COMPLEX){ + switch(twoType){ + case INT: + case REAL: + /* Complex / (Int|Real) = Complex */ + num = CreateComplex(DivideNumbers(GetReal(one), two), DivideNumbers(GetImaginary(one), two)); + break; + case COMPLEX: + /* Complex / Complex = Complex */ + num = DivideByComplex(one, two); + } + } + + /* Reduce the number to its best type */ + ReduceNumber(num); + + return num; +} + +/* Take a power */ +VyNumber** ExponentiateNumber(VyNumber** base, VyNumber** exponent){ + int baseType = base[0]->type; + int expType = exponent[0]->type; + + /* Cannot raise to complex power, so return error code -1 */ + if(expType == COMPLEX){ + return (VyNumber**)(-1); + } + + VyNumber** num; + + if(baseType == INT){ + switch(expType){ + case INT: + num = CreateInt((int)(pow(GetInt(base), GetInt(exponent)))); + break; + case REAL: + num = CreateReal(pow(GetInt(base), GetDouble(exponent))); + break; + } + } + else if(baseType == REAL){ + switch(expType){ + case INT: + num = CreateReal(pow(GetDouble(base), GetInt(exponent))); + break; + case REAL: + num = CreateReal(pow(GetDouble(base), GetDouble(exponent))); + break; + } + } + else if(baseType == COMPLEX){ + num = ComplexExponent(base, exponent); + } + + return num; +} diff --git a/old/lisp-lang/Boolean.c b/old/lisp-lang/Boolean.c new file mode 100644 index 0000000..278bae8 --- /dev/null +++ b/old/lisp-lang/Boolean.c @@ -0,0 +1,187 @@ +#include "Vyion.h" + +/* Wrappers for checking truth values */ +int IsTrue(VyBoolean** b){ + if(b[0]->torf != 0){ + return 1; + }else{ + return 0; + } +} +int IsFalse(VyBoolean** b){ + if(b[0]->torf == 0){ + return 1; + }else{ + return 0; + } +} + +/* Creation of booleans + * Note: since all boolean values are the same, there is no need for more + * than two of them. Therefore, just return the global true or false value. */ +VyBoolean** t = NULL; +VyBoolean** f = NULL; + +VyBoolean** MakeTrueBool(){ + if(t == NULL){ + /* Create a true boolean object if one doesn't exist yet */ + t = CreateBoolObj(); + t[0]->torf = 1; + } + return t; +} +VyBoolean** MakeFalseBool(){ + if(f == NULL){ + /* Create a false boolean object if one doesn't exist yet */ + f = CreateBoolObj(); + f[0]->torf = 0; + } + return f; +} + +/* Functions for logic operations and, or, xor, and not (non-short-circuiting) */ +VyBoolean** BoolAnd(VyBoolean** one, VyBoolean** two){ + if(IsTrue(one) && IsTrue(two)){ + return t; + } + + return f; +} +VyBoolean** BoolOr(VyBoolean** one, VyBoolean** two){ + if(IsTrue(one) || IsTrue(two)){ + return t; + } + + return f; +} +VyBoolean** BoolXor(VyBoolean** one, VyBoolean** two){ + if((IsTrue(one) && IsFalse(two)) || (IsFalse(one) && IsFalse(two))){ + return t; + } + + return f; +} +VyBoolean** BoolNot(VyBoolean** b){ + if(IsTrue(b)){ + return f; + }else{ + return t; + } +} + +/* Functions for comparing numbers */ +VyBoolean** LessThan(VyNumber** one, VyNumber** two){ + /* If they are of the same type, then compare */ + if(one[0]->type == INT && two[0]->type == INT){ + if(GetInt(one) < GetInt(two)){ + return t; + } else{ + return f; + } + } + if(one[0]->type == REAL && two[0]->type == REAL){ + if(GetDouble(one) < GetDouble(two)){ + return t; + } else{ + return f; + } + } + + /* If the types are different, make sure that one is an int */ + if(one[0]->type == REAL){ + return LessThan(two, one); + } + + /* Guaranteed that type one is int and type two is double */ + else{ + if((double)(GetInt(one)) < GetDouble(two)){ + return t; + }else{ + return f; + } + } +} +VyBoolean** GreaterThan(VyNumber** one, VyNumber** two){ + /* If they are of the same type, then compare */ + if(one[0]->type == INT && two[0]->type == INT){ + if(GetInt(one) > GetInt(two)){ + return t; + } else{ + return f; + } + } + if(one[0]->type == REAL && two[0]->type == REAL){ + if(GetDouble(one) > GetDouble(two)){ + return t; + } else{ + return f; + } + } + + /* If the types are different, make sure that one is an int */ + if(one[0]->type == REAL){ + return GreaterThan(two, one); + } + + /* Guaranteed that type one is int and type two is double */ + else{ + if((double)(GetInt(one)) > GetDouble(two)){ + return t; + }else{ + return f; + } + } +} + +VyBoolean** LessThanOrEqual(VyNumber** one, VyNumber** two){ + if(IsTrue(LessThan(one, two)) || IsTrue(Equal(one, two))){ + return t; + } + + return f; +} +VyBoolean** GreaterThanOrEqual(VyNumber** one, VyNumber** two){ + if(IsTrue(GreaterThan(one, two)) || IsTrue(Equal(one, two))){ + return t; + } + + return f; +} + +VyBoolean** Equal(VyNumber** one, VyNumber** two){ + /* Because all numbers are in simplest terms, numbers with different types are not equal */ + if(one[0]->type != two[0]->type){ + return f; + } + + /* Now check each type */ + if(one[0]->type == INT){ + if(GetInt(one) == GetInt(two)){ + return t; + } + } + if(one[0]->type == REAL){ + if(GetDouble(one) == GetDouble(two)){ + return t; + } + } + if(one[0]->type == COMPLEX){ + /* Check that both the imaginary and real parts are equal */ + return BoolAnd(Equal(GetReal(one), GetReal(two)), Equal(GetImaginary(one), GetImaginary(two))); + } + else { + return f; + } +} +VyBoolean** NotEqual(VyNumber** one, VyNumber** two){ + return BoolNot(Equal(one, two)); +} + +/* Print a boolean value as either true! or false!, which are the names of the variables that represent the booleans */ +void PrintBoolean(VyBoolean** b){ + if(IsTrue(b)){ + printf("true!"); + }else{ + printf("false!"); + } +} diff --git a/old/lisp-lang/CharList.c b/old/lisp-lang/CharList.c new file mode 100644 index 0000000..f0e400a --- /dev/null +++ b/old/lisp-lang/CharList.c @@ -0,0 +1,84 @@ +#include "Vyion.h" + +/* Make a new character list and initialize the next node to NULL */ +CharList* MakeCharList(){ + CharList* c = malloc(sizeof(CharList)); + c->next = NULL; + return c; +} + +/* Add another node to the list */ +void Add(CharList* list, char c){ + /* If this is the last node, then add the character to it and add another empty node for the future */ + if(list->next == NULL){ + /* Create a new node that will be used in future additions*/ + list->next = MakeCharList(); + + /* Add the character to THIS node */ + list->val = c; + + } + /* If it isn't the last node, then continue on to the next node in the list */ + else { + Add(list->next, c); + } +} + +/* Find the character at index n */ +char Get(CharList* list, int n){ + /* If it's this node, return it; otherwise, go on to the next node */ + if(n == 0){ + return list->val; + }else{ + return Get(list->next, n - 1); + } +} + +/* Convert the CharList to a string */ +char* ToStr(CharList* list){ + /* Allocate room for the string */ + int list_size = Size(list); + char* str = malloc(sizeof(char)*list_size + 1); + + + /* Collect the string characters */ + int c; + for(c = 0; c < list_size; c++){ + str[c] = Get(list,c); + } + + /* End the string (with a ASCII 0) */ + str[list_size] = '\0'; + + /* Return the string */ + return str; +} + +int Size(CharList* list){ + if(list->next == NULL){ + return 0; + }else{ + return Size(list->next) + 1; + } +} + +/* Print the contents of the list recursively */ +void Print(CharList* list){ + if(list->next != NULL){ + printf("%c", list->val); + Print(list->next); + } +} + +/* Delete the list */ +void Delete(CharList* list){ + /* If this is the last added one, free it, otherwise, + * free the next node first and then free this node. */ + if(list->next == NULL){ + free(list); + }else{ + Delete(list->next); + free(list); + } +} + diff --git a/old/lisp-lang/Error.c b/old/lisp-lang/Error.c new file mode 100644 index 0000000..59dfbc7 --- /dev/null +++ b/old/lisp-lang/Error.c @@ -0,0 +1,30 @@ +#include "Vyion.h" + +/* Create an error from an expression and the message */ +VyError** CreateError(char* message, VyParseTree* location){ + VyError** err = CreateErrorObj(); + err[0]->message = message; + err[0]->expr = location; + + return err; +} + +/* Print an error */ +void PrintError(VyError** err){ + printf("\n\n"); + printf("------- Error Occured -------"); + if(err[0]->expr != NULL){ + PrintTree(err[0]->expr); + printf("\n"); + if(err[0]->expr->pos != NULL){ + printf("Position: "); + PrintPosition(err[0]->expr->pos); + printf("\n"); + } + } + else { + printf("\n"); + } + printf(err[0]->message); + printf("\n-----------------------------"); +} diff --git a/old/lisp-lang/Eval.c b/old/lisp-lang/Eval.c new file mode 100644 index 0000000..72cb28c --- /dev/null +++ b/old/lisp-lang/Eval.c @@ -0,0 +1,1080 @@ +#include "Vyion.h" + +/* Whether the interpreter is in interactive REPL mode */ +int replMode = 0; + +/* Process the argument list and 'return' the values and number of arguments */ +void ProcessArgumentList(Argument** funcArgs, int numFuncArgs, VyParseTree* tr, VyObject** valuesPtr, int* numArgsPtr, VyObject (*EvalFunctionToUse) (VyParseTree*)){ + /* When gathering the arguments, remember their names (if any, else NULL) */ + char** argumentNames = malloc(sizeof(char*) * (ListTreeSize(tr) - 1)); + + /* Evaluate the rest of the list and store the results */ + VyObject* values = malloc(sizeof(VyObject) * (ListTreeSize(tr) - 1)); + int i; + int numArgs = 0; + for(i = 1; i < ListTreeSize(tr); i++){ + /* If the current argument is a ~, skip it (it will be dealt with later as a named argument marker)*/ + if(GetListData(tr, i)->type == TREE_IDENT && strcmp(GetStrData(GetListData(tr, i)), "~") == 0){ + continue; + } + + /* Count the number of arguments */ + numArgs++; + + /* Check whether the previous 'argument' was a ~ */ + VyParseTree* prev = GetListData(tr, i -1 ); + + /* The evaluation result */ + VyObject val; + + /* If it is ~, then this is a named argument */ + if(prev != NULL && prev->type == TREE_IDENT && strcmp(GetStrData(prev),"~") == 0){ + /* Find the name and value */ + char* namedArgName = GetStrData(GetListData(GetListData(tr, i), 0)); + val = EvalFunctionToUse(GetListData(GetListData(tr, i), 1)); + + /* Now remember the name and the corresponding index (in the argument array) */ + argumentNames[numArgs - 1] = namedArgName; + } else{ + /* If it isn't a named argument, then it's name is NULL */ + argumentNames[numArgs - 1] = NULL; + val = EvalFunctionToUse(GetListData(tr, i)); + } + + /* Subtract one from the array index because i is the index of the list, not array */ + values[numArgs - 1] = val; + } + + /* Now re-order the argument array for the named arguments */ + /* Make sure the argument array is valid before using it */ + if(funcArgs != NULL){ + + /* First, do the required named arguments */ + int c; + for(c = 0; c < numFuncArgs && IsNamedArg(funcArgs[c]); c++){ + /* Check whether the argument is a named one */ + Argument* currArg = funcArgs[c]; + if(IsNamedArg(currArg)){ + /* If it is, match it up with the named argument that we have by switching the order of arguments */ + char* name = currArg->name; + + int d; + for(d = 0; d < numArgs; d++){ + /* If this is the argument we want to match it with */ + if(argumentNames[d] != NULL && strcmp(argumentNames[d], name) == 0){ + /* Switch the order */ + VyObject temp = values[d]; + int m; + for(m = d; m > c; m--){ + /* Move one over to the left */ + values[m] = values[m - 1]; + } + values[c] = temp; + } + } + } + } + + /* Find where the first optional argument occurs */ + int firstOptionalArg = 0; + while(firstOptionalArg < numFuncArgs && !IsOptionalArg(funcArgs[firstOptionalArg])){ + firstOptionalArg++; + } + + /* Next, sort the optional named arguments using the same method as before */ + for(c = firstOptionalArg; c < numFuncArgs && IsNamedArg(funcArgs[c]); c++){ + /* Check whether the argument is a named one */ + Argument* currArg = funcArgs[c]; + if(IsNamedArg(currArg)){ + /* If it is, match it up with the named argument that we have by switching the order of arguments */ + char* name = currArg->name; + + int d; + for(d = 0; d < numArgs; d++){ + /* If this is the argument we want to match it with */ + if(argumentNames[d] != NULL && strcmp(argumentNames[d], name) == 0){ + /* Switch the order */ + VyObject temp = values[d]; + int m; + for(m = d; m > c; m--){ + /* Move one over to the left */ + values[m] = values[m - 1]; + } + values[c] = temp; + } + } + } + } + + /* Now, make sure that optional positional arguments done get messed up by pretending they _were_ passed (use their default value) */ + for(c = firstOptionalArg; c < numFuncArgs && IsNamedArg(funcArgs[c]); c++){ + /* For every named argument, check if it really was passed by looking in the argument names array */ + int wasPassed = 0; + int n; + for(n = 0; n < numArgs; n++){ + /* If it WAS passed */ + if(argumentNames[n] != NULL && strcmp(argumentNames[n], funcArgs[c]->name) == 0){ + wasPassed = 1; + } + } + + /* If it wasn't passed, then substitute it for its default value and move all the + * values over to the right to compensate for this space */ + if(!wasPassed){ + /* Increase the amount of space needed */ + numArgs++; + values = realloc(values, numArgs * sizeof(VyObject)); + + /* Move all the values over */ + int x; + for(x = numArgs - 1; x > c; x--){ + values[x] = values[x - 1]; + } + + /* Now put the default value in where it should be */ + values[c] = funcArgs[c]->optArgDefault; + } + + } + } + + /* Return the values by storing the results in the correct memory locations */ + *valuesPtr = values; + *numArgsPtr = numArgs; + + /* Free the argument names */ + free(argumentNames); +} + +/* Perform a function given the VyFunction** and an argument list */ +VyObject PerformFunction(VyFunction** func, VyParseTree* tr){ + VyObject* values; + int numArgs; + ProcessArgumentList(func[0]->args, func[0]->numArgs, tr, &values, &numArgs, &Eval); + + /* Calculate the result of the function */ + VyObject val = RunFunction(func, values, numArgs); + free(values); + + + /* Check whether this result is an error, if it has no associated expression, give it one */ + if(ObjType(val) == VALERROR){ + VyError** err = ObjData(val); + if(err[0]->expr == NULL){ + err[0]->expr = tr; + } + } + + /* Return the result */ + return val; +} + +/* Quoted eval with and without substitutions */ +VyObject QuotedEvalWithSubstitution(VyParseTree* tr){ + return QuotedEval(tr, 1); +} +VyObject QuotedEvalWithoutSubstitution(VyParseTree* tr){ + return QuotedEval(tr, 0); +} + +/* Call a macro */ +VyObject ExpandMacro(VyMacro** mac, VyParseTree* tr){ + /* Process the arguments as needed */ + VyObject* vals; + int numArgs; + ProcessArgumentList(mac[0]->args, mac[0]->numArgs, tr, &vals, &numArgs, &QuotedEvalWithoutSubstitution); + + char* err = CheckFunctionArguments(mac[0]->args, mac[0]->numArgs, vals, numArgs); + if(err != NULL){ + return ToObject(CreateError(err, tr)); + } + + /* Evaluate it as a native function */ + VyObject obj = EvalNativeFunctionOrMacro(mac[0]->args, mac[0]->numArgs, mac[0]->code, mac[0]->scp, vals, numArgs); + + if(ObjType(obj) == VALERROR){ + /* If it has no associated expression, give it one */ + VyError** err = ObjData(obj); + if(err[0]->expr == NULL){ + err[0]->expr = tr; + } + return obj; + } + + /* Evaluate the macro expansion */ + VyParseTree* tree = ObjToParseTree(obj); + free(vals); + + return Eval(tree); + +} + +/* Handle an error: if in REPL mode, just continue, otherwise, exit */ +void HandleError(VyObject err){ + PrintError(ObjData(err)); + if(!replMode){ + exit(0); + } +} + +/* Convert an object into a corresponding parse tree */ +VyParseTree* ObjToParseTree(VyObject obj){ + int type = ObjType(obj); + if(type == VALLIST){ + /* Make a list parse tree and add the elements to it */ + VyParseTree* list = MakeListTree(); + int size = ListSize(ObjData(obj)); + int i; + + for(i = 0; i < size; i++){ + AddToList(list, ObjToParseTree(ListGet(ObjData(obj), i))); + } + + return list; + } + else if(type == VALSYMB){ + /* Create an ident from symbols */ + VyParseTree* symb = MakeIdent(); + SetStrData(symb, GetSymbolString(ObjData(obj))); + return symb; + + } + else if(type == VALNUM){ + /* Numbers are still numbers, just in VyParseTree* form */ + VyParseTree* num = MakeNum(); + SetNumberData(num, ObjData(obj)); + return num; + } else { + printf("TYPE IS %d", type);fflush(stdout); + PrintObj(obj);printf("\n"); + return NULL; + } +} + +/* Check a string for equality */ +int StrEquals(char* one, char* two){ + return (strcmp(one, two) == 0); +} + +/* Evaluate a parse tree */ +VyObject Eval(VyParseTree* tr){ + + /* If it is a list, then evaluate it as a function or keyword */ + if(tr->type == TREE_LIST){ + /* If you are parsing a list, use the first element to check what to do */ + VyParseTree* first = ListTreeHead(tr); + + /* If the first element is an identifier, it can be a function call or a keyword */ + if(first->type == TREE_IDENT) { + char* funcName = GetStrData(first); + + /* Create a function on lambda */ + if(StrEquals(funcName, "lambda")){ + return ParseFunction(tr); + } + + /* Create a macro on mambda */ + if(StrEquals(funcName, "mambda")){ + return ParseMacro(tr); + } + + /* Create a local variable binding on set */ + else if(StrEquals(funcName, "set")){ + /* Create a variable binding and return the value held by it */ + VyParseTree* varName = GetListData(tr, 1); + char* strVarName = GetStrData(varName); + + VyObject varValue = Eval(GetListData(tr, 2)); + + /* Try looking for the object in the local scope */ + if(FindValue(GetLocalScope(), strVarName) >= 0){ + SetVariable(GetLocalScope(), strVarName, varValue); + } + else if(FindValue(GetCurrentFunctionScope(), strVarName) >= 0){ + SetVariable(GetCurrentFunctionScope(), strVarName, varValue); + } + else if(FindValue(GetGlobalScope(), strVarName) >= 0){ + SetVariable(GetGlobalScope(), strVarName, varValue); + } + + /* Add it to the scope */ + SetVariable(GetLocalScope(), strVarName, varValue); + + return varValue; + } + + /* Create a global variable binding on global */ + else if(StrEquals(funcName, "global")){ + /* Create a variable binding and return the value held by it */ + VyParseTree* varName = GetListData(tr, 1); + char* strVarName = GetStrData(varName); + VyObject varValue = Eval(GetListData(tr, 2)); + + /* Add it to the scope */ + VarBinding* var = CreateVariable(strVarName, varValue); + AddVariable(GetGlobalScope(), var); + + return varValue; + } + + /* If statements */ + else if(StrEquals(funcName, "if")){ + /* Evaluate the condition */ + VyObject cond = Eval(GetListData(tr, 1)); + + /* Check that the condition evaluates to a boolean value */ + if(ObjType(cond) == VALBOOL){ + VyBoolean** b = ObjData(cond); + + /* Based on the value of the boolean, either evaluate the first or second parts */ + if(IsTrue(b)){ + return Eval(GetListData(tr, 2)); + } else { + if(ListTreeSize(tr) < 4){ + return ToObject(b); + } + return Eval(GetListData(tr, 3)); + } + } + /* Dont generate double-errors */ + else if(ObjType(cond) == VALERROR){ + return cond; + } + + /* If the condition doesn't evaluate to a boolean, error */ + else { + return ToObject(CreateError("Invalid boolean variable (condition must evaluate to boolean). ", GetListData(tr, 1))); + } + } + + /* The quote operator */ + if(StrEquals(funcName, "quote")){ + return QuotedEval(GetListData(tr, 1), 0); + } + + /* The substituting quote operator */ + else if(StrEquals(funcName, "quote-substitutions")){ + return QuotedEval(GetListData(tr, 1), 1); + } + + /* Implement tagbody/go */ + else if(StrEquals(funcName, "tagbody")){ + /* Build up the array containing the tagbody tags so go knows where to go */ + int tags = ListTreeSize(tr) - 1; + char** tagNames = malloc(sizeof(char*) * tags); + + int i; + for(i = 0; i < tags; i++){ + VyParseTree* tagTree = GetListData(tr, i + 1); + if(tagTree->type != TREE_LIST){ + return ToObject(CreateError("Tagbody tags must be wrapped in a list. ", tr)); + } + + VyParseTree* tagNameIdent = GetListData(tagTree, 0); + if(tagNameIdent->type != TREE_IDENT){ + return ToObject(CreateError("Tag name must be an identifier. ", tagNameIdent)); + } + char* name = GetStrData(tagNameIdent); + tagNames[i] = name; + } + + /* Eval statements sequencially, storing the last value, and going places on go */ + VyObject lastValue; + int currentTagNumber = 0; + while(currentTagNumber < tags){ + VyParseTree* currentTag = GetListData(tr, currentTagNumber + 1); + int numExprs = ListTreeSize(currentTag) - 1; + + /* Assume that you will go to the next tag afterwards */ + currentTagNumber++; + + for(i = 0; i < numExprs; i++){ + /* Evaluate the expression, go if needed, otherwise keep on eval'ing */ + VyParseTree* expr = GetListData(currentTag, i + 1); + lastValue = Eval(expr); + + /* Check and jump for go */ + if(ObjType(lastValue) == VALFLOW){ + VyFlowControl** ctrl = ObjData(lastValue); + if(ctrl[0]->type == FLOWGO){ + /* Find the number of this tag */ + char* goTo = ctrl[0]->data; + int tagNumberToGoTo; + int d; + for(d = 0; d < tags; d++){ + if(StrEquals(tagNames[d], goTo)){ + tagNumberToGoTo = d; + break; + } + } + + /* Now jump by changing what tag it's on right now and breaking out of the sequencial eval loop */ + currentTagNumber = tagNumberToGoTo; + break; + + } + } + else if(ObjType(lastValue) == VALERROR){ + return lastValue; + } + + } + } + + free(tagNames); + return lastValue; + + } + + else if(StrEquals(funcName, "go")){ + char* goToTag = GetStrData(GetListData(tr, 1)); + return ToObject(CreateFlowControl(FLOWGO,goToTag)); + } + + /* Or perform the given function */ + else{ + /* Find the function with the given name */ + VyObject func = FindObjAllScopes(funcName); + + /* If it was found, continue */ + if(func >= 0){ + /* Either return the evaluation of the function */ + if(ObjType(func) == VALFUNC){ + VyObject val = PerformFunction(ObjData(func), tr); + return val; + } + /* Or expand and evaluate the macro */ + else if(ObjType(func) == VALMAC){ + + VyObject result = ExpandMacro(ObjData(func), tr); + return result; + } + /* Otherwise, function not found */ + else{ + int size = strlen("Cannot call a non-executable data type: ") + strlen(funcName) + 1; + char* str = malloc(size); + sprintf(str, "%s%s", "Cannot call a non-executable data type: ", funcName); + return ToObject(CreateError(str, tr)); + } + } + else { + int size = strlen("Callable not found: ") + strlen(funcName) + 1; + char* str = malloc(size); + sprintf(str, "%s%s", "Callable not found: ", funcName); + return ToObject(CreateError(str, tr)); + } + } + + } + /* If the first element is a list, it may be a lambda */ + else if(first->type == TREE_LIST){ + VyObject firstVal = Eval(first); + /* If it is a function or macro, then run it */ + if(ObjType(firstVal) == VALFUNC){ + VyObject result = PerformFunction(ObjData(firstVal), tr); + return result; + } + else if(ObjType(firstVal) == VALMAC){ + VyObject result = ExpandMacro(ObjData(firstVal), tr); + return result; + + } + /* If it isn't, then just treat it as a block, and evaluate each expression and return the value of the last one */ + else{ + VyObject lastValue = firstVal; + int i; + for(i = 1; i < ListTreeSize(tr); i++){ + lastValue = Eval(GetListData(tr, i)); + if(ObjType(lastValue) == VALERROR){ + return lastValue; + } + } + return lastValue; + } + + } + + } + + /* Evaluate it to itself if it is a number */ + else if(tr->type == TREE_NUM){ + return ToObject(GetNumberData(tr)); + } + + /* If it is an ident, look for it in the current scope */ + else if(tr->type == TREE_IDENT){ + char* varName = GetStrData(tr); + + VyObject val = FindObjAllScopes(varName); + + /* If the variable isn't found, error */ + if(val < 0){ + int size = strlen("Variable not found: ") + strlen(varName) + 1; + char* str = malloc(size); + sprintf(str, "%s%s", "Variable not found: ", varName); + return ToObject(CreateError(str, NULL)); + } + + return val; + } + + /* If the type is weird, return null */ + printf("Error occured in Eval(), see last line, it SHOULD NOT GET HERE!"); + exit(0); + return 0; + +} + +/* Evaluate a quoted expression: in other words, convert the parse tree into an object. Lists are still lists, identifiers are symbols, etc. */ +VyObject QuotedEval(VyParseTree* tr, int doSubstitutions){ + + /* An identifier becomes a symbol */ + if(tr->type == TREE_IDENT){ + VySymbol** symb = CreateSymbol(GetStrData(tr)); + return ToObject(symb); + } + + /* A parse tree list becomes a value list */ + else if(tr->type == TREE_LIST){ + /* A list may be a substitution */ + if(IsSubstitution(tr) && doSubstitutions){ + /* Return the normal Eval of the data */ + VyParseTree* data = GetListData(tr, 1); + return Eval(data); + } + + VyList** l = CreateList(); + + /* Add the elements to the list one by one */ + int listElements = ListTreeSize(tr); + int i; + for(i = 0; i < listElements; i++){ + VyParseTree* nextParseTree = GetListData(tr, i); + + /* Since we're in a list, check for splicing substitutions */ + if(IsSplicingSubstitution(nextParseTree) && doSubstitutions){ + /* Get the resulting list */ + VyObject list = Eval(GetListData(nextParseTree, 1)); + + if(ObjType(list) != VALLIST){ + return ToObject(CreateError("A splicing substitution operates only on lists.", tr)); + } + + /* Add each of it's elements to the list */ + int size = ListSize(ObjData(list)); + int i; + for(i = 0; i < size; i++){ + l = ListAppend(l, ListGet(ObjData(list), i)); + } + + } + else{ + l = ListAppend(l, QuotedEval(nextParseTree, doSubstitutions)); + } + } + + return ToObject(l); + } + + /* A number when quoted is still a number */ + else if(tr->type == TREE_NUM){ + return Eval(tr); + } + + printf("Whoa! Wrong type! QuotedEval()"); + exit(0); + return -1; +} + +/* Define all the built-in functions as wrappers over the other functions. + * Note, however: all argument validation must be done IN THE WRAPPERS if possible, + * because the real functions don't have the option to return VyError**'s, making error + * detection and printing much harder. + */ + +/* Wrappers around list functions */ +VyObject LHead(VyFunction** f, VyObject* args, int argNum){ + return ListHead(ObjData(args[0])); +} +VyObject LTail(VyFunction** f, VyObject* args, int argNum){ + return ToObject(ListTail(ObjData(args[0]))); +} +VyObject LGet(VyFunction** f, VyObject* args, int argNum){ + if(GetInt(ObjData(args[1])) > ListSize(ObjData(args[0]))){ + return ToObject(CreateError("List index out of bounds.", NULL)); + } + return ListGet(ObjData(args[0]), GetInt(ObjData(args[1]))); +} +VyObject LSize(VyFunction** f, VyObject* args, int argNum){ + return ToObject(CreateInt(ListSize(ObjData(args[0])))); +} +VyObject LInsert(VyFunction** f, VyObject* args, int argNum){ + return ToObject(ListInsert(ObjData(args[0]), args[1], GetInt(ObjData(args[2])))); +} + +/* Wrapper functions around arithmetic */ +VyObject AddValues(VyFunction** f, VyObject* args, int argNum){ + VyNumber** result = CreateInt(0); + + int i; + for(i = 0; i < argNum; i++){ + VyNumber** temp = AddNumbers(result, ObjData(args[i])); + result = temp; + } + + VyObject resultValue = ToObject(result); + return resultValue; +} +VyObject MultValues(VyFunction** f, VyObject* args, int argNum){ + VyNumber** result = CreateInt(1); + + int i; + for(i = 0; i < argNum; i++){ + VyNumber** temp = MultiplyNumbers(result, ObjData(args[i])); + result = temp; + } + + VyObject resultValue = ToObject(result); + return resultValue; +} +VyObject DivValues(VyFunction** f, VyObject* args, int argNum){ + VyNumber** one = ObjData(args[0]); + VyNumber** two = ObjData(args[1]); + + VyNumber** result = DivideNumbers(one, two); + VyObject resultValue = ToObject(result); + return resultValue; +} +VyObject ExpValues(VyFunction** f, VyObject* args, int argNum){ + VyNumber** one = ObjData(args[0]); + VyNumber** two = ObjData(args[1]); + + /* A number cannot be raised to an complex power yet */ + if(two[0]->type == COMPLEX){ + return ToObject(CreateError("Cannot raise number to complex power.", NULL)); + } + + VyNumber** result = ExponentiateNumber(one, two); + VyObject resultValue = ToObject(result); + return resultValue; +} +VyObject SubtractValues(VyFunction** f, VyObject* args, int argNum){ + /* Make (-) return 0 for now */ + if(argNum == 0){ + return ToObject(CreateInt(0)); + } + + VyNumber** result = ObjData(args[0]); + int i; + for(i = 1; i < argNum; i++){ + VyNumber** temp = SubtractNumbers(result, ObjData(args[i])); + result = temp; + } + + VyObject resultValue = ToObject(result); + return resultValue; +} + +/* Wrappers around all the boolean and number comparison functions */ +VyObject BAnd(VyFunction** f, VyObject* args, int argNum){ + VyBoolean** result = MakeTrueBool(); + + int i; + for(i = 0; i < argNum; i++){ + result = BoolAnd(result, ObjData(args[i])); + } + + VyObject resultValue = ToObject(result); + return resultValue; + +} +VyObject BOr(VyFunction** f, VyObject* args, int argNum){ + VyBoolean** result = MakeFalseBool(); + + int i; + for(i = 0; i < argNum; i++){ + result = BoolOr(result, ObjData(args[i])); + } + + VyObject resultValue = ToObject(result); + return resultValue; + +} +VyObject BXor(VyFunction** f, VyObject* args, int argNum){ + VyBoolean** result = MakeFalseBool(); + + int i; + for(i = 0; i < argNum; i++){ + result = BoolXor(result, ObjData(args[i])); + } + + VyObject resultValue = ToObject(result); + return resultValue; + +} +VyObject BNot(VyFunction** f, VyObject* args, int numArgs){ + return ToObject(BoolNot(ObjData(args[0]))); +} + +VyObject LT(VyFunction** f, VyObject* args, int numArgs){ + VyNumber** one = ObjData(args[0]); + VyNumber** two = ObjData(args[1]); + if(one[0]->type == COMPLEX || two[0]->type == COMPLEX){ + return ToObject(CreateError("Operations > and < are undefined on complex numbers.", NULL)); + } + + return ToObject(LessThan(one, two)); +} +VyObject GT(VyFunction** f, VyObject* args, int numArgs){ + VyNumber** one = ObjData(args[0]); + VyNumber** two = ObjData(args[1]); + if(one[0]->type == COMPLEX || two[0]->type == COMPLEX){ + return ToObject(CreateError("Operations > and < are undefined on complex numbers.", NULL)); + } + + return ToObject(GreaterThan(one, two)); +} +VyObject LTE(VyFunction** f, VyObject* args, int numArgs){ + VyNumber** one = ObjData(args[0]); + VyNumber** two = ObjData(args[1]); + if(one[0]->type == COMPLEX || two[0]->type == COMPLEX){ + return ToObject(CreateError("Operations > and < are undefined on complex numbers.", NULL)); + } + + return ToObject(LessThanOrEqual(one, two)); +} +VyObject GTE(VyFunction** f, VyObject* args, int numArgs){ + VyNumber** one = ObjData(args[0]); + VyNumber** two = ObjData(args[1]); + if(one[0]->type == COMPLEX || two[0]->type == COMPLEX){ + return ToObject(CreateError("Operations > and < are undefined on complex numbers.", NULL)); + } + + return ToObject(GreaterThanOrEqual(one, two)); +} +VyObject EQ(VyFunction** f, VyObject* args, int numArgs){ + VyNumber** one = ObjData(args[0]); + VyNumber** two = ObjData(args[1]); + + return ToObject(Equal(one, two)); +} +VyObject NEQ(VyFunction** f, VyObject* args, int numArgs){ + VyNumber** one = ObjData(args[0]); + VyNumber** two = ObjData(args[1]); + + return ToObject(NotEqual(one, two)); +} +VyObject GeneralEQ(VyFunction** f, VyObject* args, int numArgs){ + /* All args must be same type */ + int i; + for(i = 0; i < numArgs - 1; i++){ + if(ObjType(args[i]) !=ObjType( args[i + 1])){ + return ToObject(MakeFalseBool()); + } + } + + /* Now check for equality (unless it is a number, just check pointer equality) */ + for(i = 0; i < numArgs - 1; i++){ + if(ObjType(args[i]) == VALNUM){ + if(NotEqual(ObjData(args[i]), ObjData(args[i + 1]))){ + return ToObject(MakeFalseBool()); + } + } + if(ObjType(args[i]) == VALSYMB){ + char* one = GetSymbolString(ObjData(args[i])); + char* two = GetSymbolString(ObjData(args[i + 1])); + if(!StrEquals(one, two)){ + return ToObject(MakeFalseBool()); + } + } + else{ + if(args[i] != args[i + 1]){ + return ToObject(MakeFalseBool()); + } + } + } + + /* If all test passed, then they're equal */ + return ToObject(MakeTrueBool()); +} + +/* IO Functions */ +VyObject ObjPrint(VyFunction** f, VyObject* args, int numArgs){ + int i; + for(i = 0; i < numArgs; i++){ + PrintObj(args[i]); + } + + if(numArgs == 0) return 0; + return args[numArgs - 1]; +} +VyObject ObjPrintLine(VyFunction** f, VyObject* args, int numArgs){ + int i; + for(i = 0; i < numArgs; i++){ + PrintObj(args[i]); + printf("\n"); + } + + if(numArgs == 0) return 0; + return args[numArgs - 1]; +} + +/* Type checking functions */ +VyObject IsList(VyFunction** f, VyObject* args, int numArgs){ + if(ObjType(args[0]) != VALLIST){ + return ToObject(MakeFalseBool()); + } + return ToObject(MakeTrueBool()); +} +VyObject IsSymbol(VyFunction** f, VyObject* args, int numArgs){ + if(ObjType(args[0]) != VALSYMB){ + return ToObject(MakeFalseBool()); + } + return ToObject(MakeTrueBool()); +} +VyObject IsFunction(VyFunction** f, VyObject* args, int numArgs){ + if(ObjType(args[0]) != VALFUNC){ + return ToObject(MakeFalseBool()); + } + return ToObject(MakeTrueBool()); +} +VyObject IsMacro(VyFunction** f, VyObject* args, int numArgs){ + if(ObjType(args[0]) != VALMAC){ + return ToObject(MakeFalseBool()); + } + return ToObject(MakeTrueBool()); +} +VyObject IsNum(VyFunction** f, VyObject* args, int numArgs){ + if(ObjType(args[0]) != VALNUM){ + return ToObject(MakeFalseBool()); + } + return ToObject(MakeTrueBool()); +} +VyObject IsError(VyFunction** f, VyObject* args, int numArgs){ + if(ObjType(args[0]) != VALERROR){ + return ToObject(MakeFalseBool()); + } + return ToObject(MakeTrueBool()); +} +VyObject IsBool(VyFunction** f, VyObject* args, int numArgs){ + if(ObjType(args[0]) != VALBOOL){ + return ToObject(MakeFalseBool()); + } + return ToObject(MakeTrueBool()); +} + +/* Generate a guaranteed unique symbol */ +int symbol = -1; +VyObject GenSymb(VyFunction** f, VyObject* args, int numArgs){ + symbol++; + + /* Count the digits in the symbol number */ + int digits = 0; + int counter = 1; + while(symbol < (10^counter)){ + counter++; + digits++; + } + + /* Allocate enough space for the digit string and an extra character */ + char* genSymbStr = malloc((digits + 3)*sizeof(char)); + sprintf(genSymbStr, "#-%d", symbol); + + return ToObject(CreateSymbol(genSymbStr)); +} + +/* A temporary namespace thing */ +void ProcessFile(char*); +VyObject RequireFile(VyFunction** f, VyObject* args, int numArgs){ + VyObject name = args[0]; + VySymbol** symb = ObjData(name); + char* fileName = GetSymbolString(symb); + + ProcessFile(fileName); + + return ToObject(MakeTrueBool()); +} + +int InitEvaluator(){ + + InitMem(); + + /* Initialize scopes (before functions because functions use scopes) */ + InitScopes(); + + /* Initialize all the built-in functions */ + Argument** args = NULL; + + AddFunction("+", CreateBuiltinFunction(args, 1, &AddValues )); + AddFunction("-", CreateBuiltinFunction(args, 1, &SubtractValues)); + AddFunction("*", CreateBuiltinFunction(args, 1, &MultValues)); + AddFunction("/", CreateBuiltinFunction(args, 2, &DivValues)); + AddFunction("**", CreateBuiltinFunction(args, 2, &ExpValues)); + + AddFunction("head", CreateBuiltinFunction(args, 1, &LHead)); + AddFunction("tail", CreateBuiltinFunction(args, 1, <ail)); + AddFunction("nth", CreateBuiltinFunction(args, 2, &LGet)); + AddFunction("len", CreateBuiltinFunction(args, 1, &LSize)); + AddFunction("insert", CreateBuiltinFunction(args, 3, &LInsert)); + + AddFunction("&", CreateBuiltinFunction(args, 1, &BAnd)); + AddFunction("|", CreateBuiltinFunction(args, 1, &BOr)); + AddFunction("xor", CreateBuiltinFunction(args, 1, &BXor)); + AddFunction("not", CreateBuiltinFunction(args, 1, &BNot)); + + AddFunction("<", CreateBuiltinFunction(args, 2, <)); + AddFunction(">", CreateBuiltinFunction(args, 2, >)); + AddFunction("<=", CreateBuiltinFunction(args, 2, <E)); + AddFunction(">=", CreateBuiltinFunction(args, 2, >E)); + AddFunction("=", CreateBuiltinFunction(args, 2, &EQ)); + AddFunction("!=", CreateBuiltinFunction(args, 2, &NEQ)); + AddFunction("eq", CreateBuiltinFunction(args, 2, &GeneralEQ)); + + AddFunction("print", CreateBuiltinFunction(args, 1, &ObjPrint)); + AddFunction("print-line", CreateBuiltinFunction(args, 1, &ObjPrintLine)); + + AddFunction("include", CreateBuiltinFunction(args, 1, &RequireFile)); + + AddFunction("number?", CreateBuiltinFunction(args, 1, &IsNum)); + AddFunction("function?", CreateBuiltinFunction(args, 1, &IsFunction)); + AddFunction("list?", CreateBuiltinFunction(args, 1, &IsList)); + AddFunction("symbol?", CreateBuiltinFunction(args, 1, &IsSymbol)); + AddFunction("boolean?", CreateBuiltinFunction(args, 1, &IsBool)); + AddFunction("macro?", CreateBuiltinFunction(args, 1, &IsMacro)); + AddFunction("error?", CreateBuiltinFunction(args, 1, &IsError)); + + AddFunction("unique", CreateBuiltinFunction(args, 0, &GenSymb)); + + + + /* Initialize built-in globals */ + AddVariable(GetGlobalScope(), CreateVariable("true!", ToObject(MakeTrueBool()))); + AddVariable(GetGlobalScope(), CreateVariable("false!", ToObject(MakeFalseBool()))); + + + + return 1; +} +void ProcessFile(char* filename){ + /* Parse the file, and if no errors exist, evaluate the expressions */ + VyParseTree* exprList = ParseFile(filename); + + if(exprList != NULL && !CheckAndPrintErrors(exprList)){ + /* Evaluate each expression and, if error, print and exit */ + int i; + for(i = 0; i < ListTreeSize(exprList); i++){ + VyParseTree* next = GetListData(exprList, i); + VyObject val = Eval(next); + + if(ObjType(val) == VALERROR){ + HandleError(val); + } + + } + } +} + +/* Given a char list, check that all parens balance */ +int AllParensClosed(CharList* list){ + int counting = 1; + int parens = 0; + + int c; + for(c = 0; c < Size(list); c++){ + char next = Get(list, c); + if(counting){ + if(next == '('){ + parens++; + } + else if(next == ')'){ + parens--; + } + } + } + + if(parens == 0){ + return 1; + }else{ + return 0; + } +} + +/* The read eval print loop */ +void ReadEvalPrintLoop(){ + CharList** prevInputs = NULL; + int numInputs = 0; + char c; + + /* Let the user enter expressions and evaluate them */ + while(c != EOF){ + printf("V >> "); + fflush(stdout); + + /* Get user input */ + CharList* strList = MakeCharList(); + while(1){ + c = getchar(); + /* On entered newline, if all parenthesis balance, stop, otherwise continue data enterage */ + if(c == '\n' && AllParensClosed(strList)){ + break; + }else if(c == '\n'){ + printf(" "); + } + + Add(strList, c); + } + + numInputs++; + prevInputs = realloc(prevInputs, numInputs*sizeof(CharList*)); + prevInputs[numInputs - 1] = strList; + + /* Lex, parse, eval */ + char* str = ToStr(strList); + + /* For convenience, exit when the user types "exit" and "quit" */ + if(StrEquals(str, "exit") || StrEquals(str, "quit")){ + exit(1); + } + + Lex(str); + if(GetNumTokens() == 0){ + continue; + } + + /* Look for errors, if none found, eval and print result */ + VyParseTree* tree = Parse(); + if(!CheckAndPrintErrors(tree)){ + VyObject val = Eval(tree); + printf("\n"); + PrintObj(val); + printf("\n"); + } + + /* Free various resources */ + CleanLexer(); + CleanParser(); + free(str); + } +} + +int main(int argc, char** argv){ + InitEvaluator(); + + /* If given filenames, process all that are given, otherwise enter the read-eval-print-loop */ + if(argc >= 2){ + replMode = 0; + int file; + for(file = 1; file < argc; file++){ + ProcessFile(argv[file]); + } + } + else{ + replMode = 1; + ReadEvalPrintLoop(); + } + + /* Free memory */ + FreeHeap(GetMemoryHeap()); + + return 1; +} diff --git a/old/lisp-lang/FlowControl.c b/old/lisp-lang/FlowControl.c new file mode 100644 index 0000000..161df9c --- /dev/null +++ b/old/lisp-lang/FlowControl.c @@ -0,0 +1,9 @@ +#include "Vyion.h" + +VyFlowControl** CreateFlowControl(int type, void* data){ + VyFlowControl** ctrl = CreateFlowControlObj(); + ctrl[0]->type = type; + ctrl[0]->data = data; + + return ctrl; +} diff --git a/old/lisp-lang/Function.c b/old/lisp-lang/Function.c new file mode 100644 index 0000000..9cbd014 --- /dev/null +++ b/old/lisp-lang/Function.c @@ -0,0 +1,444 @@ +#include "Vyion.h" + +/***** Create function objects *****/ + +/* Create a builtin function */ +VyFunction** CreateBuiltinFunction(Argument** args, int argNum, VyObject (*builtin)(VyFunction**, VyObject*,int)){ + VyFunction** func = CreateFuncObj(); + func[0]->numArgs = argNum; + func[0]->args = args; + func[0]->EvalFunction = builtin; + + return func; +} + +/* Create a native function */ +VyFunction** CreateNativeFunction(Argument** args, int argNum, VyParseTree* code, Scope* funcScope){ + /* Use the builtin function EvalNativeFunction, which evaluates a ParseTree as a */ + /* function, to create a VyFunction** for a native lisp function */ + VyFunction** nativeFunc = CreateBuiltinFunction(args, argNum, &EvalNativeFunction); + nativeFunc[0]->code = code; + nativeFunc[0]->scp = funcScope; + return nativeFunc; +} + +/* Set a function scope */ +void SetFunctionScope(VyFunction** f, Scope* scp){ + f[0]->scp = scp; +} + +/***** Functions dealing with Argument*s *****/ + +/* Create an argument */ +Argument* CreateArgument(int argCode, char* symbName, int valType){ + Argument* arg = malloc(sizeof(Argument)); + arg->argCode = argCode; + arg->name = symbName; + arg->type = valType; + arg->optArgDefault = -1; + return arg; +} + +/* Use the argument codes to check if it is an optional argument */ +inline int IsOptionalArg(Argument* arg){ + /* All optional arguments have an odd argument code */ + if(arg->argCode == ARGOPTIONAL || arg->argCode == ARGNAMEDOPTIONAL){ + return 1; + } + + return 0; +} + +/* Use the argument codes to check if it is a rest argument */ +int IsRestArg(Argument* arg){ + /* All rest arguments have an argument codes greater than or equal to 100 */ + if(arg->argCode == ARGREST){ + return 1; + } + + return 0; +} + +/* Use the argument code to check if it is a named argument */ +int IsNamedArg(Argument* arg){ + /* Named arguments are greater than 1 and less than 100 or greater than 101 */ + if(arg->argCode == ARGNAMED || arg->argCode == ARGNAMEDOPTIONAL){ + return 1; + } + + return 0; +} + +/***** Functions for running both built-in and native functions */ + +/* Check the validity of a function's arguments */ +char* CheckFunctionArguments(Argument** funcArgs, int funcNumArgs, VyObject* args, int numArgs){ + /* Make sure there are arguments to validate against */ + if(funcArgs == NULL){ + return NULL; + } + if(funcNumArgs == 0){ + if(numArgs > 0){ + char* message = "Too many arguments to function."; + return (message); + } + return NULL; + } + + /* Total number of arguments */ + /* Check if this function has a rest argument */ + if(!IsRestArg(funcArgs[funcNumArgs - 1])){ + /* If it doesn't, check that too many arguments aren't given */ + if(numArgs > funcNumArgs){ + char* message = "Too many arguments to function."; + return (message); + } + } + + /* Find the number of required args */ + int requiredArgs = 0; + while(funcNumArgs > requiredArgs && !IsOptionalArg(funcArgs[requiredArgs])){ + requiredArgs++; + } + + /* Check that all of them have been satisfied */ + if(numArgs < requiredArgs){ + /* If they haven't, error */ + return ("Unsatisfied arguments."); + } + + return NULL; +} + +/* Bind arguments to variables in the local scope */ +void CreateArgumentVariableBindings(Argument** funcArgs, int funcNumArgs, VyObject* args, int numArgs){ + + /* Bind all given values to variables */ + int i; + for(i = 0; i < numArgs; i++){ + Argument* currArg = funcArgs[i]; + char* argName = currArg->name; + + /* If it is a rest argument, then put the rest of the arguments in a list and bind that list to the variable, then exit */ + if(IsRestArg(currArg)){ + /* Put the rest of the arguments in a list */ + int nonRestArgs = i; + VyList** rest = CreateList(); + int c; + for(c = nonRestArgs; c < numArgs; c++){ + rest = ListAppend(rest, args[c]); + } + + /* Bind the list value to the name */ + VyObject listVal = ToObject(rest); + SetVariable(GetLocalScope(), argName, listVal); + + /* Exit this procedure, since there are no more arguments left to bind */ + return; + } + + /* Otherwise, just set the variable */ + SetVariable(GetLocalScope(), argName, args[i]); + } + + /* Now, bind optional arguments that haven't yet been bound */ + for(i = numArgs; i < funcNumArgs; i++){ + Argument* currArg = funcArgs[i]; + SetVariable(GetLocalScope(), currArg->name, currArg->optArgDefault); + } +} + +/* Evaluate a native function, which can be a macro too */ +VyObject EvalNativeFunctionOrMacro(Argument** funcArgs, int funcNumArgs, VyParseTree* code, Scope* scp, VyObject* args, int numArgs){ + /* Push the previous scope on the scope stack and add a new scope for this function call */ + PushScope(GetLocalScope()); + SetLocalScope(CreateScope()); + + /* Since the arguments are valid, bind them to variables in the local */ + CreateArgumentVariableBindings(funcArgs, funcNumArgs, args, numArgs); + + /* Set the current function scope */ + SetCurrentFunctionScope(scp); + + /* Keep track of the last value, for this is what is returned */ + VyObject lastValue; + + /* Sequencially evaluate each expression and store the result in the last value */ + int i; + for(i = 0; i < ListTreeSize(code); i++){ + lastValue = Eval(GetListData(code, i)); + + /* If an error occurred, return it */ + if(ObjType(lastValue) == VALERROR){ + return lastValue; + } + } + + /* Delete the scope (NOTE: REMOVE THIS LATER WHEN GC COMES AROUND) */ + DeleteScope(GetLocalScope()); + + /* Return to the previous scope */ + SetLocalScope(PopScope()); + + return lastValue; + +} + +/* Evaluate a native function (not a macro) */ +VyObject EvalNativeFunction(VyFunction** func, VyObject* args, int numArgs){ + return EvalNativeFunctionOrMacro(func[0]->args, func[0]->numArgs, func[0]->code, func[0]->scp, args, numArgs); +} + +/* Evaluate a function for the given arguments */ +VyObject RunFunction(VyFunction** func, VyObject* args, int numArgs){ + /* Check the function's arguments, and if they are invalid, error */ + char* err = CheckFunctionArguments(func[0]->args, func[0]->numArgs, args, numArgs); + if(err != NULL){ + return ToObject(CreateError(err, NULL)); + } + + /* Evaluate the function by calling the function pointer in it */ + return func[0]->EvalFunction(func, args, numArgs); + +} + +/***** Functions for parsing, storing, and retrieving functions */ + +/* Parse a single argument */ +Argument* ParseArgument(VyParseTree* arg, VyParseTree* prevTree){ + /* Create an argument with default values */ + Argument* result = CreateArgument(0, NULL, VALUNDEF); + + /* A simple argument */ + if(arg->type == TREE_IDENT){ + /* Set the variable name */ + result->name = GetStrData(arg); + } + + /* An optional, named, or rest argument */ + else if(arg->type == TREE_LIST){ + /* Check the previous parse tree to see whether it is optional, named, or rest */ + char* lastTreeIdent = GetStrData(prevTree); + + /* Optional */ + if(strcmp(lastTreeIdent, "?") == 0){ + /* Make it an optional argument */ + result->argCode = ARGOPTIONAL; + + /* Find the name */ + result->name = GetStrData(GetListData(arg, 0)); + + /* Find the default value */ + result->optArgDefault = Eval(GetListData(arg, 1)); + + } + + /* Named */ + else if(strcmp(lastTreeIdent, "~") == 0){ + /* Make it named */ + result->argCode = ARGNAMED; + + /* Get the name */ + char* namedName = GetStrData(GetListData(arg, 0)); + result->name = namedName; + } + + /* Rest */ + else if(strcmp(lastTreeIdent, "&") == 0){ + /* Make it a rest argument */ + result->argCode = ARGREST; + + /* Get the argument name */ + result->name = GetStrData(GetListData(arg, 0)); + } + + /* Named optional */ + else if(strcmp(lastTreeIdent, "~?") == 0){ + /* Make it a named optional argument */ + result->argCode = ARGNAMEDOPTIONAL; + + /* Get the name and default value */ + result->name = GetStrData(GetListData(arg, 0)); + result->optArgDefault = Eval(GetListData(arg, 1)); + } + } + + return result; +} + +/* Parse a function's arguments */ +Argument** ParseFunctionArguments(VyParseTree* argList, int* storeNumArgs, char** errorStore){ + /* Find the number of arguments (but don't count ? ~ and &s) */ + int argNums = 0; + int c; + for(c = 0; c < ListTreeSize(argList); c++){ + /* Get the argument and check if it is ? or & or ~*/ + VyParseTree* currentArg = GetListData(argList, c); + + /* If it isn't, increment the number of arguments */ + if(currentArg->type == TREE_IDENT){ + char* argStr = GetStrData(currentArg); + /* Check that it isn't a ? or ~ */ + if(strcmp("?", argStr) != 0 && strcmp("~", argStr) != 0 && strcmp("~?", argStr) != 0){ + argNums++; + } + + /* If it is a &, this is the last argument, so break (it has already been counted above) */ + if(strcmp("&", argStr) == 0){ + break; + } + }else{ + argNums++; + } + } + *storeNumArgs = argNums; + + /* Mallocate an array of arguments of the right size */ + Argument** argArray = malloc( sizeof(Argument*) * (*storeNumArgs) ); + + /* When parsing arguments, make sure that optional arguments are all after normal ones */ + int optionArgumentsStarted = 0; + + /* Parse each argument */ + int i; + int argumentsFilled = 0; + for(i = 0; i < ListTreeSize(argList); i++){ + /* Get the previous argument (or NULL if this is first one) */ + VyParseTree* prev = NULL; + if(i > 0) { + prev = GetListData(argList, i - 1); + } + + /* Check that this isn't the symbol for optional or rest arguments */ + VyParseTree* currentArg = GetListData(argList, i); + + /* If it is a special symbol, not an argument, just skip this argument */ + if(currentArg->type == TREE_IDENT && (strcmp("?", GetStrData(currentArg)) == 0 || strcmp("~?", GetStrData(currentArg)) == 0 || strcmp("~", GetStrData(currentArg)) == 0 || (strcmp("&", GetStrData(currentArg)) == 0))){ + continue; + } + + /* Parse each separate argument */ + Argument* arg = ParseArgument(currentArg, prev); + + /* Optional arguments already? */ + if(IsOptionalArg(arg)){ + optionArgumentsStarted = 1; + } + + /* Make sure optional arguments come after normal ones, and if not, error */ + if(optionArgumentsStarted && !IsOptionalArg(arg)){ + /* It can also be a rest argument */ + if(!IsRestArg(arg)){ + *errorStore = "Optional arguments must come last."; + return NULL; + } + } + + /* Make sure rest arguments are last */ + if(IsRestArg(arg) && i != ListTreeSize(argList) - 1){ + *errorStore = "Rest arguments must come last."; + return NULL; + } + + + /* Add the argument to the argument array */ + argArray[argumentsFilled] = arg; + argumentsFilled++; + + /* If this is a rest argument, then no more arguments are possible */ + if(IsRestArg(arg)){ + break; + } + } + + /* Next, order the arguments in the following order: required named, required positional, optional named, required named, rest. */ + + /* Use a modified version of Bubble sort */ + int changes = 1; + int firstOptArg = 0; + + /* First sort the required arguments */ + while(changes){ + changes = 0; + int d; + + /* Iterate through all the elements until you reach the end or an optional argument */ + for(d = 0; d < argNums - 1 && !IsOptionalArg(argArray[d + 1]); d++){ + /* Store the starting place for the next sorting routine */ + firstOptArg = d; + + /* Move named arguments to the left */ + if(IsNamedArg(argArray[d + 1]) && !IsNamedArg(argArray[d])){ + Argument* temp = argArray[d]; + argArray[d] = argArray[d + 1]; + argArray[d + 1] = temp; + + changes = 1; + } + } + + } + + /* Next, sort optional arguments */ + changes = 1; + while(changes){ + changes = 0; + int d; + /* Iterate through all the elements until you reach the end, starting at the first optional argument + * (but make sure to add two so that it doesn't accidentally switch an argument too far to the left) */ + for(d = firstOptArg + 2; d < argNums - 1; d++){ + /* Move named arguments to the left */ + if(IsNamedArg(argArray[d + 1]) && !IsNamedArg(argArray[d])){ + Argument* temp = argArray[d]; + argArray[d] = argArray[d + 1]; + argArray[d + 1] = temp; + + changes = 1; + + } + } + } + + return argArray; +} + +/* Parse a nameless function given a lambda list */ +VyObject ParseFunction(VyParseTree* code){ + /* Parse the function arguments */ + VyParseTree* args = GetListData(code, 1); + int numArguments = 0; + char* err = NULL; + Argument** arguments = ParseFunctionArguments(args, &numArguments, &err); + if(err != NULL){ + return ToObject(CreateError(err, code)); + } + + /* Take the rest of the expressions in the lambda as code */ + VyParseTree* exprList = MakeListTree(); + int i; + for(i = 2; i < ListTreeSize(code); i++){ + AddToList(exprList, GetListData(code, i)); + } + + /* Take variables from the current function scope and the local scope */ + Scope* funcScope = GetCurrentFunctionScope(); + Scope* localScope = GetLocalScope(); + + /* Make sure the local scope isn't the global scope */ + if(localScope == GetGlobalScope()) { + localScope = NULL; + } + + /* Merge the two scopes to get the current function scope */ + Scope* closureScope = MergeScopes(funcScope, localScope); + + /* Create the function from the data gathered */ + VyFunction** func = CreateNativeFunction(arguments, numArguments, exprList, closureScope); + return ToObject(func); +} + +/* Add a nameless function (from a lambda) to the function list, after giving it a name */ +void AddFunction(char* asName, VyFunction** func){ + /* Add the function to the global scope */ + AddVariable(GetGlobalScope(), CreateVariable(asName, ToObject(func))); +} diff --git a/old/lisp-lang/Include/Boolean.h b/old/lisp-lang/Include/Boolean.h new file mode 100644 index 0000000..786d924 --- /dev/null +++ b/old/lisp-lang/Include/Boolean.h @@ -0,0 +1,46 @@ +#ifndef BOOLEAN_H +#define BOOLEAN_H + +#include "Vyion.h" + +/* Booleans should be pretty simple. A boolean value is just a true or false value. + * Booleans are used in things such as if statements - the condition MUST evaluate + * to a boolean. Unlike other Lisps, Vyion doesn't have a NIL variable which is considered false. + * The only two boolean things are true and false, which, in the interpreter, are + * held in the true! and false! global variables. + */ + +/* A boolean type, 0 for false, and anything else for true */ +struct VyBoolean { + short torf; +}; + +/* Check the truth value of a boolean */ +int IsTrue(VyBoolean**); +int IsFalse(VyBoolean**); + +/* Creating booleans */ +VyBoolean** MakeTrueBool(); +VyBoolean** MakeFalseBool(); + +/* Functions for non-short-circuiting boolean operations */ +VyBoolean** BoolAnd(VyBoolean**, VyBoolean**); +VyBoolean** BoolOr(VyBoolean**, VyBoolean**); +VyBoolean** BoolXor(VyBoolean**, VyBoolean**); +VyBoolean** BoolNot(VyBoolean**); + +/* Functions for comparing numbers, which return a boolean */ +VyBoolean** LessThan(VyNumber**, VyNumber**); +VyBoolean** GreaterThan(VyNumber**, VyNumber**); + +VyBoolean** LessThanOrEqual(VyNumber**, VyNumber**); +VyBoolean** GreaterThanOrEqual(VyNumber**, VyNumber**); + +VyBoolean** Equal(VyNumber**, VyNumber**); +VyBoolean** NotEqual(VyNumber**, VyNumber**); + +/* Print a boolean as either true! or false! */ +void PrintBoolean(VyBoolean**); + + +#endif /* BOOLEAN_H */ diff --git a/old/lisp-lang/Include/CharList.h b/old/lisp-lang/Include/CharList.h new file mode 100644 index 0000000..c2bcc0a --- /dev/null +++ b/old/lisp-lang/Include/CharList.h @@ -0,0 +1,35 @@ +#ifndef CHAR_LIST_H +#define CHAR_LIST_H + +/* CharList is a utility for the lexer, mostly, which is just a list of characters. + * Like an expandable string. + */ + +/* A list of characters which can be expanded (currently, a linked list) */ +struct CharList { + char val; + struct CharList* next; +}; + +/* Print the contents of the list to standard output */ +void Print(CharList*); + +/* Add a character to the list */ +void Add(CharList*, char); + +/* Free the used memory */ +void Delete(CharList*); + +/* Create a character list. (Safer than creating it yourself) */ +CharList* MakeCharList(); + +/* Get the character at a set position in the list */ +char Get(CharList*, int); + +/* Convert the character list into a string */ +char* ToStr(CharList*); + +/* Find the size of the character list */ +int Size(CharList*); + +#endif /* CHAR_LIST_H */ diff --git a/old/lisp-lang/Include/Declarations.h b/old/lisp-lang/Include/Declarations.h new file mode 100644 index 0000000..8b4e77e --- /dev/null +++ b/old/lisp-lang/Include/Declarations.h @@ -0,0 +1,39 @@ +#ifndef DECLARATIONS_H +#define DECLARATIONS_H + +/* This file is just a list of all the typedef's. + * It can also serve as a sort of 'index' for all + * the data structures in the interpreter. All the + * structs are in the same named files, except for + * VyObject, VyParseTree, and VyToken, which are in + * Object.h, ParseTree.h, and Token.h, respectively + */ + +/* Objects are represented by their integer ID's */ +typedef int VyObject ; + +/* Typdef all the structs */ + +typedef struct VyBoolean VyBoolean ; +typedef struct VyFunction VyFunction ; +typedef struct VyNumber VyNumber ; +typedef struct VyError VyError ; +typedef struct VyFlowControl VyFlowControl ; +typedef struct VyList VyList ; +typedef struct VySymbol VySymbol ; +typedef struct VyMacro VyMacro ; + +typedef struct VyToken VyToken ; +typedef struct VyParseTree VyParseTree ; + +typedef struct Scope Scope ; +typedef struct VarBinding VarBinding ; +typedef struct ScopeStack ScopeStack ; +typedef struct Argument Argument ; + +typedef struct VyMemHeap VyMemHeap ; + +typedef struct Position Position ; +typedef struct CharList CharList ; + +#endif /* DECLARATIONS_H */ diff --git a/old/lisp-lang/Include/Error.h b/old/lisp-lang/Include/Error.h new file mode 100644 index 0000000..d5cc6b2 --- /dev/null +++ b/old/lisp-lang/Include/Error.h @@ -0,0 +1,18 @@ +#ifndef ERROR_H +#define ERROR_H + +#include "Vyion.h" + +/* An error with the message and the expression itself (from which the position may be deduced) */ +struct VyError { + char* message; + VyParseTree* expr; +}; + +/* Create an error object */ +VyError** CreateError(char*, VyParseTree*); + +/* Print an error */ +void PrintError(VyError**); + +#endif /* ERROR_H */ diff --git a/old/lisp-lang/Include/Eval.h b/old/lisp-lang/Include/Eval.h new file mode 100644 index 0000000..a12e610 --- /dev/null +++ b/old/lisp-lang/Include/Eval.h @@ -0,0 +1,27 @@ +#ifndef EVAL_H +#define EVAL_H + +#include "Vyion.h" + +/* The eval function is the basis of the interpreter. It actually + * evaluates the parse tree and returns a value for it. + */ + +/* Expand a of macro */ +VyObject ExpandMacro(VyMacro**, VyParseTree*); + +/* Evaluate an expression */ +VyObject Eval(VyParseTree*); + +/* Convert an object to a parse tree if possible */ +VyParseTree* ObjToParseTree(VyObject); + +/* Evaluate a quoted expression */ +VyObject QuotedEval(VyParseTree*, int); + +/* Handle an error */ +void HandleError(VyObject); + +int StrEquals(char*, char*); + +#endif /* EVAL_H */ diff --git a/old/lisp-lang/Include/FlowControl.h b/old/lisp-lang/Include/FlowControl.h new file mode 100644 index 0000000..edc9dfe --- /dev/null +++ b/old/lisp-lang/Include/FlowControl.h @@ -0,0 +1,23 @@ +#ifndef FLOW_CONTROL_H +#define FLOW_CONTROL_H + +#include "Vyion.h" + +/* A flow control object is used for various flow control jumps. + * The different types of flow control are declared here as #define's, + * and every flow control can have associated data stored in the void*. + */ + +/* Flow control types */ +#define FLOWGO 0 +#define FLOWRETURN 1 + +struct VyFlowControl { + void* data; + int type; +}; + +VyFlowControl** CreateFlowControl(int, void*); + + +#endif /* FLOW_CONTROL_H */ diff --git a/old/lisp-lang/Include/Function.h b/old/lisp-lang/Include/Function.h new file mode 100644 index 0000000..fe215f6 --- /dev/null +++ b/old/lisp-lang/Include/Function.h @@ -0,0 +1,102 @@ +#ifndef FUNCTION_H +#define FUNCTION_H + +#include "Vyion.h" + +/* A function is, unlike in some languages, also a basic type. A function can either be a + * built-in function which is coded in another compiled language, like C, or it can be a + * function written in Vyion. The function struct contains a pointer to a C function, which can either + * be the evaluation function for a parse tree, or a built-in compiled function. This allows + * the interface to builtin and native (native meaning written in Vyion) functions to be the same. + * + * Arguments can be optional, named, and rest arguments. Also, a combination of named and optional arguments + * is possible. The argument type enumeration is defined here, as is the Argument data structure. Functions + * can do argument checking, and native functions do so anyway. + */ + +/* Define types of arguments */ +#define ARGOPTIONAL 1 +#define ARGNAMED 2 +#define ARGNAMEDOPTIONAL 3 +#define ARGREST 4 + +/* A function argument */ +struct Argument { + /* The argument type */ + int argCode; + + /* The symbol name (named arguments assume the same name) */ + char* name; + + /* Optional argument's default value, or NULL */ + VyObject optArgDefault; + + /* Argument value type */ + int type; + +}; + +/* A function with its charactertics */ +struct VyFunction { + /* Function arguments */ + Argument** args; + + /* The number of arguments */ + int numArgs; + + /* Function pointer to a function used to process these arguments */ + /* The two arguments to EvalFunction are the function's arguments and the number of arguments */ + /* It returns the result of evaluating the function */ + VyObject (* EvalFunction ) (struct VyFunction**, VyObject*, int); + + /* The following applies only to non-builtin functions. It is NULL for builtins. */ + + /* Function code */ + VyParseTree* code; + + /* The function scope (for closures) */ + Scope* scp; + +}; + +/* Create a built-in function */ +VyFunction** CreateBuiltinFunction(Argument**, int, VyObject (*EvalFunction)(VyFunction**, VyObject*,int)); + +/* Create a native function */ +VyFunction** CreateNativeFunction( Argument**, int, VyParseTree*, Scope*); + +/* Create a function argument */ +Argument* CreateArgument(int, char*, int); + +/* Set a function's name */ +void SetFunctionName(VyFunction**, char*); + +/* Set a function's scope */ +void SetFunctionScope(VyFunction**, Scope*); + +/* Evaluate a function (pass the arguments and the number of them) */ +VyObject RunFunction(VyFunction**, VyObject*, int); + +/* Evaluate native and builtin functions */ +VyObject EvalNativeFunction(VyFunction**, VyObject*, int); +VyObject EvalBuiltinFunction(VyFunction**, VyObject*, int); +VyObject EvalNativeFunctionOrMacro(Argument**, int, VyParseTree*, Scope*, VyObject*, int); + +/* Parse a function's arguments */ +Argument** ParseFunctionArguments(VyParseTree*, int*, char**); + +/* Check the arguments for validity */ +char* CheckFunctionArguments(Argument**, int, VyObject*, int); + +/* Parse a function from a lambda expression */ +VyObject ParseFunction(VyParseTree*); + +/* Add a function to the function list */ +void AddFunction(char*, VyFunction**); + +/* Functions for checking argument types (named, optional, rest) */ +int IsNamedArg(Argument*); +int IsRestArg(Argument*); +int IsOptionalArg(Argument*); + +#endif /* FUNCTION_H */ diff --git a/old/lisp-lang/Include/Lexer.h b/old/lisp-lang/Include/Lexer.h new file mode 100644 index 0000000..5ab8018 --- /dev/null +++ b/old/lisp-lang/Include/Lexer.h @@ -0,0 +1,52 @@ +#ifndef LEXER_H +#define LEXER_H + +#include "Vyion.h" + +/* The lexer is the part of the interpreter which deals with pure textual + * input. What it does is it reads the input as characters, and emits + * tokens (in the form of VyToken*) so that the parser doesn't have to deal with + * pesky things such as whitespace. The lexer is used by the parser, and makes life a + * whole lot better. + */ + +/***** Functions to access the current state of the lexer *****/ + +/* Get the token list */ +VyToken** GetTokenList(); + +/* Get the next token */ +VyToken* GetNextToken(); + +/* Find out if there are more tokens */ +int MoreTokensExist(); + +/* Backtrack on the current token (i.e. next time, GetNextToken() will return the previous token) */ +int BacktrackToken(); + +/* Returns the next token, but doesn't change the next outcome of GetNextToken() */ +VyToken* GetLookAheadToken(); + +/* Find the total number of tokens for the last processed data */ +int GetNumTokens(); + +/* Free the used memory and reset the lexer to its initial state */ +void CleanLexer(); + +/***** Functions for tokenizing data *****/ + +/* Process a whole file */ +void LexFile(char*); + +/* Process a string */ +void Lex(char*); + +/***** Debugging functions *****/ + +/* Print the token list (for debugging) */ +void PrintTokenList(); + +/* Print a token */ +void PrintToken(VyToken*); + +#endif /* LEXER_H */ diff --git a/old/lisp-lang/Include/List.h b/old/lisp-lang/Include/List.h new file mode 100644 index 0000000..b644413 --- /dev/null +++ b/old/lisp-lang/Include/List.h @@ -0,0 +1,52 @@ +#ifndef LIST_H +#define LIST_H + +#include "Vyion.h" + +/* A list is one of Vyion's basic data types, since its whole + * code structure is based on lists. Although traditionally Lisp + * lists are stored as linked lists, there is really no such restriction + * as long as the list implements head, tail, get, size, append, etc etc. + * Therefore, the implementation of this may change. + */ + +/* A linked list data structure */ +struct VyList { + VyList** next; + VyObject data; +}; + +/* Create a list */ +VyList** CreateList(); + +/* Copy a list */ +VyList** CloneList(VyList**); + +/* First element of the list */ +VyObject ListHead(VyList**); + +/* List tail */ +VyList** ListTail(VyList**); + +/* Find the size of a list */ +int ListSize(VyList**); + +/* Get from index */ +VyObject ListGet(VyList**, int); + +/* Append an element to a list */ +VyList** ListAppend(VyList**, VyObject); + +/* Insert an element into a list at an index */ +VyList** ListInsert(VyList**, VyObject, int); + +/* Concatenate two lists */ +VyList** ListConcat(VyList**, VyList**); + +/* Delete the list */ +void DeleteList(VyList**); + +/* Print a list */ +void PrintList(VyList**); + +#endif /* LIST_H */ diff --git a/old/lisp-lang/Include/Macro.h b/old/lisp-lang/Include/Macro.h new file mode 100644 index 0000000..f70c0ce --- /dev/null +++ b/old/lisp-lang/Include/Macro.h @@ -0,0 +1,37 @@ +#ifndef MACRO_H +#define MACRO_H + +/* A macro is more or less a function on steroids. The difference between a macro and a function is this: a macro must return + * a data type which can be then converted into a parse tree. These data types include lists, symbols, numbers, as well as others. + * What makes a macro special as opposed to a function is that unlike a function, it doesn't generate a value - it generates code. + * This code is then evaluated, and only that results in a value. + * + * The data type that stores a macro is very similar to the one that stores a function, but since all macros must be native code, + * the data type does not need to store a pointer to a function. + */ + +/* The macro data type */ +struct VyMacro { + /* The number of arguments to the macro */ + int numArgs; + + /* The arguments */ + Argument** args; + + /* The macro code */ + VyParseTree* code; + + /* The scope (macro closures) */ + Scope* scp; +}; + +/* Create a macro */ +VyMacro** CreateMacro(Argument**, int, VyParseTree*, Scope*); + +/* Evaluate a macro and return the resulting parse tree */ +VyParseTree* EvalMacro(VyMacro**, VyObject*, int); + +/* Parse a macro */ +VyObject ParseMacro(VyParseTree*); + +#endif /* MACRO_H */ diff --git a/old/lisp-lang/Include/Mem.h b/old/lisp-lang/Include/Mem.h new file mode 100644 index 0000000..5b70a22 --- /dev/null +++ b/old/lisp-lang/Include/Mem.h @@ -0,0 +1,76 @@ +#ifndef V_MEMORY_H +#define V_MEMORY_H + +#include "Vyion.h" + +/* The memory manager, also known as the garbage collector, manages all the memory for the language */ + + +/* The garbage collector operates on the memory heap, which is defined in the VyMemHeap struct. It + * contains data about the current heap size, the amount of space used on the heap, the start of the free + * memory on the heap, and a pointer to the base of the heap. + * -------------------------------------------------------------------------------------------------------- + * + * Also, it contains a 2-D array. The indices of the array are the ID numbers of the objects. The first row + * of the array contains the type of the object (an integer), and the second row contains pointers to + * the data of the objects. To facilitate use by the garbage collector, the interpreter should NEVER + * directly store the value of that pointer in a variable, because the pointer may be invalidated during garbage + * collection, resulting in a dangling pointer. Instead, the interpreter should use a pointer to that pointer, so that + * when the garbage collector is called, it can update all the pointers and all the interpreter references will + * automatically be updated. + * + * Problem: When the amount of objects grows, the 2-D array must also grow. When, however, it is realloc'd, it may move + * in memory, therefore invalidating all the pointers to it. Lovely! It does EXACTLY what it was supposed to help avoid + * (i.e. the invalidation of pointers. ) + * + * Solution: Instead of having one 2D array, have an array of them. Each of the 2D arrays will have a known size. That way, + * if we have n 2D arrays each with m elements in them, we can store m*n objects. It isn't hard to malloc a new array, and + * all the old arrays stay in the same place when that happens. We can find which array an object is in and its index in that + * array quite easily, too. + * + * Note: The first row (index 0) is the type, and the second is the pointer to the data. + * ------------------------------------------------------------------------------------------------------- + * + * The memory manager itself has four external functions: InitMem(), the initilization function, which should be called as the + * very FIRST thing in an application, VyMemCollect(), which forces a garbage collection cycle, and also VyMallocate(), which + * allocates space on the heap for a certain number of bytes and returns a pointer to that space. The last function is FreeHeap(), which just + * frees the memory on the heap, as well as the heap structure itself. This should be called at the end of the program to ensure that + * all memory is released. + * + * If the heap that the memory is requested on is too small, then VyMallocate() automatically calls the garbage collector. The + * garbage collector does a few things: it determines which objects are still reachable, then creates a new, larger heap, copies those objects + * to the heap, and then free's the old heap memory. While it copies those objects to the new heap, it updates the pointers to them in + * the heap structure so that the interpreter knows where to reach those objects. + */ + +struct VyMemHeap { + /* Heap data */ + int heapSize; + int usedSpace; + + /* An array of 2-D arrays. The 2-D arrays contain void*'s. */ + void**** idMapArray; + int numIdMaps; + int idMapSize; + + int objectsOnHeap; + + /* The pointers to the heap base and free memory */ + void* heapBase; + void* freeMem; + +}; + +/* Initialize the memory manager */ +void InitMem(); + +/* Allocate a number of bytes on the heap and return a pointer to it */ +void* VyMallocate(int, VyMemHeap*); + +/* Force a garbage collection cycle to occur */ +void VyMemCollect(VyMemHeap*); + +/* Delete the heap */ +void FreeHeap(VyMemHeap*); + +#endif /* V_MEMORY_H */ diff --git a/old/lisp-lang/Include/Number.h b/old/lisp-lang/Include/Number.h new file mode 100644 index 0000000..f9dfb45 --- /dev/null +++ b/old/lisp-lang/Include/Number.h @@ -0,0 +1,90 @@ +#ifndef NUMBER_H +#define NUMBER_H + +/* In Vyion, a number is it's own type. Unlike most other languages, there is no external difference between integers, + * floats, complex numbers, ratios, longnums, etc. A number may be converted to a specific type if it is needed, and auxilary functions + * may provide more info about the number, but by default numbers are automatically converted back and forth between needed types by the + * built-in arithmetic functions. + */ + +/* Define all the numeric types */ +typedef struct { + int i; +} IntNum; + +typedef struct { + double d; +} RealNum; + +typedef struct { + VyNumber** real; + VyNumber** imaginary; +} ComplexNum; + +typedef struct { + int numerator; + int denominator; +} RatioNum; + + +/* Numeric types: integers, floats, complex numbers, and ratios */ +struct VyNumber { + int type; + void* data; +}; + +/* Parse a number from a string */ +VyNumber** ParseNumber(char*); + +/* Get any parsing errors; NULL if none */ +char* GetLastNumberParsingError(); + +/* Create a number */ +VyNumber** CreateNumber(int); + +/* Convert a number to one of its sub-types (Only to be used internally) */ +void* NumberToSubtype(VyNumber**); + +/* Delete and free memory */ +void DeleteNumber(VyNumber**); + +/* Print the number to stdout */ +void PrintNumber(VyNumber**); + +/* Create specific types of number */ +VyNumber** CreateInt(int); +VyNumber** CreateReal(double); +VyNumber** CreateImaginary(VyNumber**); +VyNumber** CreateComplex(VyNumber**, VyNumber**); +VyNumber** CreateRatio(int,int); + +/* Retrieve data from numbers */ +int GetInt(VyNumber**); +double GetDouble(VyNumber**); +int GetNumerator(VyNumber**); +int GetDenominator(VyNumber**); +VyNumber** GetReal(VyNumber**); +VyNumber** GetImaginary(VyNumber**); + +/* Negate a number */ +VyNumber** NegateNumber(VyNumber**); + +/* Add two numbers */ +VyNumber** AddNumbers(VyNumber**,VyNumber**); + +/* Subtract two numbers */ +VyNumber** SubtractNumbers(VyNumber**,VyNumber**); + +/* Divide two numbers */ +VyNumber** DivideNumbers(VyNumber**,VyNumber**); + +/* Multiply two numbers */ +VyNumber** MultiplyNumbers(VyNumber**,VyNumber**); + +/* Exponentiate a number */ +VyNumber** ExponentiateNumber(VyNumber**,VyNumber**); + +/* Conversions between number types */ +VyNumber** RatioToReal(VyNumber**); + +#endif /* NUMBER_H */ diff --git a/old/lisp-lang/Include/NumberType.h b/old/lisp-lang/Include/NumberType.h new file mode 100644 index 0000000..d97ff0d --- /dev/null +++ b/old/lisp-lang/Include/NumberType.h @@ -0,0 +1,10 @@ +#ifndef NUMBER_TYPE_H +#define NUMBER_TYPEH + +/* Define the numeric types as an enum */ +#define REAL 0 +#define INT 1 +#define COMPLEX 2 +#define RATIO 3 + +#endif /* NUMBER_TYPE_H */ diff --git a/old/lisp-lang/Include/ObjType.h b/old/lisp-lang/Include/ObjType.h new file mode 100644 index 0000000..31f1b63 --- /dev/null +++ b/old/lisp-lang/Include/ObjType.h @@ -0,0 +1,15 @@ +#ifndef VALUE_TYPE_H +#define VALUE_TYPE_H + +/* Data in values */ +#define VALUNDEF -1 +#define VALNUM 0 +#define VALFUNC 1 +#define VALLIST 2 +#define VALSYMB 3 +#define VALBOOL 4 +#define VALMAC 5 +#define VALERROR 6 +#define VALFLOW 7 + +#endif /* VALUE_TYPE_H */ diff --git a/old/lisp-lang/Include/Object.h b/old/lisp-lang/Include/Object.h new file mode 100644 index 0000000..eefa04a --- /dev/null +++ b/old/lisp-lang/Include/Object.h @@ -0,0 +1,38 @@ +#ifndef VyObject_H +#define VyObject_H + +/* An object is the value returned by any operation or function in the Vyion language. Internally, + * you do not actually manipulate objects themselves. Instead - you manipulate their ID's, or the data inside them. + * To look up the type of an object or the data of an object based on ID, use the ObjType() and ObjData() functions. + */ + +#include "Vyion.h" + +/* The memory heap */ +void SetMemoryHeap(VyMemHeap*); +VyMemHeap* GetMemoryHeap(); + +/* Find the number of bytes needed for a certain type of object */ +int DataSize(int); + +/* Print a value to standard output */ +void PrintObj(VyObject); + +/* Create objects from values */ +VyNumber** CreateNumObj(); +VyFunction** CreateFuncObj(); +VyMacro** CreateMacroObj(); +VySymbol** CreateSymbObj(); +VyList** CreateListObj(); +VyBoolean** CreateBoolObj(); +VyError** CreateErrorObj(); +VyFlowControl** CreateFlowControlObj(); + +/* Retrieve the actual value and type from the contiguous memory space */ +void* ObjData(VyObject); +int ObjType(VyObject); + +/* Convert a VyNumber*, VyFunction*, VyList*, etc to a VyObject */ +VyObject ToObject(void*); + +#endif /* VyObject_H */ diff --git a/old/lisp-lang/Include/ParseTree.h b/old/lisp-lang/Include/ParseTree.h new file mode 100644 index 0000000..3eb1f5c --- /dev/null +++ b/old/lisp-lang/Include/ParseTree.h @@ -0,0 +1,108 @@ +#ifndef PARSE_TREE_H +#define PARSE_TREE_H + +#include "Vyion.h" + +/* Nodes of a parse tree */ +struct VyParseTree; + +typedef struct { + struct VyParseTree** list; + int length; +} list_node; + +typedef struct { + char* str; +} ident_node; + +typedef struct { + VyNumber** num; +} num_node; + +typedef struct { + struct VyParseTree* data; +} quote_node; + +typedef struct { + struct VyParseTree* data; + int splice; +} subst_node; + +typedef struct { + struct VyParseTree* obj; + struct VyParseTree* ref; +} ref_node; + +typedef struct { + char* str; +} string_node; + +typedef struct { + char* message; +} error_node; + +/* The data of a parse tree node */ +typedef union { + list_node list; + ident_node ident; + num_node num; + string_node str; + quote_node quote; + subst_node subst; + ref_node ref; + error_node error; +} tree_node_data; + +/* A parse tree node */ +struct VyParseTree { + int type; + Position* pos; + tree_node_data* data; +}; + +/* Create empty parse trees of a certain type */ +VyParseTree* MakeListTree(); +VyParseTree* MakeNum(); +VyParseTree* MakeIdent(); +VyParseTree* MakeString(); + +/* Quote an expression or get the expression in a quote */ +VyParseTree* Quote(VyParseTree*); +int IsQuote(VyParseTree*); + +/* Put something in/out of a substitution */ +VyParseTree* Substitution(VyParseTree*, int); +int IsSubstitution(VyParseTree*); +int IsSplicingSubstitution(VyParseTree*); + +/* Create an object reference */ +VyParseTree* Reference(VyParseTree*, VyParseTree*); + +/* Retrieve either the obj or ref part of the reference */ +VyParseTree* GetObj(VyParseTree*); +VyParseTree* GetRef(VyParseTree*); + +/* Make an error node */ +VyParseTree* ParseError(char*); + +/* List operations (adding, retrieving, and finding list size) */ +int AddToList(VyParseTree*,VyParseTree*); +VyParseTree* GetListData(VyParseTree*,int); +inline int ListTreeSize(VyParseTree*); +VyParseTree* ListTreeHead(VyParseTree*); + +/* Get and set the associated string data for this node */ +int SetStrData(VyParseTree*, char*); +char* GetStrData(VyParseTree*); + +/* Get/Set Number Data */ +void SetNumberData(VyParseTree*, VyNumber**); +VyNumber** GetNumberData(VyParseTree*); + +/* Set the position in the original text of this node */ +void SetPosition(VyParseTree*, Position*); + +/* Delete a parse tree and the used memory */ +void DeleteParseTree(VyParseTree*); + +#endif /* PARSE_TREE_H */ diff --git a/old/lisp-lang/Include/Parser.h b/old/lisp-lang/Include/Parser.h new file mode 100644 index 0000000..b8d7ad5 --- /dev/null +++ b/old/lisp-lang/Include/Parser.h @@ -0,0 +1,21 @@ +#ifndef PARSER_H +#define PARSER_H + +#include "Vyion.h" + +/* A routine to parse a file (wraps file into a list, since a file consists of many expressions */ +VyParseTree* ParseFile(char*); + +/* A function that parses whatever happens to be in the lexer */ +VyParseTree* Parse(); + +/* Print the parse tree (for debugging) */ +void PrintTree(VyParseTree*); + +/* Look for and print errors, return if there were any */ +int CheckAndPrintErrors(VyParseTree*); + +/* Clean all the resources of the parser */ +void CleanParser(); + +#endif /* PARSER_H */ diff --git a/old/lisp-lang/Include/Scope.h b/old/lisp-lang/Include/Scope.h new file mode 100644 index 0000000..61d8689 --- /dev/null +++ b/old/lisp-lang/Include/Scope.h @@ -0,0 +1,62 @@ +#ifndef SCOPE_H +#define SCOPE_H + +#include "Vyion.h" + +/* A variable scope */ +struct Scope { + VarBinding** vars; + int size; +}; + +/***** Functions to deal with scope data structures *****/ + +/* Create a scope */ +Scope* CreateScope(); + +/* Find a variable in a scope; if it doesn't exist, return NULL; if it doesn, return it's value. */ +VyObject FindValue(Scope*, char*); + +/* Set a variable (may need to add it first) */ +void SetVariable(Scope*, char*, VyObject); + +/* Add a variable to a scope */ +void AddVariable(Scope*, VarBinding*); + +/* Print the concents of a scope */ +void PrintScopeContents(Scope*); + +/* Merge two scopes into one */ +Scope* MergeScopes(Scope*, Scope*); + +/* Destroy a scope */ +void DeleteScope(Scope*); + +/***** Functions to deal with the program's scope *****/ + +/* Get the global scope */ +Scope* GetGlobalScope(); + +/* Add or remove scopes to the function scope stack */ +void PushScope(Scope*); +Scope* PopScope(); + +/* Get the local scope */ +Scope* GetLocalScope(); + +/* Get the current function scope */ +Scope* GetCurrentFunctionScope(); + +/* Set the current function scope */ +void SetCurrentFunctionScope(Scope*); + +/* Set the local scope */ +void SetLocalScope(Scope*); + +/* Find a value in all currently accesible scopes */ +VyObject FindObjAllScopes(char*); + +/* Initialize scopes */ +void InitScopes(); + +#endif /* SCOPE_H */ diff --git a/old/lisp-lang/Include/ScopeStack.h b/old/lisp-lang/Include/ScopeStack.h new file mode 100644 index 0000000..22c61e4 --- /dev/null +++ b/old/lisp-lang/Include/ScopeStack.h @@ -0,0 +1,21 @@ +#ifndef SCOPE_STACK_H +#define SCOPE_STACK_H + +#include "Vyion.h" + +/* A scope stack */ +struct ScopeStack { + int numElements; + int size; + Scope** data; +}; + +/* Pop and push scopes */ +void Push(ScopeStack*, Scope*); +Scope* Pop(ScopeStack*); + +/* Create and delete stacks */ +ScopeStack* CreateScopeStack(); +void DeleteScopeStack(ScopeStack*); + +#endif /* SCOPE_STACK_H */ diff --git a/old/lisp-lang/Include/StringUtil.h b/old/lisp-lang/Include/StringUtil.h new file mode 100644 index 0000000..4c27b01 --- /dev/null +++ b/old/lisp-lang/Include/StringUtil.h @@ -0,0 +1,17 @@ +#ifndef STRING_UTIL_H +#define STRING_UTIL_H + +/* A few string and character functions which are used extensively throughout the interpreter. + * Mostly, however, their uses are confined to the lexer and number parsing routines. + */ + +/* Checks whether the character represents a digit (i.e., matches [0-9]) */ +int isNumeric(char); + +/* Checks whether a character is whitespace (space, tab, or newline) */ +int isWhitespace(char); + +/* Safely concat two strings, with no side effects, although the newly created string should still be freed explicitly. */ +char* ConcatStrings(char*, char*); + +#endif /* STRING_UTIL_H */ diff --git a/old/lisp-lang/Include/Symbol.h b/old/lisp-lang/Include/Symbol.h new file mode 100644 index 0000000..16927d1 --- /dev/null +++ b/old/lisp-lang/Include/Symbol.h @@ -0,0 +1,18 @@ +#ifndef SYMBOL_H +#define SYMBOL_H + +/* A quoted identifier is a symbol */ +struct VySymbol { + char* ident; +}; + +/* Make a symbol */ +VySymbol** CreateSymbol(char*); + +/* Get the symbol ident */ +char* GetSymbolString(VySymbol**); + +/* Print a symbol to standard output */ +void PrintSymbol(VySymbol**); + +#endif /* SYMBOL_H */ diff --git a/old/lisp-lang/Include/Token.h b/old/lisp-lang/Include/Token.h new file mode 100644 index 0000000..ec1479a --- /dev/null +++ b/old/lisp-lang/Include/Token.h @@ -0,0 +1,44 @@ +#ifndef TOKEN_H +#define TOKEN_H + +/* A position of a token in the given code */ +struct Position { + int line; + int indent; + int character; +}; + +/* A lexer token */ +struct VyToken { + int type; + char* data; + Position* pos; +}; + +/* Create a token with no associated data of given type */ +VyToken* EmptyToken(int); + +/* Create a token of a given type with associated string data */ +VyToken* DataToken(int,char*); + +/* Set the position of a token */ +void SetTokenPosition(VyToken*, int, int, int); + +/* Print a position (line and character) */ +void PrintPosition(Position*); + +/* Find the line or character position of a token */ +int GetLine(VyToken*); +int GetCharacter(VyToken*); +int GetIndent(VyToken*); + +/* Whether the token has a known position */ +int HasKnownPosition(VyToken*); + +/* Whether the token is an empty token (i.e., no associated string data) */ +int IsEmptyToken(VyToken*); + +/* Delete the token data and free used memory */ +void DeleteToken(VyToken*); + +#endif /* TOKEN_H */ diff --git a/old/lisp-lang/Include/TokenType.h b/old/lisp-lang/Include/TokenType.h new file mode 100644 index 0000000..bd342f4 --- /dev/null +++ b/old/lisp-lang/Include/TokenType.h @@ -0,0 +1,19 @@ +#ifndef TOKEN_TYPE_H +#define TOKEN_TYPE_H + +/* Define all the token types */ +#define OPAREN 0 +#define CPAREN 1 +#define OBRACKET 2 +#define CBRACKET 3 +#define COLON 4 +#define DOLLAR 5 +#define QUOTE 6 +#define NUM 7 +#define IDENT 8 +#define STRING 9 +#define DOLLARAT 10 +#define OCURLY 11 +#define CCURLY 11 + +#endif /* TOKEN_TYPE_H */ diff --git a/old/lisp-lang/Include/TreeType.h b/old/lisp-lang/Include/TreeType.h new file mode 100644 index 0000000..250376e --- /dev/null +++ b/old/lisp-lang/Include/TreeType.h @@ -0,0 +1,16 @@ +#ifndef TREE_TYPE_H +#define TREE_TYPE_H + +/* The different nodes of the syntax tree */ + +#define TREE_IDENT 0 +#define TREE_NUM 1 +#define TREE_LIST 2 +#define TREE_SUBST 4 +#define TREE_REF 5 +#define TREE_STR 6 + +/* Used to represent an error */ +#define TREE_ERROR 10 + +#endif /* TREE_TYPE_H */ diff --git a/old/lisp-lang/Include/Variable.h b/old/lisp-lang/Include/Variable.h new file mode 100644 index 0000000..a4a85d0 --- /dev/null +++ b/old/lisp-lang/Include/Variable.h @@ -0,0 +1,22 @@ +#ifndef VARIABLE_H +#define VARIABLE_H + +#include "Vyion.h" + +/* A variable binding */ +struct VarBinding { + char* name; + VyObject val; +}; + +/* Create a binding */ +VarBinding* CreateVariable(char*,VyObject); + +/* Retrieve the name or value of a variable */ +char* GetVarName(VarBinding*); +VyObject GetVarValue(VarBinding*); + +/* Free the memory */ +void DeleteVariable(VarBinding*); + +#endif /* VARIABLE_H */ diff --git a/old/lisp-lang/Include/Vyion.h b/old/lisp-lang/Include/Vyion.h new file mode 100644 index 0000000..f54c9a7 --- /dev/null +++ b/old/lisp-lang/Include/Vyion.h @@ -0,0 +1,97 @@ +#ifndef VYION_HEADER_H +#define VYION_HEADER_H + +/****** Include all the Vambre language headers ******/ + +/* Include all standard C libraries */ +#include +#include +#include +#include +#include + +/* Check that NULL is defined */ +#ifndef NULL + #define NULL 0 +#endif + +/* Include all the type definitions and declarations */ +#include "Declarations.h" + +/* The lexer and related utilities: + * The lexer takes either a string or a filename and then tokenizes that. + * Tokenizing the input is the process of reading the input and splitting it up into + * pieces that will be easier for subsequent parsing. The token data structure is described in Token.h, + * the different token types are described in TokenType.h, and the main lexing routines are described in Lexer.h. + */ + +#include "StringUtil.h" +#include "CharList.h" +#include "Token.h" +#include "Lexer.h" + + +/* Parser: + * The parser takes as an input a series of tokens, created by the lexer. It then reads through them + * and creates a parse tree based on them. The parse tree represents the structure of the program + * code. In the case of Vambre, the parse tree is just a list which may contain symbols, numbers, other lists, etc. + * The data structure to hold the parse tree is described in ParseTree.h, and the different types of parse trees + * have an enumeration in TreeType.h. + * + * Note: For convenience, Parser.h also includes a routine to parse the contents of a file. This routine simply calls the lexing routine, and + * only then actually does the parsing. + */ + +#include "Parser.h" +#include "ParseTree.h" + +/* Evaluation of expressions: + * The function which evaluates a parse tree is the eval function, which is in Eval.h. The eval function + * takes a parse tree structure and then evaluates it (recursively, if needed). Functions are described in Function.h, which presents + * a function data type that unifies built-in C functions and functions actually written in Vambre through the use of function pointers. + * Vambre is lexically scoped, and the scope data structure in described in Scope.h, while the call stack is in ScopeStack.h. + * The different types of objects and values are unified into one type in Value.h, with the value type enumeration in ValueType.h. + * Variables, that is, bindings to values, are described in Value.h. + * + * Note: The main entry point to the program is in the Eval() function, in Eval.h. + */ + +#include "Eval.h" +#include "Scope.h" +#include "ScopeStack.h" +#include "Object.h" +#include "Variable.h" + +/* Basic variable types: + * The different types of objects in Vambre are described in these files. Currently, Vambre has the following types: + * - Boolean: True or false values, used in boolean expressions. + * - List: A list of objects, implemented as a linked list. + * - Number: A number, which can be either real (i.e. double), integer, or complex. Arithmetic operations convert between those types. + * - Symbol: The symbol is what you get as a result of quoting an identifier. It is (more-or-less) a string used as an identifier. + * - Function: A function, which can be called with arguments to produce a result. Functions are created with lambda. + * - Macro: A macro, which evaluates to Vambre code, which can then be used for anything else. Created with mambda. + * - Error: An error. Errors contain information for traceback calls. Note, these aren't errors that you can resume from, only catch. + */ + +#include "Boolean.h" +#include "List.h" +#include "Number.h" +#include "Symbol.h" +#include "Function.h" +#include "Macro.h" +#include "Error.h" +#include "FlowControl.h" + +/* Memory management: + * These headers provide an interface to the Vambre memory functions, which allocate and free memory, + * as well as the Vambre garbage collector. + */ +#include "Mem.h" + +/* Various type enumerations */ +#include "TokenType.h" +#include "TreeType.h" +#include "ObjType.h" +#include "NumberType.h" + +#endif /* VAMBRE_HEADER_H */ diff --git a/old/lisp-lang/Lexer.c b/old/lisp-lang/Lexer.c new file mode 100644 index 0000000..dbaac14 --- /dev/null +++ b/old/lisp-lang/Lexer.c @@ -0,0 +1,477 @@ +#include "Vyion.h" + +/* The resulting tokens */ +VyToken** tokenList = NULL; +int numTokens = 0; +int currentToken = 0; //For returning the tokens one by one + +/* The special characters */ +const char specialChars[] = { '(', ')', '[', ']', '{', '}', ':', '$', '\''}; + +/* Read the contents of a file */ +char* ReadFile(char* filename){ + /* Open that file for reading and make sure it is accessable */ + FILE* file = fopen(filename, "r"); + if(file == NULL){ + fprintf(stderr, "\"%s\" not available.\n", filename); + exit(0); + } + + /* Find the size of the file */ + fseek(file, 0, SEEK_END); + int length = ftell(file); + + /* Return to the beginning of the file for reading */ + fseek(file, 0, SEEK_SET); + + /* Read the contents of the file */ + int size = sizeof(char)*(length); + + /* Add one to the memory needed for the extra '\0' character */ + char* contents = malloc(size + 1); + if(contents == NULL){ + fprintf(stderr, "Memory error\n"); + return 0; + } + fread(contents, size, 1, file); + fclose(file); + + /* Add the terminating 0 to the string */ + contents[size] = '\0'; + + return contents; +} + +/* Anything non-whitespace and not a special character returns true */ +int isIdentChar(char c){ + /* Check that it isn't whitespace or a special character */ + if(isWhitespace(c) == 1) return 0; + int i; + for( i = 0; i < 9; i++){ + if(c == specialChars[i]) return 0; + } + + return 1; +} + +/* Decide whether a string is a number or an identifier */ +int isNumber(CharList* str){ + char first = Get(str, 0); + + /* A string is a number if: + * - the first character is a number + * - the first character is a '+', '-', or '.', and: + * * is followed by a sequence of numbers + * * or is followed by a sequence of numbers with 'e' or '.' in it, but not as the second or last characters + * * also, 'e' and '.' cannot be repeated twice in a number + */ + + /* It is a number if the first character is a number */ + if(isNumeric(first)){ + return 1; + } + /* It can also be a number if the first character is '+', '-', or '.' (but only if there are more characters later) */ + else if((first == '-' || first == '+' || first == '.') && Size(str) > 1){ + /* The rest must be either numeric or 'e' + * 'e' can only occur once, and cannot be second or last */ + int occurences_of_e = 0; + int i; + for(i = 1; i < Size(str); i++){ + /* Deal with the 'e' case */ + if(Get(str, i) == 'e'){ + /* In a number, it cannot be second or last */ + if(i == 1 || i == (Size(str) - 1) || occurences_of_e > 0){ + return 0; //If it is, then it's not a number, therefore return false + } + occurences_of_e++; + } + /* Make sure '.' isn't repeated twice */ + else if(Get(str,i) == '.'){ + if(first == '.'){ + return 0; + } + } + /* Also, if it ends with i then it is an imaginary number */ + else if(Get(str,i) == 'i' || Get(str,i) == 'I'){ + /* If it isn't one, then it is an error and it cannot be a number */ + if(i != Size(str) - 1) { + return 0; + } + } + /* If any character is non-numeric, not 'e', and not '.', then it can't be a number */ + else if(!isNumeric(Get(str,i))){ + return 0; + } + } + + /* If it hasn't failed yet, its a number */ + return 1; + } + /* Otherwise, it is an ident */ + else{ + return 0; + } + +} + +/* Add a new token with a position */ +void AddToken(VyToken* tok, int line, int character, int indent){ + /* Set the position */ + SetTokenPosition(tok, line, character, indent); + + /* Make more room and add it to the array */ + numTokens++; + tokenList = realloc(tokenList, (numTokens)*sizeof(VyToken*)); + tokenList[numTokens - 1] = tok; +} + +/* Convert a token type int to a string */ +char* GetTokenTypeStr(VyToken* tok){ + int type = tok->type; + switch(type){ + case 0: return "O-Paren "; + case 1: return "C-Paren "; + case 2: return "O-Bracket"; + case 3: return "C-Bracket"; + case 4: return "Colon "; + case 5: return "Dollar "; + case 6: return "Quote "; + case 7: return "Number "; + case 8: return "Ident "; + case 9: return "String "; + case 10:return "Dollar-At"; + case 11:return "O-Curly "; + case 12:return "C-Curly "; + default:return "Unknown token type.... "; + } +} + +/* Get the data from a token in text form for printing */ +char* GetTokenDataStr(VyToken* tok){ + int type = tok->type; + switch(type){ + case 0: return "("; + case 1: return ")"; + case 2: return "["; + case 3: return "]"; + case 4: return ":"; + case 5: return "$"; + case 6: return "'"; + default: return tok->data; + } +} + +/* Print a token in a pretty manner */ +void PrintToken(VyToken* tok){ + printf("\nToken Type: %s\t", GetTokenTypeStr(tok)); + if(HasKnownPosition(tok)){ + printf("at position:(%d, %d, %d)\t", GetLine(tok), GetCharacter(tok), GetIndent(tok)); + } + printf(" with data: %s", GetTokenDataStr(tok)); + + +} + +/* Print the tokens in a pretty fashion for debugging */ +void PrintTokenList(){ + int i; + for(i = 0; i < numTokens; i++){ + VyToken* tok = tokenList[i]; + PrintToken(tok); + } +} + +/* Clean-up functions */ +void DeleteTokenList(){ + /* Free each token individually */ + int t; + for(t = 0; t < numTokens; t++){ + DeleteToken(tokenList[t]); + } + + /* Free the token list itself */ + free(tokenList); + tokenList = NULL; +} + +/* Clean up so the lexer can be reused */ +void CleanLexer(){ + DeleteTokenList(); + numTokens = 0; + currentToken = 0; +} + +/* Perform lexing on the given text */ +void Lex(char* text){ + /* Keep track of the amount processed */ + int length = strlen(text); + int read = 0; + + /* Keep track of the current position in the file */ + int line = 0; + int charOnLine = 0; + int indent = 0; + + /* Process all the text until the ASCII 0 character */ + while(read < length){ + /* Read next character */ + char next = text[read]; + read++; + + /* Use newlines and spaces for position */ + if(isWhitespace(next)){ + if(next == '\n'){ + line++; + indent = 0; + charOnLine = 0; + }else{ + if(next == '\t'){ + indent++; + } + charOnLine++; + } + + } + + /* Recognize all the special characters */ + else if(next == '('){ + AddToken(EmptyToken(OPAREN), line, charOnLine, indent); + charOnLine++; + } + else if(next == ')'){ + AddToken(EmptyToken(CPAREN), line, charOnLine, indent); + charOnLine++; + } + else if(next == '['){ + AddToken(EmptyToken(OBRACKET), line, charOnLine, indent); + charOnLine++; + } + else if(next == ']'){ + AddToken(EmptyToken(CBRACKET), line, charOnLine, indent); + charOnLine++; + } + else if(next == ':'){ + AddToken(EmptyToken(COLON), line, charOnLine, indent); + charOnLine++; + } + else if(next == '$'){ + /* Check if it is a splice substitution */ + if(text[read] == '@'){ + AddToken(EmptyToken(DOLLARAT), line, charOnLine, indent); + charOnLine++; + read++; + }else{ + AddToken(EmptyToken(DOLLAR), line, charOnLine, indent); + } + + charOnLine++; + } + else if(next == '\''){ + AddToken(EmptyToken(QUOTE), line, charOnLine, indent); + charOnLine++; + } + else if(next == '{'){ + AddToken(EmptyToken(OCURLY), line, charOnLine, indent); + charOnLine++; + } + else if(next == '}'){ + AddToken(EmptyToken(CCURLY), line, charOnLine, indent); + charOnLine++; + } + + /* Completely ignore comments */ + else if(next == '|' && text[read] == '{'){ + /* Comments start with |{ and end with }|, nested comments allowed */ + charOnLine += 2; + read ++; + int commentLevel = 1; + next = text[read]; + read++; + + while(commentLevel > 0){ + if(next == '}' && text[read] == '|'){ + commentLevel--; + } + else if(next == '|' && text[read] == '{'){ + commentLevel++; + + } + else if(next == '\0'){ + printf("Unclosed comment at end of program. Exiting."); + exit(0); + } + else if(next == '\n'){ + line++; + charOnLine = 0; + indent = 0; + } + else if(next == '\t'){ + indent++; + } + + charOnLine++; + next = text[read]; + read++; + + } + } + else if(next == ';'){ + /* For single line comments starting with a semicolon, just keep reading until the \n */ + while(next != '\n' && next != '\0'){ + next = text[read]; + read++; + } + + /* And increment the line count */ + line++; + indent = 0; + charOnLine = 0; + } + else if(next == '#'){ + /* Loop through until the end of the ident */ + while(1){ + if(!isIdentChar(text[read])){ + break; + } + + next = text[read]; + read++; + + /* Position */ + if(next == '\n'){ + line++; + indent = 0; + charOnLine = 0; + }else{ + charOnLine++; + } + } + } + + /* Record strings enclosed in "quotes" separately */ + else if(next == '"'){ + /* Record the 'previous' character and keep reading until you have a quote not preceeded by a backslash */ + CharList* str_contents = MakeCharList(); + + char prev = next; + next = text[read]; + read++; + charOnLine++; + + /* Record the starting position */ + int start_line = line; + int start_char = charOnLine; + + while(next != '"' || prev == '\\'){ + Add(str_contents, next); + prev = next; + next = text[read]; + read++; + + /* Position */ + if(next == '\n'){ + line++; + indent = 0; + charOnLine = 0; + }else{ + charOnLine++; + } + + } + + /* Add the string token and clean up */ + AddToken(DataToken(STRING, ToStr(str_contents)), start_line, start_char, indent); + Delete(str_contents); + + } + /* Lastly, deal with numbers and identifiers */ + else { + + /* Find the whole string */ + CharList* ident = MakeCharList(); + while(isIdentChar(next) && next != '\0'){ //While the character can be in a number or identifier, keep reading + Add(ident, next); + next = text[read]; + read++; + charOnLine++; + } + + /* Don't skip the character after the ident, it may be a symbol and not a space */ + read--; + + /* Convert the character list to a string */ + char* ident_string = ToStr(ident); + + /* Decide whether the string is a number or identifier token and add it */ + if(isNumber(ident)){ + AddToken(DataToken(NUM, ident_string), line, charOnLine, indent); + }else{ + AddToken(DataToken(IDENT, ident_string), line, charOnLine, indent); + } + + /* The string is no longer needed, so delete it */ + Delete(ident); + } + } + +} + +/* A utility function for reading and lexing a whole file */ +void LexFile(char* filename){ + /* Read the file and perform lexing */ + char* fileContents = ReadFile(filename); + Lex(fileContents); + + /* Free the memory used by the file contents */ + free(fileContents); + +} + +/* Functions to access the token list */ +VyToken** GetTokenList(){ + return tokenList; +} + +/* Backtrack one token */ +int BacktrackToken(){ + currentToken--; + + return currentToken; +} + +/* Return the next token */ +VyToken* GetNextToken(){ + /* Make sure there are more tokens; if not, return NULL */ + if(currentToken >= numTokens){ + return NULL; + }else{ + VyToken* next = tokenList[currentToken]; + currentToken++; //Increment the index of the current token + return next; + } +} + +/* Return a lookahead token */ +VyToken* GetLookAheadToken(){ + VyToken* next = GetNextToken(); + + /* Only backtrack if a token really was returned */ + if(next != NULL) BacktrackToken(); + + return next; +} + +/* Whether more tokens exist */ +int MoreTokensExist(){ + if(currentToken >= numTokens){ + return 0; + }else{ + return 1; + } +} + +/* Find the number of tokens */ +int GetNumTokens(){ + return numTokens; +} + diff --git a/old/lisp-lang/List.c b/old/lisp-lang/List.c new file mode 100644 index 0000000..9364a24 --- /dev/null +++ b/old/lisp-lang/List.c @@ -0,0 +1,193 @@ +#include "Vyion.h" + +/* Create a list */ +VyList** CreateList(){ + /* Create a list struct and initialize its members to NULL */ + VyList** l = CreateListObj(); + l[0]->data = -1; + l[0]->next = NULL; + + return l; +} + +/* First element of the list */ +VyObject ListHead(VyList** l){ + if(l != NULL){ + return l[0]->data; + } + + return -1; +} + +/* List tail */ +VyList** ListTail(VyList** l){ + if(l != NULL){ + return l[0]->next; + } + + return NULL; +} + +/* Get from index */ +VyObject ListGet(VyList** l, int index){ + if(l != NULL){ + /* If this one is it, return the data */ + if(index == 0){ + return l[0]->data; + } + + /* Otherwise, keep going */ + else{ + return ListGet(l[0]->next, index - 1); + } + } + + return -1; +} + +/* Clone a list */ +VyList** CloneList(VyList** l){ + /* A base case for recursive list copying */ + if(l == NULL){ + return NULL; + } + //printf("List data: (id %d) (ptr %p) (rptr %p) (next %p) (data %d)\n", ToObject(l), l, l[0], l[0]->next, l[0]->data);fflush(stdout); + + VyList** new = CreateList(); + new[0]->data = l[0]->data; + new[0]->next = CloneList(l[0]->next); + + return new; +} + +/* Internal function used in ListAppend() to avoid side effects */ +void ListInternalAppend(VyList** l, VyObject v){ + /* Check to see whether this is an empty list */ + if(l[0]->data < 0){ + /* If it is, then set its data instead of creating a new node */ + l[0]->data = v; + return; + } + + /* If this is the last node, add the value to a new node */ + if(l[0]->next == NULL){ + VyList** x = CreateList(); + l[0]->next = x; + l[0]->next[0]->data = v; + } + + /* Otherise, proceed to the last node */ + else{ + /* Use ListInternapAppend because here, we want it to have the 'side-effect' of actually adding something to the list */ + ListInternalAppend(l[0]->next, v); + } +} + +/* Append an element to a list */ +VyList** ListAppend(VyList** l, VyObject v){ + VyList** new = CloneList(l); + ListInternalAppend(new, v); + + return new; +} + +/* Find the size of a list */ +int ListSize(VyList** l){ + /* Check for empty list */ + if(l[0]->next == NULL && l[0]->data < 0){ + return 0; + } + + /* If it isn't empty, recursively compute the size */ + if(l[0]->next == NULL){ + return 1; + }else{ + return ListSize(l[0]->next) + 1; + } +} + +/* Get the list starting at an index */ +VyList** GetListStartingAt(VyList** l, int index){ + if(l != NULL){ + /* If this one is it, return the data */ + if(index == 0){ + return l; + } + + /* Otherwise, keep going */ + else{ + return GetListStartingAt(l[0]->next, index - 1); + } + } + + /* If l == NULL, return NULL */ + return NULL; +} + +/* Insert an element into a list at an index */ +VyList** ListInsert(VyList** l, VyObject v, int index){ + + /* Copy the list to avoid side effects */ + l = CloneList(l); + + /* Create the new list element */ + VyList** newList = CreateList(); + newList[0]->data = v; + + /* It it is being added to the front, just add it to the front */ + if(index == 0){ + newList[0]->next = l; + return newList; + } + + /* Else, Insert it into its place */ + VyList** prevNode = GetListStartingAt(l, index - 1); + VyList** nextNode = GetListStartingAt(l, index); + prevNode[0]->next = newList; + newList[0]->next = nextNode; + + return l; +} + +/* Concatenate two lists (make sure to copy the lists so that this call has no side effects) */ +VyList** ListConcat(VyList** one, VyList** two){ + /* Find the last node of list one */ + VyList** oneCopy = CloneList(one); + VyList** node = GetListStartingAt(oneCopy, ListSize(oneCopy)); + + /* Set the next one to be the start of list two */ + node[0]->next = CloneList(two); + + return oneCopy; +} + +/* Delete the list (but not the values) */ +void DeleteList(VyList** l){ + if(l[0]->next != NULL){ + DeleteList(l[0]->next); + free(l[0]->next); + } + + free(l); +} + +/* Print a list */ +void PrintList(VyList** l){ + int listSize = ListSize(l); + int i; + + printf("("); + + /* Cycle through and print each value */ + for(i = 0; i < listSize;i++){ + VyObject next = ListGet(l, i); + PrintObj(next); + printf(" "); + } + + /* Delete the extra space if needed */ + if(listSize > 0){ + printf("\b"); + } + printf(")"); +} diff --git a/old/lisp-lang/Macro.c b/old/lisp-lang/Macro.c new file mode 100644 index 0000000..f46cbe5 --- /dev/null +++ b/old/lisp-lang/Macro.c @@ -0,0 +1,65 @@ +#include "Vyion.h" + +/* Create a macro */ +VyMacro** CreateMacro(Argument** args, int numArguments, VyParseTree* code, Scope* scp){ + VyMacro** mac = CreateMacroObj(); + mac[0]->args = args; + mac[0]->numArgs = numArguments; + mac[0]->code = code; + mac[0]->scp = scp; + + return mac; +} + +/* Evaluate a macro and return the resulting parse tree */ +VyParseTree* EvalMacro(VyMacro** mac, VyObject* args, int numArgs){ + /* Check the macro arguments */ + char* err = CheckFunctionArguments(mac[0]->args, mac[0]->numArgs, args, numArgs); + if(err != NULL){ + HandleError(ToObject(CreateError(err, NULL))); + } + + /* Evaluate it as a native function */ + VyObject obj = EvalNativeFunctionOrMacro(mac[0]->args, mac[0]->numArgs, mac[0]->code, mac[0]->scp, args, numArgs); + if(ObjType(obj) == VALERROR){ + HandleError(obj); + } + VyParseTree* tree = ObjToParseTree(obj); + + return tree; +} + +/* Parse a macro */ +VyObject ParseMacro(VyParseTree* code){ + /* Parse the function arguments */ + VyParseTree* args = GetListData(code, 1); + int numArguments = 0; + char* error = NULL; + Argument** arguments = ParseFunctionArguments(args, &numArguments, &error); + if(error != NULL){ + return ToObject(CreateError(error, code)); + } + + /* Take the rest of the expressions in the lambda as code */ + VyParseTree* exprList = MakeListTree(); + int i; + for(i = 2; i < ListTreeSize(code); i++){ + AddToList(exprList, GetListData(code, i)); + } + + /* Take variables from the current function scope and the local scope */ + Scope* funcScope = GetCurrentFunctionScope(); + Scope* localScope = GetLocalScope(); + + /* Make sure the local scope isn't the global scope */ + if(localScope == GetGlobalScope()) { + localScope = NULL; + } + + /* Merge the two scopes to get the current function scope */ + Scope* closureScope = MergeScopes(funcScope, localScope); + + /* Create the function from the data gathered */ + VyMacro** mac = CreateMacro(arguments, numArguments, exprList, closureScope); + return ToObject(mac); +} diff --git a/old/lisp-lang/Mem.c b/old/lisp-lang/Mem.c new file mode 100644 index 0000000..432b4c0 --- /dev/null +++ b/old/lisp-lang/Mem.c @@ -0,0 +1,78 @@ +#include "Vyion.h" + +/* How many bytes the GC should allocate at start time */ +#define INIT_ALLOC 1024*100 + +/* How much the allocator should allocate every time more memory is needed */ +#define ALLOC_STEP 1.75 + +/* A temporary holder for the base of a heap when the new heap is created */ +void* tempBase = NULL; + +/* Initialize the garbage collector and heap and allocate a starting amount of memory */ +void InitMem(){ + /* Initialize the heap data structure */ + VyMemHeap* heap = malloc(sizeof(VyMemHeap)); + heap->objectsOnHeap = heap->usedSpace = 0; + heap->idMapSize = 10000; + + /* Let CreateObj() do the initial allocation too */ + heap->numIdMaps = 0; + heap->idMapArray = NULL; + + /* And allocate the heap memory itself */ + heap->heapBase = heap->freeMem = malloc(INIT_ALLOC); + heap->heapSize = INIT_ALLOC; + + /* Set this heap as the current memory heap */ + SetMemoryHeap(heap); +} + +/* Free the remaining memory */ +void FreeHeap(VyMemHeap* heap){ + free(heap); +} + +/* Force a collection cycle to happen */ +void VyMemCollect(VyMemHeap* heap){ + void* newHeap = calloc(1, heap->heapSize * ALLOC_STEP); + if(newHeap == NULL){ + printf("Not enough space for large heap. Dead."); + fflush(stdout); + } + heap->heapSize *= ALLOC_STEP; + void* freeMemStart = newHeap; + + int id; + for(id = 0; id < heap->objectsOnHeap; id++){ + int objIndex = id % heap->idMapSize; + int idMapNum = id/heap->idMapSize; + + int objSize = DataSize(ObjType(id)) + sizeof(int); + void* toCopy = heap->idMapArray[idMapNum][1][objIndex] - sizeof(int); + + heap->idMapArray[idMapNum][1][objIndex] = freeMemStart + sizeof(int); + memcpy(freeMemStart, toCopy, objSize); + freeMemStart += objSize; + } + free(heap->heapBase); + heap->heapBase = newHeap; + heap->freeMem = freeMemStart; +} + +/* Provide a way for Vyion to allocate memory on the heap */ +void* VyMallocate(int size, VyMemHeap* heap){ + + /* Check whether the heap ran out of space, and if it has, it's time to for a garbage collection cycle */ + if(size + heap->usedSpace > heap->heapSize){ + printf("Heap: %p ", heap->freeMem); + VyMemCollect(heap); + printf("\nHeap: %p ", heap->freeMem); + printf("? %d ?\n", heap->objectsOnHeap); + } + + /* Store and then increment the free memory location */ + heap->usedSpace += size; + heap->freeMem += size; + return heap->freeMem - size; +} diff --git a/old/lisp-lang/Number.c b/old/lisp-lang/Number.c new file mode 100644 index 0000000..cb58984 --- /dev/null +++ b/old/lisp-lang/Number.c @@ -0,0 +1,355 @@ +#include "Vyion.h" + +/* Return the last caused parsing error */ +char* parsingError = NULL; +char* GetLastNumberParsingError(){ + return parsingError; +} + +/* Find the amount of memory this number uses */ +int NumberSize(int type){ + switch(type){ + case REAL: + return sizeof(RealNum); + case COMPLEX: + return sizeof(ComplexNum); + case INT: + return sizeof(IntNum); + case RATIO: + return sizeof(RatioNum); + default: + return 0; + } +} + +/* Create a general number with no init value */ +VyNumber** CreateNumber(int type){ + /* Create a number object */ + VyNumber** num = CreateNumObj(); + num[0]->type = type; + + /* Now allocate space for the actual contents of this number */ + num[0]->data = malloc(NumberSize(type)); + + return num; +} + +/* Convert a VyNumber** to one of the number subtypes (actually, to a void pointer) */ +void* NumberToSubtype(VyNumber** num){ + return num[0]->data; +} + +/* Create an integer */ +VyNumber** CreateInt(int i){ + /* Create a number */ + VyNumber** num = CreateNumber(INT); + + /* Set the value */ + IntNum* iNum = NumberToSubtype(num); + iNum->i = i; + + return num; +} + +/* Create a double value number */ +VyNumber** CreateReal(double d){ + VyNumber** num = CreateNumber(REAL); + + RealNum* rNum = NumberToSubtype(num); + rNum->d = d; + + return num; +} + +/* Create a complex number with a real coefficient of 0 (i.e. only the imaginary part) */ +VyNumber** CreateImaginary(VyNumber** n){ + VyNumber** num = CreateNumber(COMPLEX); + + ComplexNum* cNum = NumberToSubtype(num); + cNum->real = CreateInt(0); + cNum->imaginary = n; + + return num; +} + +/* Create a complex number */ +VyNumber** CreateComplex(VyNumber** real, VyNumber** imaginary){ + VyNumber** cmplex = CreateNumber(COMPLEX); + + ComplexNum* cNum = NumberToSubtype(cmplex); + + cNum->real = real; + cNum->imaginary = imaginary; + + return cmplex; +} + +/* Create a ratio from two ints */ +VyNumber** CreateRatio(int numerator, int denominator){ + VyNumber** ratio = CreateNumber(RATIO); + + RatioNum* rNum = NumberToSubtype(ratio); + + rNum->numerator = numerator; + rNum->denominator = denominator; + + return ratio; +} + +/* Convert a ratio to a double number */ +VyNumber** RatioToReal(VyNumber** ratio){ + RatioNum* rNum = NumberToSubtype(ratio); + double real = ((double)(rNum->numerator))/rNum->denominator; + return CreateReal(real); +} + +/* Print a number */ +void PrintNumber(VyNumber** num){ + /* Print the number differently depending on the type */ + if(num[0]->type == INT){ + IntNum* iNum = NumberToSubtype(num); + printf("%d",iNum->i); + }else if(num[0]->type == REAL){ + RealNum* rNum = NumberToSubtype(num); + printf("%f", rNum->d); + }else if(num[0]->type == COMPLEX){ + ComplexNum* cNum = NumberToSubtype(num); + PrintNumber(cNum->real); + printf("+"); + PrintNumber(cNum->imaginary); + printf("i"); + } +} + +/* Convert a string to a double */ +double StringToDouble(char* str){ + double result = 0; + + int index = 0; + char next = str[index]; + + /* Find the integer part */ + while(next != '.' && next != '\0'){ + /* Find the int value of the digit */ + int digit = next - '0'; + + /* Update result */ + result = result*10 + digit; + + /* Next character */ + index++; + next = str[index]; + } + + /* Find the decimal part if it exists */ + if(next == '.'){ + /* Skip the decimal point */ + index++; + next = str[index]; + + double scale = 0.1; + while(next != '\0'){ + /* Add the value to the result */ + int digit = next - '0'; + result = result + digit * scale; + scale *= 0.1; + + /* Next character */ + index++; + next = str[index]; + } + } + + return result; +} + +/* Given all the data about a number that is contained in the string, create a number from it */ +VyNumber** ParseNumberFromData(CharList* beforeRadix, CharList* afterRadix, CharList* exponential, int isNegated, int isImaginary){ + + /* Determine the type based on the arguments and parse the number appropriately */ + VyNumber** num = NULL; + + /* Convert the CharList*s to strings so that we can deal with them */ + char* exponentialStr = ToStr(exponential); + char* beforeRadixStr = ToStr(beforeRadix); + char* afterRadixStr = ToStr(afterRadix); + + /* Concatenate the strings to form a double */ + char* dotted = ConcatStrings(beforeRadixStr, "."); + char* doubleStr = ConcatStrings(dotted,afterRadixStr); + free(dotted); + + /* Imaginary? */ + if(isImaginary){ + /* Create a complex number with default real value of 0 */ + num = CreateNumber(COMPLEX); + ComplexNum* cNum = NumberToSubtype(num); + cNum->real = CreateInt(0); + cNum->imaginary = ParseNumberFromData(beforeRadix, afterRadix, exponential, 0, 0); + } + + /* Integer? */ + else if(Size(afterRadix) <= atoi(exponentialStr)){ + /* Integer IF there is no decimal part OR the 10 exponent turns the decimal into an integer */ + double d = StringToDouble(doubleStr); + int i = (int)(d*pow(10, atoi(exponentialStr))); + + /* Make negative if needed */ + if(isNegated){ + i = -i; + } + + num = CreateNumber(INT); + IntNum* iNum = NumberToSubtype(num); + iNum->i = i; + } + + /* Else, double */ + else { + double d = StringToDouble(doubleStr); + d = d*pow(10,atoi(exponentialStr)); + + /* Make negative if needed */ + if(isNegated){ + d = -d; + } + + num = CreateNumber(REAL); + RealNum* rNum = NumberToSubtype(num); + rNum->d = d; + } + + /* Free the used strings */ + free(exponentialStr); + free(beforeRadixStr); + free(afterRadixStr); + free(doubleStr); + + return num; +} + +/* Given a string, find all the data needed to create a number from it an create a number */ +VyNumber** ParseNumber(char* numStr){ + /* Set the parsing error to NULL to reset it */ + parsingError = NULL; + + /* Declare variables to store data about the number */ + int hasRadix = 0; + + /* The radix denotes where the integer part ends */ + CharList* beforeRadix = MakeCharList(); + CharList* afterRadix = MakeCharList(); + + /* For exponential form */ + int isExponentialForm = 0; + CharList* exponent = MakeCharList(); + + /* Imaginary? */ + int imaginary = 0; + + /* Negated? */ + int isNegated = 0; + + /* Declare variables needed for iteration over the characters */ + int index = 0; + char next = numStr[index]; + + /* If it is negated, parse the rest and negate */ + if(numStr[0] == '-'){ + isNegated = 1; + index++; + next = numStr[index]; + } + + /* Also allow a + instead of a -, although it does nothing */ + else if(numStr[0] == '+'){ + index++; + next = numStr[index]; + } + + + /* For each character in the string */ + while(next != '\0'){ + /* If it finds a radix */ + if(next == '.'){ + hasRadix = 1; + + /* If it is already in exponential form, a radix is an error, because exponential + * form only takes ints for the exponent, so there cannot be a radix */ + if(isExponentialForm){ + parsingError = "Badly formatted number: scientific notation exponent must be integer."; + return NULL; + } + } + + /* Scientific notation */ + else if(next == 'e'){ + isExponentialForm = 1; + + /* If the next is + or -, allow them */ + if(numStr[index + 1] == '+' || numStr[index + 1] == '-'){ + Add(exponent, numStr[index + 1]); + + /* Continue on to the next character */ + index++; + next = numStr[index]; + } + + /* 'e' cannot be the last character */ + else if(numStr[index + 1] == '\0'){ + parsingError = "Badly formatted number: Expecting exponent after 'e' (scientific notation)"; + return NULL; + } + } + + /* If it is an imaginary number */ + else if(next == 'i'){ + imaginary = 1; + + /* If the 'i' isn't last, error */ + if(numStr[index + 1] != '\0'){ + parsingError = "Badly formatted number: 'i', indicating imaginary numbers, must come last in a number."; + return NULL; + } + } + + /* No other non-numeric characters are allowed */ + else if(!isNumeric(next)){ + parsingError = "Badly formatted number: non-numeric characters in number."; + return NULL; + } + + /* If it is just a number, add it to the correct char list */ + else{ + if(!isExponentialForm){ + if(!hasRadix){ + Add(beforeRadix, next); + } + else{ + Add(afterRadix, next); + } + } + else{ + Add(exponent, next); + } + } + + /* Next character */ + index++; + next = numStr[index]; + } + + /* Call a function to use the data gained to create a number */ + VyNumber** number = ParseNumberFromData(beforeRadix, afterRadix, exponent, isNegated, imaginary); + + /* Free the character lists */ + Delete(beforeRadix); + Delete(afterRadix); + Delete(exponent); + + /* Return the result */ + return number; + + +} + diff --git a/old/lisp-lang/Object.c b/old/lisp-lang/Object.c new file mode 100644 index 0000000..7a0fc7c --- /dev/null +++ b/old/lisp-lang/Object.c @@ -0,0 +1,155 @@ +#include "Vyion.h" + +/* This is the implementation of generic objects. + * + * VyObjects are not actually objects - instead, they are just the ID's of objects. (You can verify this by looking at Declarations.h.) + * The actual object data is stored on the memory heap. The memory heap structure contains an array which links the object id's + * as the indices of the array to the object type and the object data. (See Mem.h, too) + * + * To find the actual locations of the object, the interpreter maintains an array, each slot corresponding to one object. + * If the index of a slow is an object's ID, then the data stored there is the actual location of the object. Thus, + * when the garbage collector is trigerred, all it needs to do is update that array. (The array is added to by CreateObj(), + * with one new slot used for every new object. ) + * + * To get the actual data from an object, use the ObjData() function, and to get the type, use the ObjType() function. Both of them + * use the array to look up - well, actually, it isn't look up since its just one array access - but anyway, they use the array + * to find the location of the object on the heap, and then use that to find the type and data. + * + * Often, you will find yourself with a VyFunction**, or VyNumber**, etc etc, and you need to find the ID of that object. To do this, + * use the ToObject() function. The ID of an object is stored in the contiguous memory BEFORE an object as an integer, so the ToObject() + * function just finds this location and retrieves the ID from it. + * + * *Note: 'virtually' isn't really true. It happens when the heap runs out of memory - however, there's now way of + * predicting this, really, so manipulating any objects in the same function as creating them would be unsafe. + */ + +/***** Create objects *****/ + +/* The heap on which all these objects are stored */ +VyMemHeap* heap = NULL; + +void SetMemoryHeap(VyMemHeap* memHeap){ + heap = memHeap; +} +VyMemHeap* GetMemoryHeap(){ + return heap; +} + +/* Find the size (in bytes) taken up by the actual data behind an object for a certain type */ + int typeSizes[] = { + sizeof(VyNumber), + sizeof(VyFunction), + sizeof(VyList), + sizeof(VySymbol), + sizeof(VyBoolean), + sizeof(VyMacro), + sizeof(VyError), + sizeof(VyFlowControl) + }; +int DataSize(int type){ + return typeSizes[type]; +} + +/* Allocate memory for an object of a certain type, and return the ID of the object */ +VyObject CreateObj(int type){ + /* Mallocate room */ + void* mem = VyMallocate(DataSize(type) + sizeof(int), heap); + + /* The object Id is just the number of the object on the heap */ + int objId = heap->objectsOnHeap; + + /* If needed, add space in the arrays */ + int objIndex = objId % heap->idMapSize; + if(objIndex == 0){ + /* Increase the number of ID maps and allocate space for everything */ + heap->numIdMaps++; + heap->idMapArray = realloc(heap->idMapArray, sizeof(void***) * heap->numIdMaps); + heap->idMapArray[heap->numIdMaps - 1] = malloc(sizeof(void**) * 2); + heap->idMapArray[heap->numIdMaps - 1][0] = malloc(sizeof(void*) * heap->idMapSize); + heap->idMapArray[heap->numIdMaps - 1][1] = malloc(sizeof(void*) * heap->idMapSize); + } + + /* The location of the object in the arrays */ + + heap->idMapArray[heap->numIdMaps - 1][0][objIndex] = (void*)(type); + heap->idMapArray[heap->numIdMaps - 1][1][objIndex] = mem + sizeof(int); + + /* Store the id of the object right before the object itself for efficiency */ + *(int*)(mem) = objId; + heap->objectsOnHeap++; + + /* Return the ID */ + return objId; +} + +/* Create objects */ +VyBoolean** CreateBoolObj(){ + return ObjData(CreateObj(VALBOOL)); +} +VyNumber** CreateNumObj(){ + return ObjData(CreateObj(VALNUM)); +} +VyFunction** CreateFuncObj(){ + VyFunction** f = ObjData(CreateObj(VALFUNC)); + return f; +} +VyMacro** CreateMacroObj(){ + return ObjData(CreateObj(VALMAC)); +} +VyList** CreateListObj(){ + return ObjData(CreateObj(VALLIST)); +} +VySymbol** CreateSymbObj(){ + return ObjData(CreateObj(VALSYMB)); +} +VyError** CreateErrorObj(){ + return ObjData(CreateObj(VALERROR)); +} +VyFlowControl** CreateFlowControlObj(){ + return ObjData(CreateObj(VALFLOW)); +} + +/***** Retrieve data from VyObject pointers *****/ + +void* ObjData(VyObject val){ + int idMapNum = val/heap->idMapSize; + int objIndex = val % heap->idMapSize; + return &(heap->idMapArray[idMapNum][1][objIndex]); +} +int ObjType(VyObject val){ + int idMapNum = val/heap->idMapSize; + int objIndex = val % heap->idMapSize; + return (int)(heap->idMapArray[idMapNum][0][objIndex]); +} + +/* Retrieve the object ID from a VyNumber**, VyFunction**, VyList**, etc */ +VyObject ToObject(void* doublePointer){ + /* Get the pointer to the ID of this object */ + void** ptr = (void**)(doublePointer); + int* idPtr = (int*)((char*)(*ptr) - sizeof(int)); + return *idPtr; +} + +/* Print a value */ +void PrintObj(VyObject val){ + if(ObjType(val) == VALNUM){ + PrintNumber(ObjData(val)); + } + + else if(ObjType(val) == VALLIST){ + PrintList(ObjData(val)); + } + + else if(ObjType(val) == VALSYMB){ + PrintSymbol(ObjData(val)); + } + + else if(ObjType(val) == VALBOOL){ + PrintBoolean(ObjData(val)); + } + + else if(ObjType(val) == VALERROR){ + PrintError(ObjData(val)); + } + +} diff --git a/old/lisp-lang/ParseTree.c b/old/lisp-lang/ParseTree.c new file mode 100644 index 0000000..e6107bd --- /dev/null +++ b/old/lisp-lang/ParseTree.c @@ -0,0 +1,282 @@ +#include "Vyion.h" + +/* Create a general empty parse tree of a certain type */ +VyParseTree* MakeParseTree(int type){ + VyParseTree* tree = malloc(sizeof(VyParseTree)); + tree->type = type; + tree->data = malloc(sizeof(tree_node_data)); + tree->pos = NULL; + return tree; +} + +/* Create a list */ +VyParseTree* MakeListTree(){ + VyParseTree* list = MakeParseTree(TREE_LIST); + list->data->list.length = 0; + list->data->list.list = NULL; + return list; +} + +/* Create a number */ +VyParseTree* MakeNum(){ + VyParseTree* num = MakeParseTree(TREE_NUM); + return num; +} + +/* Create a string */ +VyParseTree* MakeString(){ + VyParseTree* str = MakeParseTree(TREE_STR); + return str; +} + +/* Create an ident */ +VyParseTree* MakeIdent(){ + VyParseTree* ident = MakeParseTree(TREE_IDENT); + return ident; +} + +/* Put something in a quote */ +VyParseTree* Quote(VyParseTree* elem){ + /* The resulting list, (quote ...) */ + VyParseTree* qList = MakeListTree(); + + /* The quote ident */ + VyParseTree* qIdent = MakeIdent(); + SetStrData(qIdent, "quote"); + + /* Add to the list */ + AddToList(qList, qIdent); + AddToList(qList, elem); + + return qList; +} + +/* Find out if a list is a quote list */ +int IsQuote(VyParseTree* qt){ + /* It must be a list with two elements to be a quote */ + if(qt->type == TREE_LIST){ + if(ListTreeSize(qt) == 2){ + /* And the first element must be the quote ident */ + if(GetListData(qt,0)->type == TREE_IDENT && strcmp(GetStrData(GetListData(qt, 0)), "quote") == 0){ + return 1; + } + } + } + + /* Assume false otherwise */ + return 0; +} + +/* Put something in a substitution */ +VyParseTree* Substitution(VyParseTree* elem, int splice){ + /* The resulting list, (quote ...) */ + VyParseTree* sList = MakeListTree(); + + /* The quote ident */ + VyParseTree* sIdent = MakeIdent(); + if(splice){ + SetStrData(sIdent, "splicing-substitution"); + }else{ + SetStrData(sIdent, "substitution"); + } + + /* Add to the list */ + AddToList(sList, sIdent); + AddToList(sList, elem); + + return sList; +} + +/* Find out if a list is a substitution list */ +int IsSubstitution(VyParseTree* qt){ + /* Same rules apply as for IsQuote, except the ident is different */ + if(qt->type == TREE_LIST){ + if(ListTreeSize(qt) == 2){ + if(GetListData(qt,0)->type == TREE_IDENT){ + char* str = GetStrData(GetListData(qt, 0)); + if(strcmp(str, "substitution") == 0 || strcmp(str, "splicing-substitution") == 0){ + return 1; + } + + } + } + } + + /* Assume false otherwise */ + return 0; +} + +/* Find whether it is a splicing substitution */ +int IsSplicingSubstitution(VyParseTree* subst){ + if(IsSubstitution(subst) + && strcmp(GetStrData(GetListData(subst, 0)), "splicing-substitution") == 0){ + return 1; + } + return 0; +} + +/* Create a reference */ +VyParseTree* Reference(VyParseTree* obj, VyParseTree* ref){ + VyParseTree* tree = MakeParseTree(TREE_REF); + tree->type = TREE_REF; + tree->data->ref.obj = obj; + tree->data->ref.ref= ref; + return tree; +} + +/* Make an error node */ +VyParseTree* ParseError(char* message){ + VyParseTree* error = MakeParseTree(TREE_ERROR); + error->data->error.message = message; + return error; +} + +/* Find the obj or ref parts of the reference */ +inline VyParseTree* GetObj(VyParseTree* ref){ + return ref->data->ref.obj; +} +inline VyParseTree* GetRef(VyParseTree* ref){ + return ref->data->ref.ref; +} + +/* Find the size of a list tree */ +inline int ListTreeSize(VyParseTree* tree){ + return tree->data->list.length; +} + +/* Add to a list and return it's size */ +int AddToList(VyParseTree* tree, VyParseTree* item){ + /* If it isn't a list, return 0 */ + if(tree->type != TREE_LIST){ + return 0; + } + + /* Allocate more memory and add the item */ + tree->data->list.list = realloc(tree->data->list.list, sizeof(VyParseTree*)*(ListTreeSize(tree)+ 1)); + tree->data->list.list[ListTreeSize(tree)] = item; + + /* Increment the list's size */ + tree->data->list.length++; + + return 1; +} + + +/* Get data from a list */ +VyParseTree* GetListData(VyParseTree* tree, int index){ + return tree->data->list.list[index]; +} + +/* Get the first element of a list */ +VyParseTree* ListTreeHead(VyParseTree* list){ + /* Validate that it is a list and has at least one element */ + if(list->type != TREE_LIST && ListTreeSize(list) > 0){ + return NULL; + } + else{ + return GetListData(list, 0); + } +} + + +/* Set or fetch string data for ident nodes */ +int SetStrData(VyParseTree* tree, char* str){ + /* Make sure it has an appropriate type */ + switch(tree->type){ + case TREE_IDENT: + tree->data->ident.str = strdup(str); + return 1; + case TREE_STR: + tree->data->str.str = strdup(str); + return 1; + default: + return 0; + } + + +} +char* GetStrData(VyParseTree* tree){ + /* Make sure it has an appropriate type */ + switch(tree->type){ + case TREE_IDENT: + return tree->data->ident.str; + case TREE_STR: + return tree->data->str.str; + default: + return NULL; + } + + +} + +/* Get and set number data */ +void SetNumberData(VyParseTree* tree, VyNumber** num){ + if(tree->type == TREE_NUM){ + tree->data->num.num = num; + } +} +VyNumber** GetNumberData(VyParseTree* tree){ + if(tree->type == TREE_NUM){ + return tree->data->num.num; + }else{ + return NULL; + } +} + +/* Set the position */ +void SetPosition(VyParseTree* tree, Position* pos){ + /* Copy all the position data */ + if(tree->pos == NULL) { + tree->pos = malloc(sizeof(Position)); + tree->pos->line = pos->line; + tree->pos->indent = pos->indent; + tree->pos->character = pos->character; + } +} + +/* Delete a parse tree */ +void DeleteParseTree(VyParseTree* tree){ + /* Make sure you aren't freeing null pointers */ + if(tree != NULL){ + if(tree->data != NULL){ + /* Free all the sub-trees depending on the type */ + int treeType = tree->type; + + /* For identifiers the only associated data to free is the string data */ + if(treeType == TREE_IDENT){ + free(tree->data->ident.str); + } + + /* For lists, free all the members of the list */ + else if(treeType == TREE_LIST){ + /* Iterate through and free all the elements */ + int i; + for(i = 0; i < ListTreeSize(tree); i++){ + VyParseTree* next = GetListData(tree,i); + DeleteParseTree(next); + } + + /* Free the used array */ + free(tree->data->list.list); + } + + /* For references, free both parts of the reference */ + else if(treeType == TREE_REF){ + DeleteParseTree(GetObj(tree)); + DeleteParseTree(GetRef(tree)); + } + + + + /* Finally, free the rest of the tree and the data*/ + free(tree->data); + } + /* Free the position data */ + if(tree->pos != NULL){ + free(tree->pos); + } + free(tree); + } +} + + diff --git a/old/lisp-lang/Parser.c b/old/lisp-lang/Parser.c new file mode 100644 index 0000000..9068c4f --- /dev/null +++ b/old/lisp-lang/Parser.c @@ -0,0 +1,410 @@ +#include "Vyion.h" + +VyParseTree* Parse(); + +/* Parse a generic list (either () or []) */ +VyParseTree* ParseListGeneric(int endTokenType){ + /* Create a list with no items in it */ + VyParseTree* list = MakeListTree(); + + /* Make sure there is more to read and that the file isn't over */ + if(!MoreTokensExist()){ + return ParseError("Unclosed list at end of file."); + } + + /* While the list, isn't over add items to it */ + VyToken* nextToken; + while((nextToken = GetLookAheadToken())->type != endTokenType){ + /* Add the next element, which is recieved from Parse(), to the list */ + VyParseTree* nextElement = Parse(); + AddToList(list, nextElement); + + + /* If there are no more tokens, then a parenthesis is unclosed */ + if(!MoreTokensExist()) { + VyParseTree* error = ParseError("Unclosed list"); + SetPosition(error, nextToken->pos); + AddToList(list, error); + return list; + } + + } + GetNextToken(); + + + return list; + +} + +/* Parse a list */ +VyParseTree* ParseList(){ + return ParseListGeneric(CPAREN); +} + +/* Parse a bracketed list as a quoted list */ +VyParseTree* ParseBracketedList(){ + /* Same procedure as for a normal list, but + * with CBRACKET as the end condition instead of CPAREN */ + VyParseTree* list = ParseListGeneric(CBRACKET); + + /* Put it in an outer list containting quote-substitutions */ + VyParseTree* outerList = MakeListTree(); + VyParseTree* symb = MakeIdent(); + SetStrData(symb, "quote-substitutions"); + AddToList(outerList, symb); + AddToList(outerList, list); + + return outerList; +} + +/* Parse a list enclosed in {braces} as an infix list */ +VyParseTree* ParseCurlyList(){ + VyParseTree* list = ParseListGeneric(CCURLY); + + /* Put it in an outer list containting quote-substitutions */ + VyParseTree* outerList = MakeListTree(); + VyParseTree* symb = MakeIdent(); + SetStrData(symb, "infix"); + AddToList(outerList, symb); + AddToList(outerList, list); + + return outerList; +} + +/* Parse an item preceeded by a quote mark ' */ +VyParseTree* ParseQuoted(){ + /* Parse it normally and put it in a quote */ + return Quote(Parse()); +} + +/* Parse a substitution (an item preceeded by a dollar sign) */ +VyParseTree* ParseSubstitution(){ + /* Parse the next item and put it in a substitution node */ + return Substitution(Parse(), 0); +} + +/* Parse a splicing subsitution */ +VyParseTree* ParseSpliceSubstitution(){ + /* Parse the next item and put it in a substitution node */ + return Substitution(Parse(), 1); +} + +/* Parse a number from a token */ +VyParseTree* ParseNumberFromToken(VyToken* tok){ + char* numData = tok->data; + VyNumber** num = ParseNumber(numData); + + /* Check for errors in the parsing */ + char* error = GetLastNumberParsingError(); + if(error != NULL){ + return ParseError(error); + } + + /* If no errors, return the parsing result */ + else{ + VyParseTree* tree = MakeNum(); + SetNumberData(tree, num); + return tree; + } +} + +/* Parse the next expression */ +VyParseTree* Parse(){ + /* Check that we have not reached the end of the input stream; if so, return null */ + if(!MoreTokensExist()){ + return NULL; + } + + + /* Get the next token */ + VyToken* next = GetNextToken(); + + /* It's type is used to determine how to continue parsing */ + int tokType = next->type; + + /* Store the result of parsing before returning it */ + VyParseTree* expr; + + /* If it starts with a parenthesis, parse it as a list */ + if(tokType == OPAREN){ + expr = ParseList(); + } + + /* If it begins with a quote, then parse whatever is next and quote it */ + else if(tokType == QUOTE){ + expr = ParseQuoted(); + } + + /* Parse a substitution */ + else if(tokType == DOLLAR){ + expr = ParseSubstitution(); + } + /* Parse a splicing substitution */ + else if(tokType == DOLLARAT){ + expr = ParseSpliceSubstitution(); + } + + /* Parse a bracketed list */ + else if(tokType == OBRACKET){ + expr = ParseBracketedList(); + } + + /* Parse an infix list (curly braces) */ + else if(tokType == OCURLY){ + expr = ParseCurlyList(); + } + /* If it is a number, identifier, or string then make a parse tree out of the token */ + else if(tokType == IDENT){ + VyParseTree* ident = MakeIdent(); + SetStrData(ident, next->data); + expr = ident; + } + else if(tokType == NUM){ + expr = ParseNumberFromToken(next); + } + else if(tokType == STRING){ + VyParseTree* str = MakeString(); + SetStrData(str,next->data); + expr = str; + } + /* Unexpected end of list */ + else if(tokType == CPAREN || tokType == CBRACKET || tokType == CCURLY){ + VyParseTree* err = ParseError("Unexpected end of list"); + SetPosition(err, next->pos); + return err; + } + + /* If there is no expression before a :, then the token type will be COLON + * Instead of dying, add an error */ + else if(tokType == COLON){ + VyParseTree* error = ParseError("Reference lacking instance"); + SetPosition(error, next->pos); + return error; + } + + /* Handle object references: Check whether the next token is a colon. + * If so, then use the previously parsed expression (expr) and another + * expression gotten from Parse() to create a reference node */ + VyToken* lookAhead = GetNextToken(); + if(lookAhead != NULL /* Make sure that the token list didn't end before looking at the type */ + && lookAhead->type == COLON){ + VyParseTree* obj = expr; + + VyParseTree* ref = Parse(); + + /* Check for validity */ + if(ref == NULL){ + expr = Reference(obj, ParseError("Incomplete reference.")); + }else{ + expr = Reference(obj, ref); + } + } + else{ + /* Backtrack one token to make up for the lookahead */ + if(lookAhead != NULL) BacktrackToken(); + } + + /* Set the position of the current expression */ + SetPosition(expr, next->pos); + + /* If the tree is an object reference, set the position of + * the first part (obj), because it wasn't gotten through a full Parse() call*/ + if(expr->type == TREE_REF){ + SetPosition(GetObj(expr), next->pos); + } + + return expr; +} + +/* Check and print errors */ +int CheckAndPrintErrors(VyParseTree* tree){ + int treeType = tree->type; + int error = 0; + + if(treeType == TREE_LIST){ + /* Check each element recursively */ + int i; + for(i = 0; i < ListTreeSize(tree); i++){ + VyParseTree* next = GetListData(tree,i); + + /* Check the sub nodes for errors */ + int listError = CheckAndPrintErrors(next); + if(listError) error = 1; + } + } + + /* Check each piece of the ref */ + else if(treeType == TREE_REF){ + + int objError = CheckAndPrintErrors(GetObj(tree)); + int refError = CheckAndPrintErrors(GetRef(tree)); + if(objError || refError) error = 1; + } + + /* If it is an error, print the error */ + else if(treeType == TREE_ERROR){ + printf("\n\n"); + printf("------- Parsing Error -------\n"); + printf("Position: "); + PrintPosition(tree->pos); + printf("\n"); + printf(tree->data->error.message); + printf("\n-----------------------------"); + error = 1; + } + + return error; + + +} + +/* Functions to print the tree */ +int linesPrinted = 0; + +/* Print a string multiple times */ +void PrintMultiple(char* str, int times){ + int t; + for(t = 0; t < times; t++){ + printf(str); + } +} + +void PrintParseTree(VyParseTree*); +void PrintListGeneric(VyParseTree* tree, char oDelim, char cDelim){ + printf("%c", oDelim); + + /* Print each element recursively */ + int i; + for(i = 0; i < ListTreeSize(tree); i++){ + VyParseTree* next = GetListData(tree,i); + if(IsQuote(next)){ + printf("'"); + PrintParseTree(GetListData(next, 1)); + } + else if(IsSubstitution(next)){ + if(IsSplicingSubstitution(next)){ + printf("$@"); + }else{ + printf("$"); + } + + PrintParseTree(GetListData(next, 1)); + } + else if(next->type == TREE_LIST){ + VyParseTree* first = GetListData(next, 0); + if(first->type == TREE_IDENT && StrEquals(GetStrData(first), "infix")){ + PrintListGeneric(GetListData(next, 1), '{','}'); + } + else if(first->type == TREE_IDENT && StrEquals(GetStrData(first), "quote-substitutions")){ + PrintListGeneric(GetListData(next, 1), '[',']'); + }else{ + PrintParseTree(next); + } + } + else{ + PrintParseTree(next); + } + } + + /* If it wasn't an empty list, remove the extra space generated by the item inside */ + if(ListTreeSize(tree) > 0){ + printf("\b"); + } + + printf("%c ", cDelim); +} + +/* Recursively print a parse tree as code */ +void PrintParseTree(VyParseTree* tree){ + int treeType = tree->type; + + /* If it is a list, then print a parenthesized list */ + if(treeType == TREE_LIST){ + PrintListGeneric(tree, '(', ')'); + } + + /* Print a reference separated by a colon */ + else if(treeType == TREE_REF){ + PrintParseTree(GetObj(tree)); + /* Delete the previous space before adding the colon */ + printf("\b:"); + PrintParseTree(GetRef(tree)); + } + + /* If it is a number or identifier, just print the string */ + else if(treeType == TREE_IDENT) { + printf("%s ", GetStrData(tree)); + } + else if(treeType == TREE_NUM){ + PrintNumber(GetNumberData(tree)); + + /* Print a space so that the backspace doesn't delete part of the number */ + printf(" "); + } + /* Print strings enclosed in quotes */ + else if(treeType == TREE_STR){ + printf("\""); + printf("%s", GetStrData(tree)); + printf("\""); + printf("\""); + } + + /* If it is an error, print the error */ + else if(treeType == TREE_ERROR){ + printf("\n---------------------------------\n"); + printf("Error: %s", tree->data->error.message); + printf("\n---------------------------------\n"); + } + + else{ + printf("\n\n\nWarning: Incorrect parse tree node type: %d! \n\n\n", treeType); + } + +} + +/* The controlling function for PrintParseTree(VyParseTree*) */ +void PrintTree(VyParseTree* tree){ + if(tree != NULL){ + printf("\n"); + + /* Recursively print */ + PrintParseTree(tree); + + linesPrinted = 0; + }else{ + printf(" NULL TREE "); + } +} + +/* A utility function for parsing a whole file */ +VyParseTree* ParseFile(char* filename){ + if(filename == NULL){ + fprintf(stderr, "Null pointer as filename."); + return NULL; + } + + /* Perform lexing */ + LexFile(filename); + + if(GetNumTokens() < 1){ + printf("Empty file: %s\n", filename); + return NULL; + } + /* Parse the tokens */ + VyParseTree* list = MakeListTree(); + while(MoreTokensExist()) { + VyParseTree* tree = Parse(); + AddToList(list, tree); + } + + CleanLexer(); + + return list; + +} + +/* Free all parser resources and restart the parser to it's original state */ +void CleanParser(){ + linesPrinted = 0; +} + diff --git a/old/lisp-lang/Scope.c b/old/lisp-lang/Scope.c new file mode 100644 index 0000000..43578ff --- /dev/null +++ b/old/lisp-lang/Scope.c @@ -0,0 +1,207 @@ +#include "Vyion.h" + +/***** Dealing with the scope data structure *****/ + +/* Create an empty scope */ +Scope* CreateScope(){ + Scope* scp = malloc(sizeof(Scope)); + scp->vars = NULL; + scp->size = 0; + + return scp; +} + +/* Find a variable value */ +VyObject FindValue(Scope* scp, char* varName){ + /* If scope is null, return null */ + if(scp == NULL){ + return -1; + } + + /* Iterate through all the variables and compare their names */ + int i; + for(i = 0; i < scp->size; i++){ + /* Retrieve the variable and name at that index */ + VarBinding* var = scp->vars[i]; + char* currentVarName = GetVarName(var); + + /* Compare names */ + if(strcmp(varName, currentVarName) == 0){ + /* If they are the same, return the value */ + return GetVarValue(var); + } + } + + /* If the variable wasn't found, return < 0 */ + return -1; +} + +/* Add a variable to a scope */ +void AddVariable(Scope* scp, VarBinding* var){ + /* Allocate more memory for the new variable */ + int scopeSize = scp->size; + scp->vars = realloc(scp->vars, sizeof(VarBinding*) * (scopeSize + 1)); + + /* Add the variable and increment size */ + scp->vars[scopeSize] = var; + scp->size++; +} + +/* Set a variable value (independent of whether it already exists or not( */ +void SetVariable(Scope* scp, char* varName, VyObject val){ + /* If the variable doesn't exist yet, then add it, otherwise, update it */ + if(FindValue(scp, varName) < 0){ + AddVariable(scp, CreateVariable(varName, val)); + }else{ + /* Iterate through all the variables and compare their names */ + int i; + for(i = 0; i < scp->size; i++){ + /* Retrieve the variable and name at that index */ + VarBinding* var = scp->vars[i]; + char* currentVarName = GetVarName(var); + + /* Compare names */ + if(strcmp(varName, currentVarName) == 0){ + /* If they are the same, update the value and exit */ + var->val = val; + return; + } + } + } +} + +/* Print the contents of a scope to stdout */ +void PrintScopeContents(Scope* scp){ + /* Cycle through and print each variable name and it's type */ + int i; + printf("\n--- Scope Contents ---\n"); + if(scp->size == 0) { + printf("No values in scope."); + } + else{ + for(i = 0; i < scp->size; i++){ + printf("Variable: %s - %d\n", scp->vars[i]->name, ObjType(scp->vars[i]->val)); + } + } +} + +/* Merge two scopes (both old scopes are unchanged) */ +Scope* MergeScopes(Scope* one, Scope* two){ + Scope* new = CreateScope(); + + int i; + + /* Add the variables from scope one */ + if(one != NULL){ + for(i = 0; i < one->size; i++){ + AddVariable(new, one->vars[i]); + } + } + + /* And variables from scope two */ + if(two != NULL){ + for(i = 0; i < two->size; i++){ + AddVariable(new, two->vars[i]); + } + } + + return new; +} + +/* Destroy the scope and free used memory */ +void DeleteScope(Scope* scp){ + if(scp != NULL){ + /* Delete all the variables */ + int i; + for(i = 0; i < scp->size; i++){ + DeleteVariable(scp->vars[i]); + } + + /* Free the array of variables */ + free(scp->vars); + + /* Delete the scope itself */ + free(scp); + } + +} + +/***** Dealing with program scopes *****/ +Scope* globalScope; +Scope* currentFunctionScope; +Scope* localScope; + +ScopeStack* functionScopes; + +/* Inititialize all the scopes */ +void InitScopes(){ + /* Create a global scope */ + globalScope = CreateScope(); + + /* Before any functions are called, the global scope IS the local scope */ + localScope = globalScope; + + /* Create a scope stack for the functions */ + functionScopes = CreateScopeStack(); + +} + +/* Return the global scope */ +Scope* GetGlobalScope(){ + return globalScope; +} + +/* Manipulate the scope stack */ +void PushScope(Scope* scp){ + Push(functionScopes, scp); +} + +Scope* PopScope(){ + return Pop(functionScopes); +} + +/* Return the local scope */ +Scope* GetLocalScope(){ + return localScope; +} + +/* Return the current function scope */ +Scope* GetCurrentFunctionScope(){ + return currentFunctionScope; +} + +/* Set the current function scope */ +void SetCurrentFunctionScope(Scope* scp){ + currentFunctionScope = scp; +} + +/* Set the local scope */ +void SetLocalScope(Scope* scp){ + localScope = scp; +} + +/* Find a variable in the currently accessible scopes - that is, local, global, and closure scope */ +VyObject FindObjAllScopes(char* name){ + /* Try looking for the object in the local scope */ + VyObject obj = FindValue(GetLocalScope(), name); + if(obj >= 0){ + return obj; + } + + /* If not found, try function scope */ + obj = FindValue(GetCurrentFunctionScope(), name); + if(obj >= 0){ + return obj; + } + + /* If still not found, try global scope */ + obj = FindValue(GetGlobalScope(), name); + if(obj >= 0){ + return obj; + } + + /* If it wasn't found at all, return NULL */ + return -1; + +} + diff --git a/old/lisp-lang/ScopeStack.c b/old/lisp-lang/ScopeStack.c new file mode 100644 index 0000000..b66f0f2 --- /dev/null +++ b/old/lisp-lang/ScopeStack.c @@ -0,0 +1,49 @@ +#include "Vyion.h" + +void Push(ScopeStack* stack, Scope* new){ + /* Check if you need more memory, and if you do, allocate it */ + if(stack->size < stack->numElements + 1){ + stack->data = realloc(stack->data, sizeof(Scope*)*(stack->size + 1)); + stack->size++; + } + + /* Store the new scope and record it */ + stack->data[stack->numElements] = new; + stack->numElements++; +} + +/* Pop a scope off the stack */ +Scope* Pop(ScopeStack* stack){ + /* Make sure there is something to pop */ + if(stack->numElements <= 0){ + return NULL; + } + + /* Decrease the number of elements and return the popped element */ + stack->numElements--; + return stack->data[stack->numElements]; +} + +/* Create a scope stack */ +ScopeStack* CreateScopeStack(){ + ScopeStack* stack = malloc(sizeof(ScopeStack)); + stack->numElements = 0; + stack->size = 0; + stack->data = NULL; + + return stack; +} + +/* Delete the stack */ +void DeleteScopeStack(ScopeStack* stack){ + if(stack != NULL){ + /* Free all the Scope*s */ + int i; + for(i = 0; i < stack->size; i++){ + free(stack->data[i]); + } + + /* Free the stack itself */ + free(stack); + } +} diff --git a/old/lisp-lang/StringUtil.c b/old/lisp-lang/StringUtil.c new file mode 100644 index 0000000..45565dd --- /dev/null +++ b/old/lisp-lang/StringUtil.c @@ -0,0 +1,29 @@ +#include "Vyion.h" + +/* Whether a char is [0-9] */ +int isNumeric(char c){ + if(c >= '0' && c <= '9') return 1; + else return 0; +} + +/* Whehter a char is a space, tab, or newline */ +int isWhitespace(char c){ + if(c == ' ' || c == '\t' || c == '\n' || c == '\r') + return 1; + else + return 0; +} + +/* Concat strings */ +char* ConcatStrings(char* str1, char* str2){ + /* Create a new string with a needed length */ + int totalLength = strlen(str1) + strlen(str2); + char* new = calloc((totalLength+1),sizeof(char)); + + /* Concat the strings */ + strcat(new, str1); + strcat(new, str2); + return new; +} + + diff --git a/old/lisp-lang/Symbol.c b/old/lisp-lang/Symbol.c new file mode 100644 index 0000000..fa2b78b --- /dev/null +++ b/old/lisp-lang/Symbol.c @@ -0,0 +1,22 @@ +#include "Vyion.h" + +/* Create a new symbol with data */ +VySymbol** CreateSymbol(char* data){ + VySymbol** symb = CreateSymbObj(); + symb[0]->ident = data; + + return symb; +} + +/* Get the symbol string data */ +char* GetSymbolString(VySymbol** symb){ + return symb[0]->ident; +} + +/* Print the symbol as it would appear in a parse tree */ +void PrintSymbol(VySymbol** symb){ + char* string = GetSymbolString(symb); + + /* Quote the identifier */ + printf("%s", string); +} diff --git a/old/lisp-lang/Token.c b/old/lisp-lang/Token.c new file mode 100644 index 0000000..61cb1e4 --- /dev/null +++ b/old/lisp-lang/Token.c @@ -0,0 +1,91 @@ +#include "Vyion.h" + +/* Create a token with no associated data */ +VyToken* EmptyToken(int type){ + VyToken* tok = malloc(sizeof(VyToken)); + tok->type = type; + tok->data = NULL; + tok->pos = NULL; + return tok; +} + +/* Create a token with associated string data */ +VyToken* DataToken(int type, char* data){ + VyToken* tok = EmptyToken(type); + tok->data = data; + return tok; +} + +/* Set the position of a token in the program */ +void SetTokenPosition(VyToken* tok, int line, int character, int indent){ + if(tok->pos == NULL){ + tok->pos = malloc(sizeof(Position)); + } + tok->pos->line = line; + tok->pos->character = character; + tok->pos->indent = indent; +} + +/* Print a position */ +void PrintPosition(Position* pos){ + /* Increment the line and character so they start at 1 and not 0 */ + if(pos != NULL) + printf("line %d, character %d", pos->line + 1, pos->character + 1); +} + +/* Whether the token is an empty token (i.e. has no associated data) */ +int IsEmptyToken(VyToken* tok){ + if(tok->data == NULL){ + return 1; + } + else{ + return 0; + } +} + +/* Find the location of the token */ +int GetLine(VyToken* tok){ + if(tok->pos == NULL){ + return -1; + }else{ + return tok->pos->line; + } +} +int GetCharacter(VyToken* tok){ + if(tok->pos == NULL){ + return -1; + }else{ + return tok->pos->character; + } +} +int GetIndent(VyToken* tok){ + if(tok->pos == NULL){ + return -1; + }else{ + return tok->pos->indent; + } +} + +/* Whether the position of the token has been marked */ +int HasKnownPosition(VyToken* tok){ + if(tok->pos == NULL){ + return 0; + }else{ + return 1; + } +} + +/* Free the used memory */ +void DeleteToken(VyToken* tok){ + /* If needed, free the string data as well */ + if(!IsEmptyToken(tok)){ + free(tok->data); + } + + /* Free the position data */ + if(tok->pos != NULL){ + free(tok->pos); + } + + free(tok); +} diff --git a/old/lisp-lang/Variable.c b/old/lisp-lang/Variable.c new file mode 100644 index 0000000..b9438a5 --- /dev/null +++ b/old/lisp-lang/Variable.c @@ -0,0 +1,28 @@ +#include "Vyion.h" + +/* Create a variable */ +VarBinding* CreateVariable(char* name, VyObject val){ + VarBinding* var = malloc(sizeof(VarBinding)); + + /* Clone the name string so that deleting the variable has no side effects */ + var->name = strdup(name); + var->val = val; + + return var; +} + +/* Delete a variable (doesn't delete the value) */ +void DeleteVariable(VarBinding* var){ + free(var->name); + free(var); +} + +/* Get the variable name */ +char* GetVarName(VarBinding* var){ + return var->name; +} + +/* Get the variable value */ +VyObject GetVarValue(VarBinding* var){ + return var->val; +} diff --git a/old/lisp-lang/VyionLib.v b/old/lisp-lang/VyionLib.v new file mode 100644 index 0000000..d23ceb8 --- /dev/null +++ b/old/lisp-lang/VyionLib.v @@ -0,0 +1,58 @@ +|{ Set up macros that create macros and functions without using mambda and lambda }| +(set macro + (mambda (name arguments &(body)) + [set $name (mambda $arguments $@body)])) + +(macro function (name arguments &(body)) + [set $name (lambda $arguments $@body)]) + +|{ Define additional list functions which aren't built-in }| +(function concat (l1 l2) [$@l1 $@l2]) +(function list (&(body)) body) +(function append (list &(body)) [$@list $@body]) +(function front (list &(body)) [$@body $@list]) + +|{ Define a temporary infix system, which, although simple, can still be useful }| +(macro infix (expr) [$(nth expr 1) $(nth expr 0) $(nth expr 2)]) + +|{ Increment and decrement macros }| +(macro inc(n) [set $n {$n + 1}]) +(macro dec(n) [set $n {$n - 1}]) + +|{ Implement the looping macros while and for }| +(macro while(condition &(body)) + (set symb (unique)) + [tagbody ($symb (if $condition ($@body (go $symb))))]) + +(macro for-each(var-name lst &(body)) + (set i (unique)) + (set eval-list (unique)) + (set size (unique)) + + [ + (set $eval-list $lst) + (set $size (len $eval-list)) + (set $i 0) + (while {$i < $size} + (set $var-name (nth $eval-list $i)) + $@body + (inc $i) + ) + ] +) + + +|{ Define the short circuiting boolean operators }| +(macro or(first second) + [if $first + #then 'true! + #else $second]) + +(macro and(first second) + [if (not $first) + #then 'false! + #else $second]) + +|{ Macro-run allows code to be run as a macro but not to return a value (macro-run return values should NEVER be used for anything) }| +(macro macro-run (name args &(body)) + [macro $name $args $@body '[]]) diff --git a/old/lisp-lang/input.v b/old/lisp-lang/input.v new file mode 100644 index 0000000..7b29c3c --- /dev/null +++ b/old/lisp-lang/input.v @@ -0,0 +1,25 @@ +(include 'VyionLib.v) + +; All currently defined infix operators (start with only numerical operators) +(macro-run init-infix () + (global infix-ops [= != < > <= >= ** * / + -])) + +; Create a macro to add a new infix operator +(macro-run def-operator(symbol ~?(before false!)) + ; If the order isn't specified, just add it last + (if (eq before false!) (set infix-ops (append infix-ops symbol)) + + ; Otherwise, add it before the specified element + ((set elem (head infix-ops)) + ; Find which element you're adding it before + (set index 0) + (while (not (eq elem before)) + (inc index) + (set elem (nth infix-ops index))) + ; Insert it where needed + (set infix-ops (insert infix-ops symbol index))))) + +(macro infix (&(body)) + (for + + diff --git a/old/lisp-lang/makefile b/old/lisp-lang/makefile new file mode 100644 index 0000000..5e5ab56 --- /dev/null +++ b/old/lisp-lang/makefile @@ -0,0 +1,24 @@ + +# The compiler used and the command line arguments to it +COMPILER = gcc +ARGS = -Wall -I Include/ -g +EXECUTABLE = vyion +CMDLINK = ${COMPILER} -lm -o ${EXECUTABLE} ${ARGS} # Link the .o files into an executable +CMD = ${COMPILER} -c ${ARGS} # Don't link, just compile to .o + +ALLFILES = Arithmetic.o Boolean.o CharList.o Eval.o Function.o Lexer.o List.o Number.o Object.o Parser.o ParseTree.o Scope.o ScopeStack.o StringUtil.o Symbol.o Token.o Variable.o Macro.o Error.o FlowControl.o Mem.o + +# Top level rule, compile whole program +all: ${EXECUTABLE} + +# Invoke the compiler with linking enabled +${EXECUTABLE}: ${ALLFILES} + ${CMDLINK} ${ALLFILES} + +# Compile all C files into object code +%.o: %.c + ${CMD} $< + +# Clean out the project and delete all .o files +clean: + rm -rf *.o ${EXECUTABLE} diff --git a/old/lisp-lang/vyion.vim b/old/lisp-lang/vyion.vim new file mode 100644 index 0000000..19f72d5 --- /dev/null +++ b/old/lisp-lang/vyion.vim @@ -0,0 +1,4 @@ +syn keyword vyionVars set global +syn keyword vyionFuncs lambda mambda macro function +syn keyword vyionFlow if tagbody go while for-each for +syn keyword vyionBool true! false! and or not