initial commit
This commit is contained in:
parent
cdc6a08f41
commit
17c7c247af
25 changed files with 1557 additions and 223 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1 +1,3 @@
|
|||
./main
|
||||
./test
|
||||
main
|
||||
|
|
151
README.md
151
README.md
|
@ -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...
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
PRINT 1
|
|
@ -1 +0,0 @@
|
|||
PRINT (1+2)
|
|
@ -1,5 +0,0 @@
|
|||
LET A BE 0
|
||||
WHILE NOT A DO
|
||||
PRINT A
|
||||
LET A BE A+1
|
||||
ENDWHILE
|
|
@ -1 +0,0 @@
|
|||
PRINT "Hello World"
|
6
examples/input_and_compute.ltor
Normal file
6
examples/input_and_compute.ltor
Normal 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
2
examples/print_42.ltor
Normal file
|
@ -0,0 +1,2 @@
|
|||
# just print 42
|
||||
eval print_number(42)
|
418
src/evaluator.c
Normal file
418
src/evaluator.c
Normal 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
6
src/evaluator.h
Normal 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
141
src/funcs.c
Normal 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
49
src/funcs.h
Normal 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
251
src/list.c
Normal 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
71
src/list.h
Normal 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
|
257
src/main.c
257
src/main.c
|
@ -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));
|
||||
|
||||
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);
|
||||
|
||||
// read the file
|
||||
//
|
||||
printf("result is: %d \n", evaluate(inputStr));
|
||||
}
|
||||
|
||||
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
173
src/number_parsing.c
Normal 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
10
src/number_parsing.h
Normal 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
78
src/operate.c
Normal 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
14
src/operate.h
Normal 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
23
src/repr_utils.c
Normal 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
10
src/repr_utils.h
Normal 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
|
39
src/stack.c
39
src/stack.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
12
src/stack.h
12
src/stack.h
|
@ -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
8
src/types.h
Normal 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
51
test.c
Normal 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);
|
||||
}
|
||||
|
Loading…
Reference in a new issue