Compare commits
9 Commits
4514d94be9
...
905acacd07
Author | SHA1 | Date | |
---|---|---|---|
905acacd07 | |||
8763fa35dd | |||
feae5d560a | |||
ec268f6047 | |||
6fff5e5cc8 | |||
7b19e553f2 | |||
64ef797727 | |||
85e17ede84 | |||
8e5b39a6e4 |
@ -1,12 +1,13 @@
|
|||||||
---
|
---
|
||||||
BasedOnStyle: LLVM
|
|
||||||
AlignConsecutiveShortCaseStatements:
|
AlignConsecutiveShortCaseStatements:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
AcrossEmptyLines: true
|
AcrossEmptyLines: true
|
||||||
AcrossComments: true
|
AcrossComments: true
|
||||||
|
IndentCaseLabels: true
|
||||||
AllowShortBlocksOnASingleLine: Always
|
AllowShortBlocksOnASingleLine: Always
|
||||||
AllowShortCaseLabelsOnASingleLine: true
|
AllowShortCaseLabelsOnASingleLine: true
|
||||||
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
|
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
|
||||||
AllowShortLoopsOnASingleLine: true
|
AllowShortLoopsOnASingleLine: true
|
||||||
IndentWidth: 4
|
IndentWidth: 4
|
||||||
PointerAlignment: Left
|
PointerAlignment: Left
|
||||||
|
AlignAfterOpenBracket: BlockIndent
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,3 +5,4 @@ tags
|
|||||||
.cache
|
.cache
|
||||||
build/*
|
build/*
|
||||||
compile_commands.json
|
compile_commands.json
|
||||||
|
vgcore.*
|
||||||
|
2
Makefile
2
Makefile
@ -14,7 +14,7 @@ TEST_OBJ_DIR = $(TEST_BUILD_DIR)/obj
|
|||||||
CC = clang
|
CC = clang
|
||||||
LINK = clang
|
LINK = clang
|
||||||
CFLAGS = -Wall -DDBG -ggdb
|
CFLAGS = -Wall -DDBG -ggdb
|
||||||
LDFLAGS =
|
LDFLAGS = -lm
|
||||||
|
|
||||||
SRC_FILES = $(wildcard $(SRC_DIR)/*.c)
|
SRC_FILES = $(wildcard $(SRC_DIR)/*.c)
|
||||||
OBJ_FILES = $(patsubst $(SRC_DIR)/%.c, $(OBJ_DIR)/%.o, $(SRC_FILES))
|
OBJ_FILES = $(patsubst $(SRC_DIR)/%.c, $(OBJ_DIR)/%.o, $(SRC_FILES))
|
||||||
|
17
README.md
17
README.md
@ -1,4 +1,4 @@
|
|||||||
# SCL: Simple Calculator Language
|
# SCL: Simple CAS Language
|
||||||
|
|
||||||
## Syntax
|
## Syntax
|
||||||
|
|
||||||
@ -12,16 +12,24 @@ As one would expect, you can evaluate simple infix expressions:
|
|||||||
You can also define your own functions:
|
You can also define your own functions:
|
||||||
|
|
||||||
```scl
|
```scl
|
||||||
> f(x) 2x
|
> f(x) = 2x
|
||||||
> f(2)
|
> f(2)
|
||||||
= 4
|
= 4
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Symbolic algebra is done in the following manner:
|
||||||
|
|
||||||
|
```scl
|
||||||
|
> f(x) = e^x
|
||||||
|
> diff(f, x:sym, 2)
|
||||||
|
= e^x
|
||||||
|
```
|
||||||
|
|
||||||
SCL will dynamically decide on types, but you can state them explicitly as
|
SCL will dynamically decide on types, but you can state them explicitly as
|
||||||
well:
|
well:
|
||||||
|
|
||||||
```scl
|
```scl
|
||||||
> f(x:int) 2x
|
> f(x:int) = 2x
|
||||||
> f(2.2)
|
> f(2.2)
|
||||||
! f(x:int): x must be of type int.
|
! f(x:int): x must be of type int.
|
||||||
```
|
```
|
||||||
@ -32,6 +40,5 @@ Variables can be defined, with several attributes:
|
|||||||
> a = 1 // Interpret type automatically.
|
> a = 1 // Interpret type automatically.
|
||||||
> b:int = 1 // Must be int.
|
> b:int = 1 // Must be int.
|
||||||
> c:const:int = 1 // Constant: value can never change.
|
> c:const:int = 1 // Constant: value can never change.
|
||||||
> d:lazy = (1 + 1) // Interpreter will wait as long as possible before
|
> x:sym // Treated symbolicaly.
|
||||||
// evaluating.
|
|
||||||
```
|
```
|
||||||
|
72
src/ast.c
72
src/ast.c
@ -1,6 +1,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "include/ast.h"
|
#include "include/ast.h"
|
||||||
|
#include "include/dstr.h"
|
||||||
#include "include/util.h"
|
#include "include/util.h"
|
||||||
|
|
||||||
extern AST* root;
|
extern AST* root;
|
||||||
@ -23,36 +24,59 @@ void ast_destroy(AST* ast) {
|
|||||||
if (!ast) return;
|
if (!ast) return;
|
||||||
|
|
||||||
switch (ast->type) {
|
switch (ast->type) {
|
||||||
case AST_TYPE_NUM: ast_type_num_destroy(ast->data); break;
|
case AST_TYPE_NUM: ast_num_data_destroy(ast->data); break;
|
||||||
case AST_TYPE_CALL: ast_type_call_destroy(ast->data); break;
|
case AST_TYPE_CALL: ast_call_data_destroy(ast->data); break;
|
||||||
default: log_dbgf("Unknown ast type %d (max: %d)", ast->type, AST_TYPE_MAX);
|
default:
|
||||||
|
log_dbgf("Unknown ast type %d (max: %d)", ast->type, AST_TYPE_MAX);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ast_print(AST* ast) {
|
void ast_print(AST* ast) { ast_print_i(ast, 0); }
|
||||||
log_dbgf("Tree type: %s", asttype_names[ast->type]);
|
|
||||||
fflush(stdout);
|
void ast_print_i(AST* ast, int i) {
|
||||||
|
INDENT_BEGIN(i);
|
||||||
|
|
||||||
|
INDENT_TITLE("AST", ast);
|
||||||
|
INDENT_FIELD("type", "%s", asttype_names[ast->type]);
|
||||||
|
INDENT_FIELD_EXT_NONL_START("data");
|
||||||
|
switch (ast->type) {
|
||||||
|
case AST_TYPE_NUM:
|
||||||
|
printf("%s %lf\n", INDENT_spacing->buf, *(ASTNumData*)ast->data);
|
||||||
|
break;
|
||||||
|
case AST_TYPE_CALL: ast_call_print(ast->data, i + 2); break;
|
||||||
|
default: exit(1);
|
||||||
|
}
|
||||||
|
INDENT_FIELD_NONL_END;
|
||||||
|
INDENT_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ASTNumData* ast_num_data_init(double val) {
|
||||||
ASTNumData* ast_type_num_init(int val) {
|
|
||||||
talloc(ASTNumData, num);
|
talloc(ASTNumData, num);
|
||||||
|
|
||||||
num->val = val;
|
log_dbgf("val: %lf", val);
|
||||||
|
|
||||||
|
*num = val;
|
||||||
|
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ast_type_num_destroy(ASTNumData* num) {
|
void ast_num_data_destroy(ASTNumData* num) {
|
||||||
if (!num)
|
if (!num) return free(num);
|
||||||
return
|
|
||||||
|
|
||||||
free(num);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ASTCallData* ast_type_call_init(char* to, size_t argc, AST** argv) {
|
void ast_num_print(ASTNumData* data, int i) {
|
||||||
|
INDENT_BEGIN(i);
|
||||||
|
|
||||||
|
INDENT_FIELD("data", "%lf", *data);
|
||||||
|
|
||||||
|
INDENT_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASTCallData* ast_call_data_init(char* to, size_t argc, AST** argv) {
|
||||||
talloc(ASTCallData, call);
|
talloc(ASTCallData, call);
|
||||||
|
|
||||||
|
log_dbgf("to: %s", to);
|
||||||
|
|
||||||
call->to = to;
|
call->to = to;
|
||||||
call->argc = argc;
|
call->argc = argc;
|
||||||
call->argv = argv;
|
call->argv = argv;
|
||||||
@ -60,11 +84,19 @@ ASTCallData* ast_type_call_init(char* to, size_t argc, AST** argv) {
|
|||||||
return call;
|
return call;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ast_type_call_destroy(ASTCallData* call) {
|
void ast_call_data_destroy(ASTCallData* call) {
|
||||||
if (!call)
|
if (!call) return free(call->to);
|
||||||
return
|
|
||||||
|
|
||||||
free(call->to);
|
|
||||||
for (size_t i = 0; i < call->argc; i++) free(call->argv[i]);
|
for (size_t i = 0; i < call->argc; i++) free(call->argv[i]);
|
||||||
free(call);
|
free(call);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ast_call_print(ASTCallData* data, int i) {
|
||||||
|
INDENT_BEGIN(i);
|
||||||
|
|
||||||
|
INDENT_TITLE("ASTCallData", data);
|
||||||
|
INDENT_FIELD("to", "%s", data->to);
|
||||||
|
INDENT_FIELD("argc", "%ld", data->argc);
|
||||||
|
INDENT_FIELD_LIST("argv", data->argv, data->argc, ast_print_i);
|
||||||
|
|
||||||
|
INDENT_END;
|
||||||
|
}
|
||||||
|
12
src/dstr.c
12
src/dstr.c
@ -25,8 +25,10 @@ void dstr_append(Dstr* dest, char* src, size_t ln) {
|
|||||||
// Double the buffer size when overflown.
|
// Double the buffer size when overflown.
|
||||||
dest->bufsz *= 2;
|
dest->bufsz *= 2;
|
||||||
dest->buf = realloc(dest->buf, dest->bufsz);
|
dest->buf = realloc(dest->buf, dest->bufsz);
|
||||||
log_dbgf("dstr @ %p doubled from %ld to %ld", dest, dest->bufsz / 2,
|
log_dbgf(
|
||||||
dest->bufsz);
|
"dstr @ %p doubled from %ld to %ld", dest, dest->bufsz / 2,
|
||||||
|
dest->bufsz
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overwrites the \0 at the end of the string, keeps the null from the given
|
// Overwrites the \0 at the end of the string, keeps the null from the given
|
||||||
@ -40,8 +42,10 @@ void dstr_appendch(Dstr* dest, char ch) {
|
|||||||
// Double the buffer size when overflown.
|
// Double the buffer size when overflown.
|
||||||
dest->bufsz *= 2;
|
dest->bufsz *= 2;
|
||||||
dest->buf = realloc(dest->buf, dest->bufsz);
|
dest->buf = realloc(dest->buf, dest->bufsz);
|
||||||
log_dbgf("dstr @ %p doubled from %ld to %ld", dest, dest->bufsz / 2,
|
log_dbgf(
|
||||||
dest->bufsz);
|
"dstr @ %p doubled from %ld to %ld", dest, dest->bufsz / 2,
|
||||||
|
dest->bufsz
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overwrites the preexisting null terminator, and adds one of its own.
|
// Overwrites the preexisting null terminator, and adds one of its own.
|
||||||
|
23
src/exec.c
23
src/exec.c
@ -7,26 +7,33 @@
|
|||||||
|
|
||||||
extern AST* root;
|
extern AST* root;
|
||||||
|
|
||||||
void exec_expr() {
|
ASTNumData exec_expr(AST* ast) {
|
||||||
ast_print(root);
|
// ast_print(ast);
|
||||||
log_dbg("Started execution.");
|
log_dbg("Started execution.");
|
||||||
switch (root->type) {
|
switch (ast->type) {
|
||||||
case AST_TYPE_CALL: exec_call(); break;
|
case AST_TYPE_CALL: return exec_call(ast);
|
||||||
|
case AST_TYPE_NUM: return *(ASTNumData*)ast->data;
|
||||||
default: printf("what\n");
|
default: printf("what\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void exec_call() {
|
ASTNumData exec_call(AST* ast) {
|
||||||
log_dbg("Started call execution.");
|
log_dbg("Started call execution.");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
ASTCallData* calldata = (ASTCallData*)root->data;
|
ASTCallData* calldata = (ASTCallData*)ast->data;
|
||||||
if (!strcmp(calldata->to, "+") && calldata->argc == 2) {
|
if (!strcmp(calldata->to, "+") && calldata->argc == 2) {
|
||||||
|
|
||||||
|
/*
|
||||||
ASTNumData* n1 = (ASTNumData*)calldata->argv[0]->data;
|
ASTNumData* n1 = (ASTNumData*)calldata->argv[0]->data;
|
||||||
ASTNumData* n2 = (ASTNumData*)calldata->argv[1]->data;
|
ASTNumData* n2 = (ASTNumData*)calldata->argv[1]->data;
|
||||||
|
*/
|
||||||
|
|
||||||
exec_return(n1->val + n2->val);
|
ASTNumData n1 = exec_expr(calldata->argv[0]);
|
||||||
|
ASTNumData n2 = exec_expr(calldata->argv[1]);
|
||||||
|
|
||||||
|
return n1 + n2;
|
||||||
}
|
}
|
||||||
|
return -1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
void exec_return(int n) { printf("= %d\n", n); }
|
void exec_print(double n) { printf("= %lf\n", n); }
|
||||||
|
@ -14,14 +14,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
%union {
|
%union {
|
||||||
int intval;
|
double fval;
|
||||||
char* strval;
|
char* strval;
|
||||||
AST* ast;
|
AST* ast;
|
||||||
}
|
}
|
||||||
|
|
||||||
%define parse.error verbose
|
%define parse.error verbose
|
||||||
|
|
||||||
%token<intval> NUM
|
%token<fval> NUM
|
||||||
%token<strval> CALL
|
%token<strval> CALL
|
||||||
%token PLUS
|
%token PLUS
|
||||||
%token NL
|
%token NL
|
||||||
@ -35,13 +35,12 @@ input:
|
|||||||
;
|
;
|
||||||
|
|
||||||
exp:
|
exp:
|
||||||
NUM { $$ = ast_init(AST_TYPE_NUM, ast_type_num_init($1)); }
|
NUM { $$ = ast_init(AST_TYPE_NUM, ast_num_data_init($1)); }
|
||||||
| NUM PLUS NUM {
|
| NUM PLUS NUM {
|
||||||
AST* argv[2] = {
|
AST** argv = calloc(2, sizeof(AST*));
|
||||||
ast_init(AST_TYPE_NUM, ast_type_num_init($1)),
|
argv[0] = ast_init(AST_TYPE_NUM, ast_num_data_init($1));
|
||||||
ast_init(AST_TYPE_NUM, ast_type_num_init($3))
|
argv[1] = ast_init(AST_TYPE_NUM, ast_num_data_init($3));
|
||||||
};
|
$$ = ast_init(AST_TYPE_CALL, ast_call_data_init("+", 2, argv));
|
||||||
$$ = ast_init(AST_TYPE_CALL, ast_type_call_init("+", 2, argv));
|
}
|
||||||
};
|
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
@ -17,13 +17,13 @@ typedef struct {
|
|||||||
AST* ast_init(ASTType type, void* data);
|
AST* ast_init(ASTType type, void* data);
|
||||||
void ast_destroy(AST* ast);
|
void ast_destroy(AST* ast);
|
||||||
void ast_print(AST* ast);
|
void ast_print(AST* ast);
|
||||||
|
void ast_print_i(AST* ast, int i);
|
||||||
|
|
||||||
typedef struct {
|
typedef double ASTNumData;
|
||||||
int val;
|
|
||||||
} ASTNumData;
|
|
||||||
|
|
||||||
ASTNumData* ast_type_num_init(int val);
|
ASTNumData* ast_num_data_init(double val);
|
||||||
void ast_type_num_destroy(ASTNumData* num);
|
void ast_num_data_destroy(ASTNumData* num);
|
||||||
|
void ast_num_print(ASTNumData*, int i);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char* to; // What the call's to.
|
char* to; // What the call's to.
|
||||||
@ -31,7 +31,8 @@ typedef struct {
|
|||||||
AST** argv; // Argument vector.
|
AST** argv; // Argument vector.
|
||||||
} ASTCallData;
|
} ASTCallData;
|
||||||
|
|
||||||
ASTCallData* ast_type_call_init(char* to, size_t argc, AST** argv);
|
ASTCallData* ast_call_data_init(char* to, size_t argc, AST** argv);
|
||||||
void ast_type_call_destroy(ASTCallData* call);
|
void ast_call_data_destroy(ASTCallData* call);
|
||||||
|
void ast_call_print(ASTCallData*, int i);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
#ifndef EXEC_H
|
#ifndef EXEC_H
|
||||||
#define EXEC_H
|
#define EXEC_H
|
||||||
|
|
||||||
void exec_expr();
|
#include "ast.h"
|
||||||
void exec_call();
|
|
||||||
void exec_return(int n);
|
ASTNumData exec_expr(AST* ast);
|
||||||
|
ASTNumData exec_call(AST* ast);
|
||||||
|
void exec_print(double n);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -17,6 +17,12 @@
|
|||||||
extern YYSTYPE yylval;
|
extern YYSTYPE yylval;
|
||||||
extern char* inp;
|
extern char* inp;
|
||||||
|
|
||||||
|
// Accumulate an integer.
|
||||||
|
int acc_int(int c);
|
||||||
|
|
||||||
|
// Accumulate a floating-point number.
|
||||||
|
double acc_float(int c);
|
||||||
|
|
||||||
// Called by `yyparse()` (in bison-generated files.)
|
// Called by `yyparse()` (in bison-generated files.)
|
||||||
int yylex();
|
int yylex();
|
||||||
void yyerror(char const* s);
|
void yyerror(char const* s);
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
#ifndef TOKEN_H
|
|
||||||
#define TOKEN_H
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
TOKEN_TYPE_CALL,
|
|
||||||
TOKEN_TYPE_NUMBER,
|
|
||||||
TOKEN_TYPE_MAX = TOKEN_TYPE_NUMBER,
|
|
||||||
} TokenType;
|
|
||||||
|
|
||||||
// Token.
|
|
||||||
typedef struct {
|
|
||||||
TokenType type; // The type of the Token.
|
|
||||||
size_t valn; // The length of val.
|
|
||||||
char* val; // The text of the Token.
|
|
||||||
size_t len; // Length of the text of the Token.
|
|
||||||
} Token;
|
|
||||||
|
|
||||||
Token* token_init(TokenType type, char* val, size_t valn);
|
|
||||||
void token_destroy(Token* token);
|
|
||||||
|
|
||||||
// Prints out a representation of the Token.
|
|
||||||
void token_print(Token* token);
|
|
||||||
|
|
||||||
// Prints out a representation of the Token, with the specified indent level.
|
|
||||||
void token_print_i(Token* token, int ilevel);
|
|
||||||
|
|
||||||
// Prints out a representation of the TokenType.
|
|
||||||
void tokentype_print(TokenType t);
|
|
||||||
|
|
||||||
// Prints out a representation of the TokenType, with the specified indent
|
|
||||||
// level.
|
|
||||||
void tokentype_print_i(TokenType t, int ilevel);
|
|
||||||
|
|
||||||
// Prints a token's type. That's it.
|
|
||||||
void tokentype_print_raw(TokenType t);
|
|
||||||
|
|
||||||
#endif
|
|
@ -50,7 +50,7 @@
|
|||||||
|
|
||||||
// Print & indent the title of a section.
|
// Print & indent the title of a section.
|
||||||
#define INDENT_TITLE(THING, WHERE) \
|
#define INDENT_TITLE(THING, WHERE) \
|
||||||
printf("%s" COL_BCYA THING " @ %p\n" COL_RESET, INDENT_spacing->buf, WHERE);
|
printf("%s" COL_BCYA THING COL_RESET " @" COL_MAG " %p\n" COL_RESET, INDENT_spacing->buf, WHERE);
|
||||||
|
|
||||||
// Print & indent a thing.
|
// Print & indent a thing.
|
||||||
#define INDENT_FIELD(FIELD, VAL, ...) \
|
#define INDENT_FIELD(FIELD, VAL, ...) \
|
||||||
@ -64,8 +64,8 @@
|
|||||||
INDENT_spacing->buf, INDENT_spacing->buf, __VA_ARGS__);
|
INDENT_spacing->buf, INDENT_spacing->buf, __VA_ARGS__);
|
||||||
|
|
||||||
// Print & indent a thing without any newline.
|
// Print & indent a thing without any newline.
|
||||||
#define INDENT_FIELD_NONL_START(FIELD) \
|
#define INDENT_FIELD_EXT_NONL_START(FIELD) \
|
||||||
printf("%s " COL_BWHI FIELD ": " COL_RESET COL_WHI, INDENT_spacing->buf);
|
printf("%s " COL_BWHI FIELD ":\n" COL_RESET COL_WHI, INDENT_spacing->buf);
|
||||||
#define INDENT_FIELD_NONL_END printf( "\n" COL_RESET);
|
#define INDENT_FIELD_NONL_END printf( "\n" COL_RESET);
|
||||||
|
|
||||||
// Print an array A of N things, by calling the function F.
|
// Print an array A of N things, by calling the function F.
|
||||||
|
52
src/lexer.c
52
src/lexer.c
@ -1,9 +1,52 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <math.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "include/lexer.h"
|
#include "include/lexer.h"
|
||||||
|
|
||||||
|
int acc_int(int c) {
|
||||||
|
int value = c - '0';
|
||||||
|
while (isdigit(*inp)) {
|
||||||
|
value = value * 10 + (*inp - '0'); // Accumulate value.
|
||||||
|
inp++;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
double acc_float(int c) {
|
||||||
|
int dplaces = 0;
|
||||||
|
double value = (double)(c - '0');
|
||||||
|
|
||||||
|
// Grab everything prior to '.'.
|
||||||
|
while (isdigit(*inp)) {
|
||||||
|
value = value * 10 + (*inp - '0'); // Accumulate value.
|
||||||
|
inp++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*inp == '.') {
|
||||||
|
inp++;
|
||||||
|
|
||||||
|
while (isdigit(*inp)) {
|
||||||
|
// TODO:
|
||||||
|
// Accumulate as int, divide once at end.
|
||||||
|
// value = value + (((double)(*inp - '0'))/pow(10.0l,
|
||||||
|
// (double)(inp-oinp))); // Accumulate value.
|
||||||
|
value = value * 10 + (*inp - '0'); // Accumulate value.
|
||||||
|
dplaces++;
|
||||||
|
inp++;
|
||||||
|
}
|
||||||
|
value = value / pow(10, dplaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
// > 1.20000
|
||||||
|
// = 1.0 + 2/10
|
||||||
|
|
||||||
|
// > 1.23
|
||||||
|
// = 1.2 + 3/100
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
int yylex() {
|
int yylex() {
|
||||||
if (*inp == '\0') return YYEOF;
|
if (*inp == '\0') return YYEOF;
|
||||||
|
|
||||||
@ -15,12 +58,7 @@ int yylex() {
|
|||||||
|
|
||||||
// Check for NUM.
|
// Check for NUM.
|
||||||
if (isdigit(c)) {
|
if (isdigit(c)) {
|
||||||
int value = c - '0';
|
yylval.fval = acc_float(c); // Set the token value.
|
||||||
while (isdigit(*inp)) {
|
|
||||||
value = value * 10 + (*inp - '0'); // Accumulate value.
|
|
||||||
inp++;
|
|
||||||
}
|
|
||||||
yylval.intval = value; // Set the token value.
|
|
||||||
return NUM;
|
return NUM;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,4 +72,4 @@ int yylex() {
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
void yyerror(char const* s) { fprintf(stderr, "Syntax error:\n%s\n", s); }
|
void yyerror(char const* s) { fprintf(stderr, "Parse error: %s\n", s); }
|
||||||
|
13
src/main.c
13
src/main.c
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
#include "include/ast.h"
|
#include "include/ast.h"
|
||||||
#include "include/dstr.h"
|
#include "include/dstr.h"
|
||||||
|
#include "include/exec.h"
|
||||||
#include "include/lexer.h"
|
#include "include/lexer.h"
|
||||||
#include "include/util.h"
|
#include "include/util.h"
|
||||||
#include "include/exec.h"
|
|
||||||
|
|
||||||
#include "../build/grammars/grammar.tab.h"
|
#include "../build/grammars/grammar.tab.h"
|
||||||
|
|
||||||
@ -31,7 +31,6 @@ int main(int argc, char** argv) {
|
|||||||
switch (c) {
|
switch (c) {
|
||||||
case EOF: dstr_destroy(ln); goto lnskip;
|
case EOF: dstr_destroy(ln); goto lnskip;
|
||||||
case '\n': goto lnend;
|
case '\n': goto lnend;
|
||||||
|
|
||||||
default: dstr_appendch(ln, c); log_dbgf("cchar: %c", c);
|
default: dstr_appendch(ln, c); log_dbgf("cchar: %c", c);
|
||||||
}
|
}
|
||||||
} while (1);
|
} while (1);
|
||||||
@ -41,14 +40,12 @@ int main(int argc, char** argv) {
|
|||||||
log_dbgf("cline: %s", ln->buf);
|
log_dbgf("cline: %s", ln->buf);
|
||||||
|
|
||||||
if (ln->ln > 0) {
|
if (ln->ln > 0) {
|
||||||
// I hope it's null-terminated.
|
|
||||||
inp = ln->buf;
|
inp = ln->buf;
|
||||||
if (yyparse() == 0)
|
if (yyparse() == 0) printf("Parsed successfully!\n");
|
||||||
printf("Parsed successfully!\n");
|
else printf("Parse error.\n");
|
||||||
else
|
|
||||||
printf("Parse error.\n");
|
|
||||||
|
|
||||||
exec_expr();
|
exec_print(exec_expr(root));
|
||||||
|
ast_print(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
dstr_destroy(ln);
|
dstr_destroy(ln);
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "include/util.h"
|
|
||||||
#include "include/stack.h"
|
#include "include/stack.h"
|
||||||
|
#include "include/util.h"
|
||||||
|
|
||||||
Stack* stack_init() {
|
Stack* stack_init() {
|
||||||
talloc(Stack, stack);
|
talloc(Stack, stack);
|
||||||
|
62
src/token.c
62
src/token.c
@ -1,62 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "include/token.h"
|
|
||||||
#include "include/dstr.h"
|
|
||||||
#include "include/util.h"
|
|
||||||
|
|
||||||
static char* tokentype_names[] = {
|
|
||||||
[TOKEN_TYPE_CALL] = "CALL",
|
|
||||||
[TOKEN_TYPE_NUMBER] = "NUMBER",
|
|
||||||
};
|
|
||||||
|
|
||||||
Token* token_init(TokenType type, char* val, size_t valn) {
|
|
||||||
Token* t = malloc(sizeof(Token));
|
|
||||||
|
|
||||||
t->type = type;
|
|
||||||
t->valn = valn;
|
|
||||||
t->val = val;
|
|
||||||
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
void token_destroy(Token* t) {
|
|
||||||
free(t->val);
|
|
||||||
free(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
void token_print(Token* token) { token_print_i(token, 0); }
|
|
||||||
|
|
||||||
void token_print_i(Token *token, int ilvl) {
|
|
||||||
INDENT_BEGIN(ilvl);
|
|
||||||
|
|
||||||
INDENT_TITLE("Token", token);
|
|
||||||
INDENT_FIELD_NONL_START("type")
|
|
||||||
tokentype_print_raw(token->type);
|
|
||||||
INDENT_FIELD_NONL_END
|
|
||||||
INDENT_FIELD("valn", "%ld", token->valn);
|
|
||||||
INDENT_FIELD_NL("val", "\"%s\"", token->val);
|
|
||||||
}
|
|
||||||
|
|
||||||
void tokentype_print_raw(TokenType t) {
|
|
||||||
if (t > TOKEN_TYPE_MAX) {
|
|
||||||
printf("Unknown (%d)", t);
|
|
||||||
log_dbgf("%d is not a valid TokenType (max: %d)", t, TOKEN_TYPE_MAX);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("%s", tokentype_names[t]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void tokentype_print(TokenType t) { tokentype_print_i(t, 0); }
|
|
||||||
|
|
||||||
void tokentype_print_i(TokenType t, int i) {
|
|
||||||
INDENT_BEGIN(i);
|
|
||||||
|
|
||||||
if (t > TOKEN_TYPE_MAX) {
|
|
||||||
INDENT_FIELD("val", "Unknown (%d)", t);
|
|
||||||
log_dbgf("%d is not a valid TokenType (max: %d)", t, TOKEN_TYPE_MAX);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
INDENT_FIELD("val", "%s", tokentype_names[t]);
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user