initial commit
This commit is contained in:
commit
1f4f58b3fb
11 changed files with 313 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
./main
|
6
Makefile
Normal file
6
Makefile
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
WERROR?=
|
||||||
|
CFLAGS=-Wall -Wextra $(WERROR) -pedantic -I.
|
||||||
|
CXXFLAGS_WITHOUT_PKGS=$(CFLAGS) -fno-exceptions -Wno-missing-braces -Wswitch-enum -lm
|
||||||
|
|
||||||
|
build:
|
||||||
|
gcc src/* -o ./main ${CXXFLAGS_WITHOUT_PKGS}
|
82
README.md
Normal file
82
README.md
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
# Simple BASIC language implementation
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
## Technology
|
||||||
|
|
||||||
|
We will create our own regex engine
|
||||||
|
|
||||||
|
## Syntax
|
||||||
|
|
||||||
|
One instruction set per line
|
||||||
|
|
||||||
|
Instruction sets avalaibles:
|
||||||
|
|
||||||
|
### Commentary
|
||||||
|
|
||||||
|
can only use single line comments with `#`
|
||||||
|
|
||||||
|
```
|
||||||
|
# this is a comment
|
||||||
|
```
|
||||||
|
|
||||||
|
### Expression evaluation
|
||||||
|
|
||||||
|
can only operate on integer
|
||||||
|
|
||||||
|
function calls: func(arg_a, arg_b)
|
||||||
|
operators: +, *, /
|
||||||
|
booleans operators: not, and, or,
|
||||||
|
|
||||||
|
### function definition
|
||||||
|
|
||||||
|
```
|
||||||
|
function {NAME}
|
||||||
|
begin
|
||||||
|
...
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### Set a variable
|
||||||
|
|
||||||
|
```
|
||||||
|
set {VARNAME} to {EXPRESSION}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Conditional structure
|
||||||
|
|
||||||
|
```
|
||||||
|
if {EXPRESSION} then
|
||||||
|
begin
|
||||||
|
...
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### Conditional loop
|
||||||
|
|
||||||
|
```
|
||||||
|
while {EXPRESSION} do
|
||||||
|
begin
|
||||||
|
...
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### Unconditional loop
|
||||||
|
|
||||||
|
```
|
||||||
|
repeat {EXPRESSION THAT EVALUATE TO INT}
|
||||||
|
begin
|
||||||
|
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### std functions
|
||||||
|
|
||||||
|
```
|
||||||
|
put_stdout()
|
||||||
|
take_stdin()
|
||||||
|
int_of_string()
|
||||||
|
random_int(min, max)
|
||||||
|
```
|
1
examples/basic_1.basic
Normal file
1
examples/basic_1.basic
Normal file
|
@ -0,0 +1 @@
|
||||||
|
PRINT 1
|
1
examples/basic_2.basic
Normal file
1
examples/basic_2.basic
Normal file
|
@ -0,0 +1 @@
|
||||||
|
PRINT (1+2)
|
5
examples/calc_1.basic
Normal file
5
examples/calc_1.basic
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
LET A BE 0
|
||||||
|
WHILE NOT A DO
|
||||||
|
PRINT A
|
||||||
|
LET A BE A+1
|
||||||
|
ENDWHILE
|
1
examples/hello_world.basic
Normal file
1
examples/hello_world.basic
Normal file
|
@ -0,0 +1 @@
|
||||||
|
PRINT "Hello World"
|
BIN
main
Executable file
BIN
main
Executable file
Binary file not shown.
193
src/main.c
Normal file
193
src/main.c
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
#include <stdbool.h>
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
//int create_stack(int a, int b)
|
||||||
|
|
||||||
|
int main () {
|
||||||
|
char *inputStr = "4732*(-5851+55)+899";
|
||||||
|
|
||||||
|
// int i = 0;
|
||||||
|
// while (inputStr[i] != 0) {
|
||||||
|
// printf("%d : '%c' \n", i, inputStr[i]);
|
||||||
|
// i++;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// int parsedValue = 0;
|
||||||
|
// if (parse_int("-999", &parsedValue) > 0) {
|
||||||
|
// printf("Error parsing int \n");
|
||||||
|
// }
|
||||||
|
// printf("Value of int %d \n", parsedValue);
|
||||||
|
|
||||||
|
// read the file
|
||||||
|
//
|
||||||
|
printf("result is: %d \n", evaluate(inputStr));
|
||||||
|
}
|
14
src/stack.c
Normal file
14
src/stack.c
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#include "./stack.h"
|
||||||
|
|
||||||
|
#define STACK_LEN = 255
|
||||||
|
|
||||||
|
struct IntStack {
|
||||||
|
int end_pos;
|
||||||
|
int data[STACK_LEN];
|
||||||
|
}
|
||||||
|
|
||||||
|
int stack_create(int a, int b)
|
||||||
|
{
|
||||||
|
return (a+b);
|
||||||
|
}
|
||||||
|
|
9
src/stack.h
Normal file
9
src/stack.h
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#ifndef STACK_H_
|
||||||
|
#define STACK_H_
|
||||||
|
|
||||||
|
#define SOME_CST_A 42
|
||||||
|
|
||||||
|
int stack_create(int a, int b);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue