initial commit

This commit is contained in:
Matthieu Bessat 2022-04-29 12:30:44 +02:00
parent cdc6a08f41
commit 17c7c247af
25 changed files with 1557 additions and 223 deletions

2
.gitignore vendored
View file

@ -1 +1,3 @@
./main
./test
main

151
README.md
View file

@ -1,22 +1,48 @@
# Simple BASIC language implementation
# Langatator
A very basic interpreted programming language.
## Background
The goal of this project is to create a simple implementation of a BASIC-like language just to learn a few things along the way and practice my C programming skills.
The goal of this project is to create a simple implementation of a BASIC-like language.
No need to do complex thing, just to create a simple interpreted language that can be used to do some arithmetics
and create for ex a number guessing game.
and create for example a number guessing game.
## Technology
I didn't really study how others languages works beforehand, I'm just guessing how I'm implementing things so that I can make mistakes to learn from.
We will create our own regex engine
## Progress
## Syntax
- 2022-04-29 : Implementation of a basic evaluator engine to evaluate arithmetic expressions and call functions
One instruction set per line
ToDo List:
Instruction sets avalaibles:
- [ ] pow operator
- [ ] binary operators
- [ ] implement basic math functions
- [ ] implement random_int(min, max)
- [ ] implement print_number(message)
- [ ] implement input_number()
- [ ] base of the CLI
- [ ] evaluate expression from stdin
- [ ] read a file
- [ ] allow to set variables
- [ ] read line comments
- [ ] conditionals
- [ ] add unit tests
- [ ] function call stack
### Commentary
## The language
can only use single line comments with `#`
You would be able to use the lang directly via CLI, via a REPL or by writing in a file (file ext `.ltor`).
To begin with and order to simplify things we would only have numbers as datatypes (so an abstraction with int or float under the hood).
One instruction set per line.
### Comments
Can only use single line comments with `#`
```
# this is a comment
@ -27,8 +53,19 @@ can only use single line comments with `#`
can only operate on integer
function calls: func(arg_a, arg_b)
operators: +, *, /
booleans operators: not, and, or,
operators: +, *, /, ^
### Set a variable
```
set {VARNAME} to {EXPRESSION}
```
### Eval an expression without using the result
```
eval print_number(42)
```
### function definition
@ -39,12 +76,6 @@ begin
end
```
### Set a variable
```
set {VARNAME} to {EXPRESSION}
```
### Conditional structure
```
@ -75,8 +106,86 @@ end
### std functions
```
put_stdout()
take_stdin()
int_of_string()
abs(nb)
sqrt,sin,cos,exp,ln,log etc.
print_number(data)
input_number()
random_int(min, max)
```
# Evaluator (draft)
EDIT: that's not actually quite how I implemented the evaluator.
Map
componentList:
bytes steam
first byte is a uint8 representing the type of the component
then depending on the type of the component there is 0 or N bytes
components types:
- name: integer
size: 4 bytes (for int)
- name: open parenthesis
size: 0 bytes
- name: close parenthesis
size: 0 bytes
- name: float
size: 32 bytes (IEEE 754)
- name: operator
size: 1 byte (255 operators are possible)
- name: function designator
desc: id of a function
size: 2 bytes (65536 functions are possibles)
Example map of `9+(5*(8+6))`
lexed stream
-TYPE:NUMERAL
VALUE:9
-TYPE:OPERATOR
VALUE:PLUS
-TYPE:OPEN_PARENTHESIS
VALUE:NULL
-TYPE:NUMERAL
VALUE:5
-TYPE:OPERATOR
VALUE:TIMES
-TYPE:OPEN_PARENTHESIS
VALUE:NULL
-TYPE:NUMERAL
VALUE:8
-TYPE:OPERATOR
VALUE:PLUS
-TYPE:NUMERAL
VALUE:6
-TYPE:CLOSE_P
VALUE:NULL
-TYPE:CLOSE_P
VALUE:NULL
scan the whole lexed stream
So there will be a kind of time line with reference, a list of reference
in the begining we allocate two lists, one for the component type, one for the component values
## Dynamics lists
we allocate N bytes (uint_8 list[2048])
methods:
list_length()
list_assign_int(int index, int value)
list_assign_float(int index, float value)
list_assign_uint_8(int index, uint_8 value)
list_get_int(int index)
etc...

View file

@ -1 +0,0 @@
PRINT 1

View file

@ -1 +0,0 @@
PRINT (1+2)

View file

@ -1,5 +0,0 @@
LET A BE 0
WHILE NOT A DO
PRINT A
LET A BE A+1
ENDWHILE

View file

@ -1 +0,0 @@
PRINT "Hello World"

View file

@ -0,0 +1,6 @@
# script to add two numbers
set a to input_number()
set b to input_number()
set res to a+b
eval print_int(c)

2
examples/print_42.ltor Normal file
View file

@ -0,0 +1,2 @@
# just print 42
eval print_number(42)

418
src/evaluator.c Normal file
View file

@ -0,0 +1,418 @@
#include "./evaluator.h"
#include <stdio.h>
#include <string.h>
#include "./types.h"
#include "./list.h"
#include "./operate.h"
#include "./number_parsing.h"
#include "./funcs.h"
/**
This sub script will look for pattern like Number Operator Number
and evaluate that
*/
int evaluator_reduce_operator_pattern(struct List* evalList) {
int patternPos = -1;
for (int i = 0; i < evalList->num_elements; i++) {
if (
is_type_number(list_get_type(evalList, i)) &&
list_get_type(evalList, i+1) == TYPE_OPERATOR &&
is_type_number(list_get_type(evalList, i+2))
) {
patternPos = i;
break;
}
}
if (patternPos == -1) {
// we did not find anything to reduce we return negative
return -1;
}
// we found a positive pattern, we gonna reduce
int typeA = list_get_type(evalList, patternPos);
int typeB = list_get_type(evalList, patternPos+2);
// que ça soit un float ou un int, ça tient en 32 bit donc dans un int :p
int a;
char operator;
int b;
list_get(evalList, patternPos, &a);
list_get(evalList, patternPos+1, &operator); // id de l'operateur
list_get(evalList, patternPos+2, &b);
int res = 0;
unsigned char typeRes = 0;
int operateStatus = operate(operator, typeA, a, typeB, b, &typeRes, &res);
if (operateStatus != 0) {
// the pattern that matched, did not worked as expected
// this is a failure
printf("ERR Evaluator: cannot operate \n");
return 400;
}
if (typeRes == TYPE_INT) {
list_set(evalList, patternPos, TYPE_INT, &res);
}
if (typeRes == TYPE_FLOAT) {
// FIXME: invalid type set, we need to flag for float
list_set(evalList, patternPos, TYPE_FLOAT, &res);
}
list_delete(evalList, patternPos+1);
list_delete(evalList, patternPos+1);
//printf("END OF THE FIRST OPERATION \n");
//list_print(&evalList);
// so we reduced an expression, return 0
return 0;
}
/**
This sub script will look for pattern like ({Number})
and remove parenthesis
*/
int evaluator_reduce_parenthesis_pattern(struct List* evalList) {
int patternPos = -1;
for (int i = 0; i < evalList->num_elements; i++) {
if (
list_get_type(evalList, i) == TYPE_OPEN_PARENTHESIS &&
is_type_number(list_get_type(evalList, i+1)) &&
list_get_type(evalList, i+2) == TYPE_CLOSE_PARENTHESIS
) {
patternPos = i;
break;
}
}
if (patternPos == -1) {
// we did not find anything to reduce we return -1
return -1;
}
// we found a positive pattern position, we gonna reduce that
// so we just have to remove the two parenthesis
list_delete(evalList, patternPos);
list_delete(evalList, patternPos+1);
// so we reduced an expression, return 0
return 0;
}
/*
This func will look for a function call pattern that is ready to be evaluated
First we will look for this kind of pattern
FUNC_NAME
OPEN_PARENTHESIS
LITERAL VALUE (for now just NUMBER_TYPE)
but no CLOSE_PARENTHESIS
if we found this pattern, we will then try to find the potential remaining arguments
like check if we have COMMA ARGUMENT
if we don't find a comma next, we try to find a closing parenthesis
if we don't find that, we throw an error
*/
int evaluator_reduce_function_call(struct List* evalList) {
int patternPos = -1;
short argsLen = 0;
for (int i = 0; i < evalList->num_elements; i++) {
if (
(list_get_type(evalList, i) == TYPE_FUNC_NAME &&
list_get_type(evalList, i+1) == TYPE_OPEN_PARENTHESIS &&
is_type_number(list_get_type(evalList, i+2)))
) {
// mode: we have at least one argument
patternPos = i;
argsLen = 1;
break;
}
if (
list_get_type(evalList, i) == TYPE_FUNC_NAME &&
list_get_type(evalList, i+1) == TYPE_OPEN_PARENTHESIS &&
list_get_type(evalList, i+2) == TYPE_CLOSE_PARENTHESIS
) {
// special mode: functions call with no arguments
patternPos = i;
argsLen = 0;
break;
}
}
if (patternPos == -1) {
// we did not find anything to reduce we return -1
return -1;
}
short funcID;
// fetch the function ID
list_get(evalList, patternPos, &funcID);
int pos = patternPos+2;
if (argsLen > 0) {
// now we know we have a start of a function
// we gonna start to look if there is others arguments
// two case: either we have another arguments or we have a closing parenthesis
pos = patternPos+3;
while (1) {
if (argsLen > 16) {
printf("ERR Evaluator: too many arguments passed to func \n");
return 100;
}
if (
list_get_type(evalList, pos) == TYPE_COMMA &&
is_type_number(list_get_type(evalList, pos+1))
) {
// another argument
pos += 2;
argsLen++;
continue;
}
if (
(
list_get_type(evalList, pos) == TYPE_COMMA &&
list_get_type(evalList, pos+1) == TYPE_CLOSE_PARENTHESIS
) || (list_get_type(evalList, pos) == TYPE_CLOSE_PARENTHESIS)
) {
// we close the function call
break;
}
printf("ERR Evaluator: cannot reduce function call \n");
return 100;
}
}
// now pos is the index of the last component for this func call
unsigned char argsTypes[argsLen];
int argsValues[argsLen];
// populate the arguments types and values
for (int i = 0; i < argsLen; i++) {
argsTypes[i] = list_get_type(evalList, patternPos+2+(i*2));
list_get(evalList, patternPos+2+(i*2), &argsValues[i]);
}
// now call the funcs
int resVal = 0;
unsigned char resType = 0;
int stat = execute_func(funcID, argsLen, argsTypes, argsValues, &resVal, &resType);
if (stat != 0) {
// error when executing the func
return 1;
}
// now we can delete in the list from pos+1 patternPos to pos
// just delete N-1 times where N is the number of components in the func call
//printf("start: %d, end: %d \n", patternPos, pos);
for (int j = 0; j < (pos-patternPos); j++) {
list_delete(evalList, patternPos);
}
list_set(evalList, patternPos, resType, &resVal);
return 0;
}
/*
Evaluate a simple string expression return 0 if no fails occurs
And return smth different than 0 if there is an error with the lexing/parsing/evaluation
Arguments:
- Input String: char pointer (the source of the evaluation)
- Result: int pointer (where the result of the evaluation will be written)
*/
int evaluate(char* inputStr, int* resultPtr, int* typePtr) {
int i = 0;
int _len = strlen(inputStr);
// we want first to parse the expression and create a stack
// for 4*81 : ["4", "*", "81"]
// for -4*(5+42) : ["-4", "*", "(", "5", "+", "42", ")"]
// as a matter of fact, this is a partition
// so we can treat that as a list of tuple (start,finish)
int partitionStartPos[_len];
int partitionStopPos[_len];
int partitionPtr = 0;
int lastStartPos = 0;
while (inputStr[i] != 0) {
if (
is_operator(inputStr[i]) ||
inputStr[i] == '(' ||
inputStr[i] == ')' ||
inputStr[i] == ','
) {
if (lastStartPos != i) {
partitionStartPos[partitionPtr] = lastStartPos;
partitionStopPos[partitionPtr] = i;
partitionPtr++;
}
partitionStartPos[partitionPtr] = i;
partitionStopPos[partitionPtr] = i+1;
partitionPtr++;
lastStartPos = i+1;
i++;
continue;
}
i++;
}
if (lastStartPos != i) {
partitionStartPos[partitionPtr] = lastStartPos;
partitionStopPos[partitionPtr] = i;
partitionPtr++;
}
// display the partition
printf("partitionPtr: %d \n", partitionPtr);
for (int j = 0; j < partitionPtr; j++) {
printf("start %d ", partitionStartPos[j]);
printf("stop %d ", partitionStopPos[j]);
int len = partitionStopPos[j] - partitionStartPos[j];
char buff[_len];
for (int z = 0; z < len; z++) {
if (z < len) {
buff[z] = inputStr[partitionStartPos[j]+z];
}
}
buff[len] = 0;
printf("content %s \n", buff);
}
// once we've lexed our expression, we want to analyse if it's righly parenthesized
int parenthesisCount = 0;
for (int j = 0; j < partitionPtr; j++) {
int len = partitionStopPos[j] - partitionStartPos[j];
char buff[_len];
for (int z = 0; z < len; z++) {
if (z < len) {
buff[z] = inputStr[partitionStartPos[j]+z];
}
}
buff[len] = 0;
if (len == 1 && buff[0] == '(') {
parenthesisCount++;
}
if (len == 1 && buff[0] == ')') {
parenthesisCount--;
}
if (parenthesisCount < 0) {
printf("ERR Evaluator: bad parenthesizing \n");
return 100;
}
}
if (parenthesisCount > 0) {
// there is an open parenthesis, so it's an error
printf("ERR Evaluator: invalid parenthesis stack \n");
return 100;
}
struct List evalList;
printf("\n - constructing list \n");
// initializing the evaluation list
for (int j = 0; j < partitionPtr; j++) {
int len = partitionStopPos[j] - partitionStartPos[j];
char buff[_len+1];
// fill the buffer with the component string
for (int z = 0; z < len; z++) {
buff[z] = inputStr[partitionStartPos[j]+z];
}
// TODO: SPLIT INTO A FUNCTION "identify_token(char* str)"
buff[len] = 0;
char dumbValue = (char) 0;
if (len == 1 && buff[0] == '(') {
list_set(&evalList, evalList.num_elements, TYPE_OPEN_PARENTHESIS, &dumbValue);
continue;
}
if (len == 1 && buff[0] == ')') {
list_set(&evalList, evalList.num_elements, TYPE_CLOSE_PARENTHESIS, &dumbValue);
continue;
}
if (len == 1 && buff[0] == ',') {
list_set(&evalList, evalList.num_elements, TYPE_COMMA, &dumbValue);
continue;
}
if (len == 1 && is_operator(buff[0])) {
char opValue = buff[0];
list_set(&evalList, evalList.num_elements, TYPE_OPERATOR, &opValue);
continue;
}
int res = 0;
int st = parse_int(buff, &res);
if (st == 0) {
// parse int success
//printf("Content aftr parsing %d %d \n", st, res);
list_set(&evalList, evalList.num_elements, TYPE_INT, &res);
}
if (st != 0) {
// failed to parsed as an int, try to parse as a float
st = parse_float(buff, (float*) &res);
if (st == 0) {
// parse float success
list_set(&evalList, evalList.num_elements, TYPE_FLOAT, &res);
}
}
if (st != 0) {
// not a float, check if this is a common function name
short funcID = identify_func_name(buff);
if (funcID == -1) {
// did not find the func name
printf("ERR Evaluator: could not identify token \"%s\" \n", buff);
return 200;
}
if (funcID >= 0) {
list_set(&evalList, evalList.num_elements, TYPE_FUNC_NAME, &funcID);
}
}
}
// check the content of this thing
list_print(&evalList);
printf("Now going to actually evaluate \n");
while (evalList.num_elements > 1) {
list_print(&evalList);
// we are going to look for pattern
// - 0. OPENP NUM CLOSEP
// - 1. NUM OP NUM
int reduceFuncOpStat = evaluator_reduce_function_call(&evalList);
int reduceOperatorOpStat = evaluator_reduce_operator_pattern(&evalList);
int reduceParenthesisOpStat = evaluator_reduce_parenthesis_pattern(&evalList);
if (reduceFuncOpStat > 0) {
printf("ERR Evaluator: function reducing failed, dumping evalList: \n");
list_print(&evalList);
return reduceOperatorOpStat;
}
if (reduceOperatorOpStat > 0) {
printf("ERR Evaluator: operator reducing failed, dumping evalList: \n");
list_print(&evalList);
return reduceOperatorOpStat;
}
if (reduceFuncOpStat == -1 && reduceOperatorOpStat == -1 && reduceParenthesisOpStat == -1) {
// all scans failed to find things to reduce
// this is actually a failure because we can't do anything to get down to 1 element in the eval list
printf("ERR Evaluator: could not reduce more, dumping evalList: \n");
list_print(&evalList);
return 400;
}
}
int typeRes = list_get_type(&evalList, 0);
*typePtr = typeRes;
list_get(&evalList, 0, resultPtr);
return 0;
}

6
src/evaluator.h Normal file
View file

@ -0,0 +1,6 @@
#ifndef EVALUATOR_H_
#define EVALUATOR_H_
int evaluate(char* inputStr, int* resultPtr, int* typePtr);
#endif

141
src/funcs.c Normal file
View file

@ -0,0 +1,141 @@
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "./types.h"
#include "./repr_utils.h"
int abs_implementation(int* res, unsigned char* resType, unsigned char* types, int* args)
{
if (types[0] == TYPE_INT) {
if (args[0] < 0) {
*res = -args[0];
return 0;
}
*res = args[0];
*resType = TYPE_INT;
return 0;
}
if (types[0] == TYPE_FLOAT) {
float val = get_float_from_int_rep(args[0]);
if (val < 0) {
val = -val;
}
*res = get_int_rep_from_float(val);
*resType = TYPE_FLOAT;
return 0;
}
return 1;
}
int sqrt_implementation(int* res, unsigned char* resType, unsigned char* types, int* args)
{
float x = 0;
if (types[0] == TYPE_INT) {
// convert to float
x = (float) args[0];
}
if (types[0] == TYPE_FLOAT) {
x = get_float_from_int_rep(args[0]);
}
*res = get_int_rep_from_float(sqrt(x));
*resType = TYPE_FLOAT;
return 0;
}
int max_implementation(int* res, unsigned char* resType, unsigned char* types, int* args)
{
short maxIndex = 0;
float a = 0;
float b = 0;
if (types[0] == TYPE_FLOAT) {
a = get_float_from_int_rep(args[0]);
}
if (types[1] == TYPE_FLOAT) {
b = get_float_from_int_rep(args[1]);
}
if (types[0] == TYPE_INT) {
a = (float) args[0];
}
if (types[1] == TYPE_INT) {
b = (float) args[1];
}
if (b > a) {
maxIndex = 1;
}
*res = args[maxIndex];
*resType = types[maxIndex];
return 0;
}
int get_pi_implementation(int* res, unsigned char* resType, unsigned char* types, int* args)
{
float val = 3.1415926535;
*res = *(int *)(&val);
*resType = TYPE_FLOAT;
return 0;
}
struct FuncIntro {
char name[20];
int (*implementation)(int*, unsigned char*, unsigned char*, int*);
short nbArgs;
};
// void* are actually long!
struct FuncIntro intros[] = {
{"ABS", &abs_implementation, 1},
{"SQRT", &sqrt_implementation, 1},
{"MAX", &max_implementation, 2},
{"GET_PI", &get_pi_implementation, 0},
{"", 0, 0}
};
static int nbOfFuncs = sizeof(intros)/sizeof(struct FuncIntro);
/**
Will return the function id
*/
short identify_func_name(char* candidate)
{
for (int i = 0; i < nbOfFuncs; i++) {
if (strcmp(intros[i].name, candidate) == 0) {
return i;
}
}
return -1;
}
int execute_func(short funcID, short argsLen, unsigned char* argsTypes, int* argsValues, int* resPtr, unsigned char* resTypePtr)
{
if (funcID >= nbOfFuncs) {
printf("ERR: Invalid func with index: %d \n", funcID);
return 1;
}
int (*impl)(int*, unsigned char*, unsigned char*, int*) = intros[funcID].implementation;
if (impl == 0) {
printf("ERR: No implementation for func with index: %d \n", funcID);
return 1;
}
char* name = intros[funcID].name;
printf("Executing func '%s' \n", name);
if (argsLen < intros[funcID].nbArgs) {
printf("ERR: Too few arguments for func call '%s' \n", name);
return 1;
}
if (argsLen > intros[funcID].nbArgs) {
printf("ERR: Too many arguments for func call '%s' \n", name);
return 1;
}
// call the function implementation
// first cast the function ptr
impl(resPtr, resTypePtr, argsTypes, argsValues);
printf("Got %d \n", *resPtr);
return 0;
}

49
src/funcs.h Normal file
View file

@ -0,0 +1,49 @@
#ifndef FUNCS_H_
#define FUNCS_H_
// // Maths functions
// #define FUNC_ABS 5
// #define FUNC_SQRT 10
// #define FUNC_EXP 11
// // natural logarithm
// #define FUNC_LN 12
// // decimal log
// #define FUNC_LOG 13
// #define FUNC_POW 14
// #define FUNC_SIN 64
// #define FUNC_COS 65
// #define FUNC_TAN 66
// #define FUNC_ACOS 72
// #define FUNC_ASIN 73
// #define FUNC_ATAN 74
// // x,y as arguments
// #define FUNC_ATAN2 75
// #define FUNC_COSH 91
// #define FUNC_SINH 92
// #define FUNC_TANH 93
// // factorial
// #define FUNC_FACT 101
// // choose (n,k) (binomial)
// #define FUNC_CHOOSE 102
// // Greatest common divisor
// #define GCD 150
// // Least common multiple
// #define LCM 151
// // Input/Output Functions
// #define FUNC_PRINT 201
// #define FUNC_INPUT 202
// will return the function id from a string or 0 if not found
short identify_func_name(char* candidate);
int execute_func(short funcID, short argsLen, unsigned char* argsTypes, int* argsValues, int* resPtr, unsigned char* resTypePtr);
#endif

251
src/list.c Normal file
View file

@ -0,0 +1,251 @@
#include "./types.h"
#include "./list.h"
#include <stdio.h>
/*
struct List {
int num_elements;
int bytes_used;
int data_ptr; // this is the pointer where there is freespace
int ptrArray[LIST_SIZE];
unsigned char typeArray[LIST_SIZE];
unsigned char data[LIST_SIZE];
};
*/
// get size in byte of a particular type
int get_size_of_type(unsigned char type)
{
int t = (int) type;
// underlying type is int (4 bytes)
if (t == TYPE_INT || t == TYPE_FLOAT) {
return 4;
}
// underlying type is short (1 byte)
if (t == TYPE_FUNC_NAME) {
return 2;
}
// underlying type is char (1 byte)
if (t == TYPE_OPERATOR) {
return 1;
}
if (
t == TYPE_OPEN_PARENTHESIS ||
t == TYPE_CLOSE_PARENTHESIS ||
t == TYPE_COMMA
) {
return 0;
}
return -1;
}
int is_type_number(unsigned char type)
{
return type == TYPE_INT || type == TYPE_FLOAT;
}
unsigned char list_get_type(struct List* list, int index) {
if (index >= list->num_elements) {
return 0;
}
return list->typeArray[index];
}
int list_get(struct List* list, int index, void* resultPtr)
{
if (index >= list->num_elements) {
// this element does not exist for now
return 1;
}
unsigned char type = list->typeArray[index];
if (type == 0) {
// we skip this element
return 1;
}
int size = get_size_of_type(type);
int addr = list->ptrArray[index];
int baseVal = 0;
unsigned char* valuePtr = (unsigned char*) &baseVal;
for (int i = 0; i < size; i++) {
valuePtr[i] = list->data[addr+i];
}
// convert to underlying C types
if (type == TYPE_INT) {
*((int*) resultPtr) = *((int*) valuePtr);
}
if (type == TYPE_FLOAT) {
*((float*) resultPtr) = *((float*) valuePtr);
}
if (type == TYPE_OPERATOR) {
*((char*) resultPtr) = *((char*) valuePtr);
}
if (type == TYPE_FUNC_NAME) {
*((short*) resultPtr) = *((short*) valuePtr);
}
return 0;
}
int list_get_int(struct List* list, int index, int* valuePtr)
{
int type = list_get_type(list, index);
if (!type) {
return 1;
}
if (type != TYPE_INT) {
// invalid type
return 2;
}
return list_get(list, index, (void*) valuePtr);
}
int list_get_float(struct List* list, int index, float* valuePtr)
{
int type = list_get_type(list, index);
if (!type) {
return 1;
}
if (type != TYPE_FLOAT) {
// invalid type
return 2;
}
return list_get(list, index, (void*) valuePtr);
}
int list_set(struct List* list, int index, unsigned char type, void* valuePtr)
{
if (index >= list->num_elements) {
// this is a new element
if (list->bytes_used == LIST_SIZE) {
// can't add, we are already complete
return 1;
}
list->num_elements++;
}
// for now, we just add at the end of the data array
int size = get_size_of_type(type);
if (size < 0) {
// the type is invalid
return 2;
}
unsigned char* data = (unsigned char*) valuePtr;
int start = list->data_ptr;
for (int i = 0; i < size; i++) {
//list->data[start+i] = value & (255<<i);
list->data[start+i] = data[i];
}
list->ptrArray[index] = start;
list->typeArray[index] = type;
list->data_ptr += size;
return 0;
}
int list_set_int(struct List* list, int index, int value)
{
return list_set(list, index, TYPE_INT, &value);
}
int list_set_float(struct List* list, int index, float value)
{
return list_set(list, index, TYPE_FLOAT, &value);
}
int list_set_char(struct List* list, int index, char value)
{
return list_set(list, index, TYPE_OPERATOR, &value);
}
void arr_delete_by_gravity(void* src, int elementLength, int length, int index)
{
unsigned char* srcPtr = (unsigned char*) src;
for (int i = index; i < length; i++) {
if (i == length-1) {
for (int j = 0; j < elementLength; j++) {
srcPtr[i*elementLength+j] = 0;
}
continue;
}
for (int j = 0; j < elementLength; j++) {
srcPtr[i*elementLength+j] = srcPtr[((i+1)*elementLength)+j];
}
}
}
int list_delete(struct List* list, int index)
{
if (index >= list->num_elements) {
// error: index out of range
return 1;
}
arr_delete_by_gravity(&list->typeArray, 1, list->num_elements, index);
arr_delete_by_gravity(&list->ptrArray, 4, list->num_elements, index);
list->num_elements--;
return 0;
}
int list_append_int(struct List* list, int value)
{
return list_set_int(list, list->num_elements, value);
}
int list_append_char(struct List* list, char value)
{
return list_set_char(list, list->num_elements, value);
}
void list_print(struct List* list)
{
printf("=== LIST REPORT === \n");
printf("num of elements: %d \n", list->num_elements);
for (int i = 0; i < list->num_elements; i++) {
printf("- i: %d, ", i);
int type = list_get_type(list, i);
if (type == TYPE_INT) {
int d = 0;
list_get(list, i, &d);
printf("type: INT, val: %d", d);
}
if (type == TYPE_FLOAT) {
float d = 0;
list_get(list, i, &d);
printf("type: FLOAT, val: %f", d);
}
if (type == TYPE_OPERATOR) {
char d = 0;
list_get(list, i, &d);
printf("type: OPERATOR, val: %d '%c'", d, d);
}
if (type == TYPE_FUNC_NAME) {
short d = 0;
list_get(list, i, &d);
printf("type: FUNC_NAME, val: %d", d);
}
if (type == TYPE_OPEN_PARENTHESIS) {
printf("type: OPEN_PARENTHESIS");
}
if (type == TYPE_COMMA) {
printf("type: COMMA");
}
if (type == TYPE_CLOSE_PARENTHESIS) {
printf("type: CLOSE_PARENTHESIS");
}
printf("\n");
}
printf("=== END === \n");
}

71
src/list.h Normal file
View file

@ -0,0 +1,71 @@
#ifndef LIST_H_
#define LIST_H_
/*
Dynamic lists
We want a data structure which is fast to read from
But not necessarily fast to write to
So we need to have a map of the data structure, so we know where to look
Since each list element can be of different size, we need to reference the address of each element
So the first thing we need is two arrays of int that we serve us as metadata arrays:
- one for the types of the elements (call it the typeArray)
- one for the addresses of the elements (call it the ptrArray)
these two arrays must remain in sync
Then we have the third array which we will call the dataArray in which we actually store the data
When we neeed to read an element from it's index, it's simple:
1. first we get the type of the element by it's index, if it's null we know that this element doesn't exists
2. second we get the start address of the element and we retrieve the bytes to reconstruct the right data type
On the other side, when we need to write an element it's a little bit more complicated:
- We know which data type we want to add, so we know what size we are looking for in the main
- We will swipe through all the data array in a desperate search for a place where we can fit our data. If we reached the end without find any place, we can either give up or launch a more complicated to move some bytes around (reorganization) in a process called defragmentation.
- If we found a place, we add the pointer to the start of that region in memory in the ptrArray and set the typeArray at the right index
- But we will have to move all the elements in the ptrArray and typeArray by gravity
- We update num_elements and bytes_used in the struct
- a simpler startegry to add data, is to jump directly at the end where we get clean space and put our data here, at the expense of loosing memory with garbage in the memory.
The minimum size of an element is 8 bits - 1 byte (for unsigned char)
So if the size of the list is N bytes, we can have a maximum of N single elements
And the maximum size of an element is 32 bytes - 4 bytes (for normal int)
*/
// how many bytes we alocate for the list
#define LIST_SIZE 4096
struct List {
int num_elements;
int bytes_used; // this is the pointer where there is freespace
int data_ptr;
int ptrArray[LIST_SIZE];
unsigned char typeArray[LIST_SIZE];
unsigned char data[LIST_SIZE];
};
int is_type_number(unsigned char type);
int get_size_of_type(unsigned char type);
unsigned char list_get_type(struct List* list, int index);
int list_get(struct List* list, int index, void* valuePtr);
int list_get_int(struct List* list, int index, int* valuePtr);
int list_get_char(struct List* list, int index, char* valuePtr);
int list_set(struct List* list, int index, unsigned char type, void* valuePtr);
int list_set_int(struct List* list, int index, int value);
int list_set_char(struct List* list, int index, char value);
int list_append_int(struct List* list, int value);
int list_append_char(struct List* list, char value);
int list_delete(struct List* list, int index);
void list_print(struct List*);
#endif

View file

@ -2,192 +2,83 @@
#include <stdio.h>
#include <string.h>
#include "./stack.h"
struct IntParsingResult {
bool hasError;
int value;
};
bool is_operator(char candidate) {
return (
candidate == '*' ||
candidate == '+'
);
}
bool is_char_numeral(char candidate) {
int n = (int) candidate;
return n >= 48 && n <= 57;
}
int integer_pow(int base, int exponent)
{
if (exponent == 0) return 1;
int r = 1;
int multiplier = base;
while (exponent) {
// if exponent is even
if (exponent & 1) {
r *= multiplier;
}
multiplier *= multiplier;
exponent >>= 1; // divide by two the exponent
}
return r;
}
int parse_clean_positive_integer(int inputStrLen, char* inputStr, int* result) {
/**
Parse an integer that is just a continus stream of decimal numbers
without any negative sign
**/
int i = 0;
int value = 0;
while (inputStr[i] != 0) {
if (!is_char_numeral(inputStr[i])) {
return 1;
}
int numeralIndex = (int) inputStr[i];
value += (
integer_pow(10, inputStrLen-(i+1)) *
(numeralIndex & 0b001111)
);
i++;
}
*result = value;
return 0;
}
int parse_int(char* inputStr, int* result) {
int i = 0;
char cleanStr[sizeof(inputStr)];
int cleanStrLen = 0;
int signIndex = -1;
while (inputStr[i] != 0) {
if (
!is_char_numeral(inputStr[i]) &&
inputStr[i] != '-' &&
inputStr[i] != ' ' &&
inputStr[i] != '_'
) {
// we've encounter a unexpected char
return 1;
}
if (signIndex >= 0 && inputStr[i] == '-') {
// we'v encounter a sign but we already have one
return 1;
}
if (signIndex == -1 && inputStr[i] == '-') {
signIndex = i;
}
if (is_char_numeral(inputStr[i])) {
cleanStr[cleanStrLen] = inputStr[i];
cleanStrLen++;
}
i++;
}
printf("clean str: %s \n", cleanStr);
parse_clean_positive_integer(cleanStrLen, cleanStr, result);
if (signIndex >= 0) {
*result *= -1;
}
return 0;
}
int evaluate(char *inputStr) {
int i = 0;
int leftOperand = 0;
int len = strlen(inputStr);
// we want first to parse the expression and create a stack
// for 4*81 : ["4", "*", "81"]
// for -4*(5+42) : ["-4", "*", "(", "5", "+", "42", ")"]
// as a matter of fact, this is a partition
// so we can treat that as a list of tuple (start,finish)
int partitionStartPos[len];
int partitionStopPos[len];
char buff[len];
int buffPtr = 0;
int partitionPtr = 0;
int lastStartPos = 0;
while (inputStr[i] != 0) {
if (
is_operator(inputStr[i]) ||
inputStr[i] == '(' ||
inputStr[i] == ')'
) {
if (lastStartPos != i) {
partitionStartPos[partitionPtr] = lastStartPos;
partitionStopPos[partitionPtr] = i;
partitionPtr++;
}
partitionStartPos[partitionPtr] = i;
partitionStopPos[partitionPtr] = i+1;
partitionPtr++;
lastStartPos = i+1;
i++;
continue;
}
i++;
}
if (lastStartPos != i) {
partitionStartPos[partitionPtr] = lastStartPos;
partitionStopPos[partitionPtr] = i;
partitionPtr++;
}
// display the partition
printf("partitionPtr: %d \n", partitionPtr);
for (int j = 0; j < partitionPtr; j++) {
printf("start %d ", partitionStartPos[j]);
printf("stop %d ", partitionStopPos[j]);
int len = partitionStopPos[j] - partitionStartPos[j];
char buff[sizeof(inputStr)];
for (int z = 0; z < sizeof(inputStr); z++) {
if (z < len) {
buff[z] = inputStr[partitionStartPos[j]+z];
}
if (z == len) {
buff[z] = 0;
}
}
printf("content %s \n", buff);
}
return 0;
}
#include "./list.h"
#include "./number_parsing.h"
#include "./evaluator.h"
#include "./repr_utils.h"
#include "./types.h"
//int create_stack(int a, int b)
int main () {
char *inputStr = "4732*(-5851+55)+899";
void test_list()
{
// test dynamic list
struct List l1;
// int i = 0;
// while (inputStr[i] != 0) {
// printf("%d : '%c' \n", i, inputStr[i]);
// i++;
// }
printf("0: %d \n", list_append_int(&l1, 844));
printf("1: %d \n", list_get_type(&l1, 0));
// int parsedValue = 0;
// if (parse_int("-999", &parsedValue) > 0) {
// printf("Error parsing int \n");
// }
// printf("Value of int %d \n", parsedValue);
int val;
printf("2: %d \n", list_get_int(&l1, 0, &val));
// read the file
//
printf("result is: %d \n", evaluate(inputStr));
printf("final value: %d \n", val);
printf("3: %d \n", list_append_int(&l1, 855));
printf("4: %d \n", list_append_int(&l1, 866));
printf("5: %d \n", list_append_int(&l1, 877));
printf("\n");
for (int i = 0; i < l1.num_elements; i++) {
printf("- elem: %d, ptr: %d, type: %d \n", i, l1.ptrArray[i] , l1.typeArray[i]);
}
printf("\n");
list_get_int(&l1, 0, &val);
printf("6: %d \n", val);
list_delete(&l1, 0);
for (int i = 0; i < l1.num_elements; i++) {
printf("- elem: %d, ptr: %d, type: %d \n", i, l1.ptrArray[i] , l1.typeArray[i]);
}
// 844, 855, 866, 877
list_get_int(&l1, 2, &val);
printf("6: %d \n", val);
}
int main () {
char *inputStr2 = "((1+1))*MAX(4, 5)";
int res = 0;
int resType = 0;
int evalStatus = evaluate(inputStr2, &res, &resType);
printf("evaluation status is: %d \n", evalStatus);
printf("result type is: %d \n", resType);
if (resType == TYPE_FLOAT) {
printf("result is float: %f \n", get_float_from_int_rep(res));
}
if (resType == TYPE_INT) {
printf("result is int: %d \n", res);
}
// example of the use of stack
// struct IntStack exStack;
// int_stack_push(&exStack, 233);
// int_stack_push(&exStack, 298);
// int_stack_push(&exStack, 299);
// int res;
// int_stack_pop(&exStack, &res);
// printf("pop stack: %d \n", res);
// int_stack_pop(&exStack, &res);
// printf("pop stack: %d \n", res);
// int_stack_pop(&exStack, &res);
// printf("pop stack: %d \n", res);
}

173
src/number_parsing.c Normal file
View file

@ -0,0 +1,173 @@
#include <stdio.h>
#include <string.h>
#include "./number_parsing.h"
int is_char_numeral(char candidate) {
int n = (int) candidate;
return (n >= 48 && n <= 57);
}
int integer_pow(int base, int exponent)
{
if (exponent == 0) return 1;
int r = 1;
int multiplier = base;
while (exponent) {
// if exponent is even
if (exponent & 1) {
r *= multiplier;
}
multiplier *= multiplier;
exponent >>= 1; // divide by two the exponent
}
return r;
}
int parse_clean_positive_integer(int inputStrLen, char* inputStr, int* result) {
/**
Parse an integer that is just a continus stream of decimal numbers
without any negative sign
**/
int i = 0;
int value = 0;
while (inputStr[i] != 0) {
if (!is_char_numeral(inputStr[i])) {
return 1;
}
int numeralIndex = (int) inputStr[i];
value += (
integer_pow(10, inputStrLen-(i+1)) *
(numeralIndex & 0b001111)
);
i++;
}
//printf("parseclean %d \n", value);
*result = value;
return 0;
}
int parse_int(char* inputStr, int* resultPtr) {
int i = 0;
char cleanStr[strlen(inputStr)];
int cleanStrLen = 0;
int hasNegSign = 0;
while (inputStr[i] != 0) {
if (
!is_char_numeral(inputStr[i]) &&
inputStr[i] != '-' &&
inputStr[i] != ' ' &&
inputStr[i] != '_'
) {
// we've encounter a unexpected char
return 1;
}
if (inputStr[i] == '-' && (hasNegSign || i > 0)) {
// we'v encounter a sign but we already have one or it's too far
return 1;
}
if (!hasNegSign && inputStr[i] == '-') {
hasNegSign = 1;
}
if (is_char_numeral(inputStr[i])) {
cleanStr[cleanStrLen] = inputStr[i];
cleanStrLen++;
}
i++;
}
cleanStr[cleanStrLen] = 0;
//printf("clean str: %s/ \n", cleanStr);
int inter = 0;
parse_clean_positive_integer(cleanStrLen, cleanStr, &inter);
*resultPtr = inter;
if (hasNegSign) {
*resultPtr = -1 * inter;
}
return 0;
}
int parse_float(char* inputStr, float* resultPtr) {
int i = 0;
char cleanStrIntPart[strlen(inputStr)];
int cleanStrIntPartLen = 0;
char cleanStrFloatPart[strlen(inputStr)];
int cleanStrFloatPartLen = 0;
int part = 0; // 0 for first part, 1 for snd part
int hasNegSign = 0;
while (inputStr[i] != 0) {
if (inputStr[i] == '.') {
// we switch part
part = 1;
i++;
continue;
}
if (part == 0) {
if (
!is_char_numeral(inputStr[i]) &&
inputStr[i] != '-' &&
inputStr[i] != ' ' &&
inputStr[i] != '_'
) {
// we've encounter a unexpected char
return 10;
}
if (inputStr[i] == '-' && (hasNegSign || i > 0)) {
// we'v encounter a sign but we already have one or it's too far
return 20;
}
if (!hasNegSign && inputStr[i] == '-') {
hasNegSign = 1;
}
if (is_char_numeral(inputStr[i])) {
cleanStrIntPart[cleanStrIntPartLen] = inputStr[i];
cleanStrIntPartLen++;
}
}
if (part == 1) {
if (
!is_char_numeral(inputStr[i]) &&
inputStr[i] != ' ' &&
inputStr[i] != '_'
) {
// we've encounter a unexpected char
return 30;
}
if (is_char_numeral(inputStr[i])) {
cleanStrFloatPart[cleanStrFloatPartLen] = inputStr[i];
cleanStrFloatPartLen++;
}
}
i++;
}
cleanStrIntPart[cleanStrIntPartLen] = 0;
cleanStrFloatPart[cleanStrFloatPartLen] = 0;
printf("clean str int part: /%s/ \n", cleanStrIntPart);
printf("clean str float part: /%s/ \n", cleanStrFloatPart);
int intPart = 0;
parse_clean_positive_integer(cleanStrIntPartLen, cleanStrIntPart, &intPart);
int floatPart = 0;
parse_clean_positive_integer(cleanStrFloatPartLen, cleanStrFloatPart, &floatPart);
float tmp1 = ((float)floatPart / ((float) integer_pow(10, cleanStrFloatPartLen)));
float inter = ((float) intPart) + tmp1;
*resultPtr = inter;
if (hasNegSign) {
*resultPtr = -1 * inter;
}
return 0;
}

10
src/number_parsing.h Normal file
View file

@ -0,0 +1,10 @@
#ifndef NB_PARSING_H_
#define NB_PARSING_H_
int is_char_numeral(char candidate);
int integer_pow(int base, int exponent);
int parse_clean_positive_integer(int inputStrLen, char* inputStr, int* result);
int parse_int(char* inputStr, int* result);
int parse_float(char* inputStr, float* result);
#endif

78
src/operate.c Normal file
View file

@ -0,0 +1,78 @@
#include "./operate.h"
#include "./types.h"
#include <stdio.h>
#include <string.h>
int is_operator(char candidate) {
return (
candidate == '*' ||
candidate == '/' ||
candidate == '+' ||
candidate == '-'
);
}
int operate(
unsigned char operator,
unsigned char typeA, int aRepr,
unsigned char typeB, int bRepr,
unsigned char* typeRes, int* resPtr
)
{
if (
typeA == TYPE_FLOAT || typeB == TYPE_FLOAT ||
operator == '/'
) {
*typeRes = TYPE_FLOAT;
float a, b, res;
if (typeA == TYPE_FLOAT) {
*((int*) &a) = aRepr;
}
if (typeB == TYPE_FLOAT) {
*((int*) &b) = bRepr;
}
if (typeA == TYPE_INT) {
a = (float) aRepr;
}
if (typeB == TYPE_INT) {
b = (float) bRepr;
}
printf("Appling operation: %f %c %f \n", a, operator, b);
if (operator == '+') {
res = a+b;
} else if (operator == '-') {
res = a-b;
} else if (operator == '*') {
res = a*b;
} else if (operator == '/') {
res = a/b;
} else {
return 2;
}
printf("Got float: %f \n", res);
// get int representation of float
*resPtr = *(int *)(&res);
return 0;
}
if (typeA == TYPE_INT && typeB == TYPE_INT) {
printf("Appling operation %d %c %d \n", aRepr, operator, bRepr);
*typeRes = TYPE_INT;
int res = 0;
if (operator == '+') {
res = aRepr+bRepr;
} else if (operator == '-') {
res = aRepr-bRepr;
} else if (operator == '*') {
res = aRepr*bRepr;
} else {
return 2;
}
*resPtr = res;
return 0;
}
return 3;
}

14
src/operate.h Normal file
View file

@ -0,0 +1,14 @@
#ifndef OPERATOR_H_
#define OPERATOR_H_
int is_operator(char candidate);
int operate(
unsigned char operator,
unsigned char typeA, int aRepr,
unsigned char typeB, int bRepr,
unsigned char* typeRes, int* resPtr
);
#endif

23
src/repr_utils.c Normal file
View file

@ -0,0 +1,23 @@
#include "./repr_utils.h"
int get_int_rep_from_float(float ft)
{
return *(int *)(&ft);
}
/**
* Get a single precision floating point from int representation
* (following IEEE 754)
*/
float get_float_from_int_rep(int representation)
{
float res;
*((int*) &res) = representation;
return res;
}
int get_int_rep_from_char(char c)
{
return *(int *)(&c);
}

10
src/repr_utils.h Normal file
View file

@ -0,0 +1,10 @@
#ifndef REPR_UTILS_H_
#define REPR_UTILS_H_
int get_int_rep_from_float(float ft);
float get_float_from_int_rep(int representation);
int get_int_rep_from_char(char c);
#endif

View file

@ -1,14 +1,35 @@
#include "./stack.h"
#define STACK_LEN = 255
struct IntStack {
int end_pos;
int data[STACK_LEN];
}
int stack_create(int a, int b)
int int_stack_push(struct IntStack* stack, int valueToPush)
{
return (a+b);
if (stack->end_pos == STACK_LEN) {
// return a stack overflow error
return 1;
}
stack->data[stack->end_pos] = valueToPush;
stack->end_pos = stack->end_pos + 1;
return 0;
}
int int_stack_pop(struct IntStack* stack, int* valuePtr)
{
if (stack->end_pos == 0) {
// return a stack underflow error
return 1;
}
*valuePtr = stack->end_pos;
stack->end_pos = stack->end_pos - 1;
*valuePtr = stack->data[stack->end_pos];
return 0;
}
int int_stack_length(struct IntStack* stack)
{
return stack->end_pos;
}

View file

@ -1,9 +1,17 @@
#ifndef STACK_H_
#define STACK_H_
#define SOME_CST_A 42
#define STACK_LEN 255
int stack_create(int a, int b);
struct IntStack {
int end_pos;
int data[STACK_LEN];
};
int int_stack_push(struct IntStack* stack, int valueToPush);
int int_stack_pop(struct IntStack* stack, int* valuePtr);
int int_stack_length(struct IntStack* stack);
#endif

8
src/types.h Normal file
View file

@ -0,0 +1,8 @@
#define TYPE_INT 2
#define TYPE_FLOAT 3
#define TYPE_OPERATOR 32
#define TYPE_COMMA 33
#define TYPE_FUNC_NAME 34
#define TYPE_OPEN_PARENTHESIS 64
#define TYPE_CLOSE_PARENTHESIS 65

51
test.c Normal file
View file

@ -0,0 +1,51 @@
#include <stdio.h>
#include "./src/types.h"
#include "./src/list.h"
#include "./src/number_parsing.h"
#include "./src/funcs.h"
#include "./src/repr_utils.h"
int some_computation(int a, int b, int* resPtr)
{
*resPtr = a+b;
return 0;
}
int main () {
// struct List l1;
// list_append_int(&l1, 4);
// list_append_char(&l1, '*');
// list_append_int(&l1, 5);
// list_print(&l1);
// list_delete(&l1, 0);
// list_print(&l1);
// list_delete(&l1, 0);
// list_print(&l1);
// float res = 0;
// void* ptr = &res;
// printf("%d\n", sizeof(ptr));
int found = identify_func_name("ABS");
printf("found: %d \n", found);
unsigned char argsType[1] = { TYPE_FLOAT };
int argsVals[1] = { get_int_rep_from_float(-3.145) };
int resVal = 0;
unsigned char resType = 0;
execute_func(found, 1, argsType, argsVals, &resVal, &resType);
printf("func res type: %d \n", resType);
printf("func res: %f \n", get_float_from_int_rep(resVal));
// int stat = parse_float("1052.254", &res);
// printf("float parsing stat: %d \n", stat);
// printf("final float: %f \n", res);
}