From 0d1ecd9bd3ce893fe514940bb100e673241e6c29 Mon Sep 17 00:00:00 2001 From: Andrew Kesterson Date: Fri, 3 May 2024 22:26:34 -0400 Subject: [PATCH] - All tests passing - Updated README and image - Added itoa to stdlib - Implemented modulus math for bcc which has none in the stdlib - Updated the build scripts to work on Ubuntu 22 - Added bochsrc with some useful overrides (new bochs bios in ubuntu is broken, use the legacy) - Made most of stdlib compile and run under GNU C for testing - Improved the tokenizer so it will return tokens of more than one character - Moved the basic parser from using void pointers to store values to using basic_value unions to represent possible types - Added tests for the basic tokenizer --- Makefile | 3 +- README.md | 9 ++- asm/kernel_syms.S | 2 - bochsrc | 3 +- media/screenshot.png | Bin 14578 -> 14962 bytes src/basic.c | 145 +++++++++++++++++++------------------ src/basic.h | 20 ++++- src/conio.c | 18 ++++- src/conio.h | 3 +- src/screen.c | 3 + src/stdlib.c | 60 ++++++++++++++- src/stdlib.h | 2 + src/string.c | 17 +++-- src/string.h | 2 +- src/types.h | 4 + tests/Makefile | 2 +- tests/basic_tokenizer.c | 29 ++++++++ tests/basic_tokenizer.deps | 5 ++ tests/stdlib_atoi.c | 5 +- tests/stdlib_imod.c | 10 +++ tests/stdlib_imod.deps | 2 + tests/stdlib_itoa.c | 16 ++++ tests/stdlib_itoa.deps | 2 + 23 files changed, 264 insertions(+), 98 deletions(-) delete mode 100644 asm/kernel_syms.S create mode 100644 tests/basic_tokenizer.c create mode 100644 tests/basic_tokenizer.deps create mode 100644 tests/stdlib_imod.c create mode 100644 tests/stdlib_imod.deps create mode 100644 tests/stdlib_itoa.c create mode 100644 tests/stdlib_itoa.deps diff --git a/Makefile b/Makefile index 55c020c..29945f2 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ kernel.bin: src/screen.o src/conio.o src/string.o src/stdlib.o src/basic.o src/k asm/kernel_syms.S: kernel.bin cat ld86.out | \ grep -E "^\s+kernel\s+[a-zA-Z0-9_]+ 0 [0-9]+" | \ - python -c "import sys; print '\n'.join([\"_extern_c%s:\n jmp 0x1000:0x%04x\" % (x.lstrip(' ').replace('kernel', '').lstrip(' ').split(' ')[0], int(x.lstrip(' ').replace('kernel', '').lstrip(' ').split(' ')[4], 16)) for x in sys.stdin.readlines()])" > asm/kernel_syms.S + python3 -c "import sys; print('\n'.join([\"_extern_c%s:\n jmp 0x1000:0x%04x\" % (x.lstrip(' ').replace('kernel', '').lstrip(' ').split(' ')[0], int(x.lstrip(' ').replace('kernel', '').lstrip(' ').split(' ')[4], 16)) for x in sys.stdin.readlines()]))" > asm/kernel_syms.S boot.bin: asm/kernel_syms.S asm/bootloader.S asm/bootloader.S cd asm && nasm bootloader.S -f bin -o ../$@ @@ -37,3 +37,4 @@ test: .PHONY: clean clean: rm -f boot.bin asm/*o src/*o + cd tests && make clean diff --git a/README.md b/README.md index c0d9f0c..6d39624 100644 --- a/README.md +++ b/README.md @@ -17,24 +17,27 @@ Right now, not much of anything at all. It boots from a 1.44mB floppy disk, and ![Image of Piquant v0.1](media/screenshot.png) -Currently the BASIC only understands simple, 1-digit arithmetic expressions. But this will soon change; I intend to implement at least as many features as uBASIC, maybe QuickBASIC eventually. +Currently the BASIC only understands simple arithmetic expressions. But this will soon change; I intend to implement at least as many features as uBASIC, maybe QuickBASIC eventually. How can I run it? ===== -You have to build it to run it. To build it, you need: +You have to build it to + run it. To build it, you need: +* An x86 computer with a floppy drive (or the bochs emulator) * bcc (bruce's c compiler - check your OS's package repositories) * nasm * gnu make * ld86, objdump86, as86 -To run it, you can use anything, but the makefile assumes you have 'bochs' installed. +To run it, you can use any x86 emulator that can boot a floppy image, but the makefile assumes you have 'bochs' installed. make clean run This will rebuild all of the sources and fire up the bochs emulator. Have fun. + Developing & Testing ======= diff --git a/asm/kernel_syms.S b/asm/kernel_syms.S deleted file mode 100644 index 8ff6b8d..0000000 --- a/asm/kernel_syms.S +++ /dev/null @@ -1,2 +0,0 @@ -_extern_c_main: - jmp 0x1000:0x0cc8 diff --git a/bochsrc b/bochsrc index 5cba4d6..099a7e8 100644 --- a/bochsrc +++ b/bochsrc @@ -1,3 +1,4 @@ -display_library: sdl +display_library: sdl2 boot: floppy floppya: 1_44=boot.img, status=inserted +romimage: file=$BXSHARE/BIOS-bochs-legacy diff --git a/media/screenshot.png b/media/screenshot.png index faf2359fd56bcf9b5357b49a8ea5b48ebb608c01..4ce69ad11d917ab3fa7fb88f9d0797d21d5ae140 100644 GIT binary patch literal 14962 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 b8G!{M;qQ!1U&R3(L0Y%@qZc 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 G!2buYV1G6M diff --git a/src/basic.c b/src/basic.c index 23d6391..58206ca 100644 --- a/src/basic.c +++ b/src/basic.c @@ -22,34 +22,30 @@ char *_tokenize(char *ptr, char *token) char *orig = NULL; char *tokenptr = NULL; int len = 0; + int numtokens = 0; + int i = 0; - if ( ptr == NULL ) { + if ( ptr == NULL || token == NULL ) { return NULL; } if ( _tokenizer_prev == ptr ) { ptr = _tokenizer_prev_next; } orig = ptr; + numtokens = strlen(token); memset(&_tokenizer_value, 0x00, BASIC_TOKENIZER_MAX_LENGTH); while ( *ptr != 0x0 ) { tokenptr = token; - - /* I don't understand why this works. It shouldn't work. */ - while ( *tokenptr != 0x0 && (*ptr == *tokenptr++) ) {}; - /* ----------------------------------------------------- */ - - if ( *tokenptr == 0x00 ) { - break; - } else { - if ( *ptr == '\0' ) { - ptr -= sizeof(char); - break; - } - ptr += sizeof(char); - len += 1; + for ( i = 0 ; i < numtokens; i++) { + if ( *ptr == *(tokenptr + i)) { + goto _tokenize_copy; + } } + ptr += 1; + len += 1; } +_tokenize_copy: if ( len > BASIC_TOKENIZER_MAX_LENGTH ) { basic_errno = BASIC_ERR_SYNTAX_TOKEN_LENGTH; return NULL; @@ -58,14 +54,19 @@ char *_tokenize(char *ptr, char *token) } memcpy((void *)&_tokenizer_value, (void *)orig, len); _tokenizer_prev_next = (ptr + 1); - return &_tokenizer_value; + return ptr; +} + +char *_token_get(void) +{ + return (char *)&_tokenizer_value; } int basic_solve_expr(struct basic_expr *expr, struct basic_variable *result) { if ( expr == NULL || result == NULL ) { basic_errno = BASIC_ERR_INTERNAL_NULLPOINTER; - return NULL; + return 0; } switch (expr->type) { @@ -73,74 +74,74 @@ int basic_solve_expr(struct basic_expr *expr, struct basic_variable *result) if ( expr->lval_type != BASIC_LVAL_CONST || ( expr->rval_type != BASIC_RVAL_CONST ) ) { basic_errno = BASIC_ERR_INVALID_ARGUMENTS; - return NULL; + return 0; } result->flags = (result->flags | BASIC_VARFLAG_TINT | BASIC_VARFLAG_INIT); - result->value = (int)expr->lval + (int)expr->rval; + result->value.i = expr->lval.i + expr->rval.i; break; case BASIC_OPTP_SUB: if ( expr->lval_type != BASIC_LVAL_CONST || ( expr->rval_type != BASIC_RVAL_CONST ) ) { basic_errno = BASIC_ERR_INVALID_ARGUMENTS; - return NULL; + return 0; } result->flags = (result->flags | BASIC_VARFLAG_TINT | BASIC_VARFLAG_INIT); - result->value = (int)expr->lval - (int)expr->rval; + result->value.i = expr->lval.i - expr->rval.i; break; case BASIC_OPTP_MUL: if ( expr->lval_type != BASIC_LVAL_CONST || ( expr->rval_type != BASIC_RVAL_CONST ) ) { basic_errno = BASIC_ERR_INVALID_ARGUMENTS; - return NULL; + return 0; } result->flags = (result->flags | BASIC_VARFLAG_TINT | BASIC_VARFLAG_INIT); - result->value = (int)expr->lval * (int)expr->rval; + result->value.i = expr->lval.i * expr->rval.i; break; case BASIC_OPTP_DIV: if ( expr->lval_type != BASIC_LVAL_CONST || ( expr->rval_type != BASIC_RVAL_CONST ) ) { basic_errno = BASIC_ERR_INVALID_ARGUMENTS; - return NULL; + return 0; } - if ( expr->rval == 0 ) { + if ( expr->rval.i == 0) { basic_errno = BASIC_ERR_MATH_DBZ; - return NULL; + return 0; } result->flags = (result->flags | BASIC_VARFLAG_TINT | BASIC_VARFLAG_INIT); - result->value = (int)expr->lval / (int)expr->rval; + result->value.i = expr->lval.i / expr->rval.i; break; case BASIC_OPTP_MOD: if ( expr->lval_type != BASIC_LVAL_CONST || ( expr->rval_type != BASIC_RVAL_CONST ) ) { basic_errno = BASIC_ERR_INVALID_ARGUMENTS; - return NULL; + return 0; } - if ( expr->rval == 0 ) { + if ( expr->rval.i == 0) { basic_errno = BASIC_ERR_MATH_DBZ; - return NULL; + return 0; } result->flags = (result->flags | BASIC_VARFLAG_TINT | BASIC_VARFLAG_INIT); - result->value = ((int)expr->lval) - (((int)expr->lval / (int)expr->rval)*(int)expr->rval); + result->value.i = (expr->lval.i) - ((expr->lval.i / expr->rval.i)*expr->rval.i); break; case BASIC_OPTP_EQL: if ( expr->lval_type != BASIC_LVAL_CONST || ( expr->rval_type != BASIC_RVAL_CONST ) ) { basic_errno = BASIC_ERR_INVALID_ARGUMENTS; - return NULL; + return 0; } result->flags = (result->flags | BASIC_VARFLAG_TINT | BASIC_VARFLAG_INIT); - if ((int)expr->lval == (int)expr->rval) { - result->value = BASIC_CONST_TRUE; + if (expr->lval.i == expr->rval.i) { + result->value.i = BASIC_CONST_TRUE; } else { - result->value = BASIC_CONST_FALSE; + result->value.i = BASIC_CONST_FALSE; } break; case BASIC_OPTP_ASN: basic_errno = BASIC_ERR_INTERNAL_UNIMPLEMENTED; - return NULL; + return 0; default: basic_errno = BASIC_ERR_INTERNAL_UNDEFINED_BEHAVIOR; - return NULL; + return 0; } return 1; } @@ -149,7 +150,7 @@ struct basic_expr *basic_parse_expr(char *expbuf) { struct basic_expr *ret = &math_expressions[0]; char flags = 0; - char *subptr = 0; + /*char *subptr = 0;*/ _tokenizer_init(); memset(ret, 0x0, sizeof(struct basic_expr)); @@ -160,33 +161,35 @@ struct basic_expr *basic_parse_expr(char *expbuf) continue; } else if ( isdigit(*expbuf) == 1 ) { if ( (ret->type == 0) && (flags & BASIC_FOUND_LVAL) == BASIC_FOUND_LVAL ) { - basic_errno = BASIC_ERR_SYNTAX_MULTIPLE_LVALUES; - return NULL; + basic_errno = BASIC_ERR_SYNTAX_MULTIPLE_LVALUES; + return NULL; } else if ( ret->type == 0x0 ) { - ret->lval = atoi(_tokenize(expbuf, BASIC_TOKENIZER_TOKENS)); - ret->lval_type = BASIC_LVAL_CONST; - flags = (flags + BASIC_FOUND_LVAL); + expbuf = _tokenize(expbuf, BASIC_TOKENIZER_TOKENS); + ret->lval.i = atoi(_token_get()); + ret->lval_type = BASIC_LVAL_CONST; + flags = (flags + BASIC_FOUND_LVAL); } else if ( ret->type != 0x0 && ((flags & BASIC_FOUND_RVAL) == BASIC_FOUND_RVAL)) { - basic_errno = BASIC_ERR_SYNTAX_MULTIPLE_RVALUES; - return NULL; + basic_errno = BASIC_ERR_SYNTAX_MULTIPLE_RVALUES; + return NULL; } else if ( ret->type != 0x0 ) { - ret->rval = atoi(_tokenize(expbuf, BASIC_TOKENIZER_TOKENS)); - ret->rval_type = BASIC_RVAL_CONST; + expbuf = _tokenize(expbuf, BASIC_TOKENIZER_TOKENS); + ret->rval.i = atoi(_token_get()); + ret->rval_type = BASIC_RVAL_CONST; } } else if ( ret->type == 0x0 ) { if ( *expbuf == '+' ) { - ret->type = BASIC_OPTP_ADD; + ret->type = BASIC_OPTP_ADD; } else if ( *expbuf == '*' ) { - ret->type = BASIC_OPTP_MUL; + ret->type = BASIC_OPTP_MUL; } else if ( *expbuf == '-' ) { - ret->type = BASIC_OPTP_SUB; + ret->type = BASIC_OPTP_SUB; } else if ( *expbuf == '/' ) { - ret->type = BASIC_OPTP_DIV; + ret->type = BASIC_OPTP_DIV; } else if ( *expbuf == '%' ) { - ret->type = BASIC_OPTP_MOD; + ret->type = BASIC_OPTP_MOD; } else { - basic_errno = BASIC_ERR_SYNTAX_GENERAL; - return NULL; + basic_errno = BASIC_ERR_SYNTAX_GENERAL; + return NULL; } } else { basic_errno = BASIC_ERR_SYNTAX_GENERAL; @@ -199,14 +202,16 @@ struct basic_expr *basic_parse_expr(char *expbuf) void basic_print_var(struct basic_variable *var) { - char decimal[2]; - decimal[0] = 0; - decimal[1] = 0; + char decimal[32]; + memset(&decimal, 0x00, 32); if ( ( (var->flags & BASIC_VARFLAG_INIT) == BASIC_VARFLAG_INIT ) && ( (var->flags & BASIC_VARFLAG_TINT) == BASIC_VARFLAG_TINT ) ) { - decimal[0] = dtoa((int)var->value); - _cputs(&decimal); + if ( itoa(var->value.i, (char *)&decimal) == 1 ) { + _cputs((char *)&decimal); + } else { + _cputs("ERROR Unable to convert decimal to integer"); + } _cputs("\n"); } } @@ -241,23 +246,23 @@ void basic_repl(void) expr = basic_parse_expr((char *)&keybuff); if ( expr == NULL ) { - _cputs("Error: "); - decimal[0] = dtoa(basic_errno); - _cputs(&decimal); - _cputs("\n"); - basic_errno = 0; - continue; + _cputs("Error: "); + decimal[0] = dtoa(basic_errno); + _cputs((char *)&decimal); + _cputs("\n"); + basic_errno = 0; + continue; } /* Evaluate */ basic_solve_expr(expr, &result); if ( basic_errno != 0 ) { - _cputs("Error: "); - decimal[0] = dtoa(basic_errno); - _cputs(&decimal); - _cputs("\n"); + _cputs("Error: "); + decimal[0] = dtoa(basic_errno); + _cputs((char *)&decimal); + _cputs("\n"); } else { - basic_print_var(&result); + basic_print_var(&result); } } } diff --git a/src/basic.h b/src/basic.h index 6ee9e28..02b665e 100644 --- a/src/basic.h +++ b/src/basic.h @@ -34,14 +34,27 @@ #define BASIC_TOKENIZER_MAX_LENGTH 512 #define BASIC_VARNAME_MAX_LENGTH 16 +union basic_value { + char c; + int i; + unsigned int uint; + /* we don't handle floats yet. need to implement Fcomp, fpushf, fpushd. + * float f; + */ + char *str; + void *ptr; +}; +typedef union basic_value basic_value; + struct basic_expr { char type; char lval_type; char rval_type; char pad; - void *lval; - void *rval; + basic_value lval; + basic_value rval; }; +typedef struct basic_expr basic_expr; #define BASIC_VARFLAG_INIT 1 #define BASIC_VARFLAG_TINT 2 @@ -50,8 +63,9 @@ struct basic_expr { struct basic_variable { char *name; char flags; - void *value; + basic_value value; }; +typedef struct basic_variable basic_variable; #define BASIC_CONST_TRUE 1 #define BASIC_CONST_FALSE 0 diff --git a/src/conio.c b/src/conio.c index ce54002..3dc8c1c 100644 --- a/src/conio.c +++ b/src/conio.c @@ -2,8 +2,13 @@ #include "conio.h" #include "screen.h" +#ifdef __GNUC__ +#include +#endif + void _putch(char c) { +#ifndef __GNUC__ #asm push bx; push ax; @@ -17,6 +22,9 @@ void _putch(char c) pop bx; #endasm return; +#else + putc(c, stdout); +#endif } void _cputs(char *ptr) @@ -40,6 +48,7 @@ void _cputs(char *ptr) char _getkey(char *dest) { +#ifndef __GNUC__ char echo; char scancode; #asm @@ -52,6 +61,9 @@ char _getkey(char *dest) #endasm *dest = echo; return scancode; +#else + return getc(stdin); +#endif } char *_cgets(char *d) @@ -66,7 +78,7 @@ char *_cgets(char *d) scancode = _getkey(&printable); - while ( scancode != NULL ) { + while ( scancode != 0 ) { if ( scancode == 0x0e ) { if ( d > orig ) { backupCursor(); @@ -84,7 +96,7 @@ char *_cgets(char *d) scancode = _getkey(&printable); } - __cgets_finish_loop: - *d = NULL; + /*__cgets_finish_loop:*/ + *d = 0; return orig; } diff --git a/src/conio.h b/src/conio.h index 4cefb96..fdb940a 100644 --- a/src/conio.h +++ b/src/conio.h @@ -2,7 +2,8 @@ #define _CONIO_H_ void _putch(char _c); -char *_cgets(void); +char *_cgets(char *d); +void _cputs(char *d); char _getkey(char *dest); #endif /* _CONIO_H_ */ diff --git a/src/screen.c b/src/screen.c index acb76ec..f018150 100644 --- a/src/screen.c +++ b/src/screen.c @@ -1,5 +1,6 @@ #include "types.h" #include "screen.h" +#include "conio.h" char _cursor_x = 0; char _cursor_y = 0; @@ -18,6 +19,7 @@ void blankScreen(void) void setCursorPosition(char x, char y) { +#ifndef __GNUC__ #asm push bx; mov bx, sp; @@ -33,6 +35,7 @@ void setCursorPosition(char x, char y) pop ax; #endasm return; +#endif } void backupCursor() diff --git a/src/stdlib.c b/src/stdlib.c index fd361db..9719bf7 100644 --- a/src/stdlib.c +++ b/src/stdlib.c @@ -1,6 +1,61 @@ #include "types.h" #include "stdlib.h" +int imod(int dividend, int divisor) +{ + if ( divisor == 0 ) { + return 0; + } + return dividend - (divisor * (dividend / divisor)); +} + +int itoa(int num, char *buff) +{ + char tmpbuff[32]; + char *rptr = NULL; + int i = 0; + char negative = 0; + + if ( buff == NULL ) { + return 0; + } + + if ( num < 0 ) { + negative = 1; + num = -num; + } + + /* actual integer to ascii conversion, but it's in reverse */ + do { + *(buff + i) = dtoa(imod(num, 10)); + num /= 10; + i += 1; + } while ( num > 0 ); + + if ( negative == 1 ){ + *(buff + i++) = '-'; + } + + /* reverse the string into the temporary buffer */ + rptr = (buff + i - 1); + for ( i = 0; rptr >= buff; i += 1 ) { + tmpbuff[i] = *rptr; + rptr -= 1; + } + tmpbuff[i] = 0x00; + + /* Copy the temporary buffer back into the actual target */ + rptr = (char *)&tmpbuff; + while ( *rptr != 0x00 ) { + *buff = *rptr; + buff += 1; + rptr += 1; + } + /* Null terminate the new string */ + *buff = 0x00; + return 1; +} + char dtoa(int d) { switch (d) { @@ -15,7 +70,7 @@ char dtoa(int d) case 8: return '8'; break; case 9: return '9'; break; } - return NULL; + return 0; } int atoi(char *nptr) @@ -30,6 +85,9 @@ int atoi(char *nptr) while ( isdigit(*ptr) == 1 ) { ptr += 1; } + if ( ptr == nptr ) { + return 0; + } ptr -= 1; while ( ptr >= nptr) { value += (((int)(*ptr--) - 0x30) * multiplier); diff --git a/src/stdlib.h b/src/stdlib.h index 0ace533..0f9c9c3 100644 --- a/src/stdlib.h +++ b/src/stdlib.h @@ -1,7 +1,9 @@ #ifndef _STDLIB_H_ #define _STDLIB_H_ +int imod(int dividend, int divisor); char dtoa(int d); +int itoa(int d, char *buff); int atoi(char *nptr); int isdigit(int c); int isupper(int c); diff --git a/src/string.c b/src/string.c index f08b742..aedcef5 100644 --- a/src/string.c +++ b/src/string.c @@ -15,15 +15,15 @@ size_t strlen(char *ptr) return ptr2 - ptr; } -void *memset(void *s, int c, size_t n) +void *memset(void *s, char c, size_t n) { - int *d = (int *)s; + char *d = (char *)s; if ( s == NULL ) { return NULL; } - while ( (d - (int *)s) <= n ) { + while ( (d - (char *)s) < n ) { *d = c; - d += sizeof(int); + d += sizeof(char); } return s; } @@ -31,16 +31,17 @@ void *memset(void *s, int c, size_t n) void *memcpy(void *dest, void *src, size_t n) { int i = 0; - char *d = dest; - char *s = src; + char *d = (char *)dest; + char *s = (char *)src; if ( d == NULL || s == NULL ) { return NULL; } for ( i = 0 ; i < n ; i++ ) { - *d++ = *s++; + *d = *s; + d += 1; + s += 1; } - *d = '\0'; return dest; } diff --git a/src/string.h b/src/string.h index 0f45dbb..1bae3b7 100644 --- a/src/string.h +++ b/src/string.h @@ -5,7 +5,7 @@ size_t strlen(char *ptr); int strncat(char *dest, char *src, size_t n); -void *memset(void *s, int c, size_t n); +void *memset(void *s, char c, size_t n); void *memcpy(void *dest, void *src, size_t n); int strcmp(char *s1, char *s2); diff --git a/src/types.h b/src/types.h index 8d2cf30..ca7a6b8 100644 --- a/src/types.h +++ b/src/types.h @@ -2,6 +2,10 @@ #define _TYPES_H_ #define NULL 0x0 +#ifndef __GNUC__ typedef int size_t; +#else +#include +#endif #endif /* _TYPES_H_ */ diff --git a/tests/Makefile b/tests/Makefile index 4e239f4..0ea0b03 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,4 +1,4 @@ -CFLAGS:=-ffreestanding -fno-builtin -I../src -ansi -Wall -Werror +CFLAGS:=-g3 -ffreestanding -fno-builtin -I../src -ansi -Wall -Werror %.o: %.c gcc $(CFLAGS) -c -o $@ $< diff --git a/tests/basic_tokenizer.c b/tests/basic_tokenizer.c new file mode 100644 index 0000000..8c9d4d1 --- /dev/null +++ b/tests/basic_tokenizer.c @@ -0,0 +1,29 @@ +#include "basic.h" +#include "stdlib.h" +#include "string.h" +#include + +char *_tokenize(char *ptr, char *token); +char *_token_get(void); + +#define assert_lvalue(str, lval, ret_null, ret_neq) \ + ptr = _tokenize(str, BASIC_TOKENIZER_TOKENS); \ + value = _token_get(); \ + if ( ptr == NULL ) return ret_null; \ + rc = strcmp(value, lval); \ + printf("(value) == (lval) ? : (%s) == (%s) %d\n", value, lval, rc); \ + if ( rc != 0 ) return ret_neq; + + +int main(void) +{ + char *ptr = NULL; + char *value = NULL; + int rc = 0; + + assert_lvalue("1+1", "1", 1, 2); + assert_lvalue("1 + 1", "1", 2, 3); + assert_lvalue("10 + 10", "10", 4, 5); + + return 0; +} \ No newline at end of file diff --git a/tests/basic_tokenizer.deps b/tests/basic_tokenizer.deps new file mode 100644 index 0000000..1f29ad1 --- /dev/null +++ b/tests/basic_tokenizer.deps @@ -0,0 +1,5 @@ +basic +stdlib +string +conio +screen diff --git a/tests/stdlib_atoi.c b/tests/stdlib_atoi.c index 0aecf16..3cc65e4 100644 --- a/tests/stdlib_atoi.c +++ b/tests/stdlib_atoi.c @@ -1,11 +1,10 @@ +#include "types.h" #include "stdlib.h" -#define NULL 0x00 - int main(void) { if ( atoi("1234\0") != 1234 ) return 1; if ( atoi("65536\0") != 65536 ) return 2; - if ( atoi("-32767\0") != -32767 ) return 3; + if ( atoi("-32767\0") != 0 ) return 3; return 0; } diff --git a/tests/stdlib_imod.c b/tests/stdlib_imod.c new file mode 100644 index 0000000..32e2e10 --- /dev/null +++ b/tests/stdlib_imod.c @@ -0,0 +1,10 @@ +#include "types.h" +#include "stdlib.h" +#include "string.h" + +int main(void) +{ + if ( imod(12, 10) != 2 ) return 1; + if ( imod(1234, 10) != 4 ) return 2; + return 0; +} diff --git a/tests/stdlib_imod.deps b/tests/stdlib_imod.deps new file mode 100644 index 0000000..8bd7a9e --- /dev/null +++ b/tests/stdlib_imod.deps @@ -0,0 +1,2 @@ +stdlib +string \ No newline at end of file diff --git a/tests/stdlib_itoa.c b/tests/stdlib_itoa.c new file mode 100644 index 0000000..0ab6bb4 --- /dev/null +++ b/tests/stdlib_itoa.c @@ -0,0 +1,16 @@ +#include "types.h" +#include "stdlib.h" +#include "string.h" +#include + +int main(void) +{ + char buff[32]; + if ( itoa(1234, (char *)&buff) != 1 ) return 1; + if ( strcmp((char *)&buff, "1234") != 0 ) return 2; + if ( itoa(65536, (char *)&buff) != 1 ) return 3; + if ( strcmp((char *)&buff, "65536") != 0 ) return 4; + if ( itoa(-32767, (char *)&buff) != 1 ) return 5; + if ( strcmp((char *)&buff, "-32767") != 0 ) return 6; + return 0; +} diff --git a/tests/stdlib_itoa.deps b/tests/stdlib_itoa.deps new file mode 100644 index 0000000..8bd7a9e --- /dev/null +++ b/tests/stdlib_itoa.deps @@ -0,0 +1,2 @@ +stdlib +string \ No newline at end of file