├── .gitignore
├── LICENSE
├── Makefile
├── Makefile.xmega
├── README.md
├── Windows
├── BASIC.sln
├── BASIC.vcxproj
├── BASIC.vcxproj.filters
└── BASIC.vcxproj.user
├── arch
├── osx
│ ├── arch.c
│ ├── error.c
│ ├── kbhit.c
│ └── main.c
├── windows
│ ├── arch.c
│ ├── error.c
│ ├── kbhit.c
│ └── main.c
└── xmega
│ ├── arch.c
│ ├── console.c
│ ├── console.h
│ ├── diskio.h
│ ├── error.c
│ ├── ext.c
│ ├── ff.c
│ ├── ff.h
│ ├── ffconf.h
│ ├── integer.h
│ ├── joystick.c
│ ├── joystick.h
│ ├── kbhit.c
│ ├── main.c
│ ├── mmc.c
│ ├── mmc.h
│ ├── sound.c
│ ├── sound.h
│ ├── spi.c
│ └── spi.h
├── basic.png
├── examples
├── FORY.bas
├── autolist
├── circle.bas
├── data.bas
├── data_array.bas
├── data_numeric.bas
├── data_test.bas
├── diamond.bas
├── dim.bas
├── expr.bas
├── for.bas
├── for_colon.bas
├── get.bas
├── gosub.bas
├── goto.bas
├── if.bas
├── if_and_or.bas
├── if_goto.bas
├── input.bas
├── left.bas
├── math.bas
├── mid.bas
├── nested_for.bas
├── on_goto.bas
├── right.bas
├── simple-basic
│ ├── happy_birthday.bas
│ └── input.bas
├── sine_wave.bas
├── sleep.bas
├── strings.bas
├── test_for.bas
├── the_first_basic_program.bas
├── toss_a_coin.bas
└── var.bas
├── include
├── arch.h
├── array.h
├── callback.h
├── dictionary.h
├── error.h
├── hexdump.h
├── io.h
├── kbhit.h
├── lines.h
├── parser.h
├── tokenizer.h
├── usingwin.h
└── variables.h
├── src
├── array.c
├── dictionary.c
├── hexdump.c
├── io.c
├── lines.c
├── parser.c
├── tokenizer.c
└── variables.c
├── t
├── Makefile
├── main.c
├── test.h
├── test_dictionary.c
└── test_lines.c
└── test
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | profile
3 | build/*
4 | *.mode1
5 | *.mode1v3
6 | *.mode2v3
7 | *.perspective
8 | *.perspectivev3
9 | *.pbxuser
10 | *.xcworkspace
11 | xcuserdata
12 | .svn
13 | CVS
14 | *.swp
15 | *.o
16 | t/test
17 | TODO
18 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Johan Van den Brande
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | TARGET = basic
2 |
3 | BUILD_FOLDER = build/basic
4 |
5 | SOURCE_FOLDERS += ./arch/osx ./src
6 |
7 | CC = gcc-10
8 | CFLAGS = -g -Wall -Werror -std=c99 -lreadline -lm -DARCH_OSX=1 -DARCH_XMEGA=2 -DARCH=1
9 |
10 | VPATH = $(SOURCE_FOLDERS)
11 |
12 | .PHONY: start end all clean run
13 |
14 | all: start $(BUILD_FOLDER) $(TARGET) end
15 |
16 | SOURCES = $(foreach folder,$(SOURCE_FOLDERS),$(wildcard $(folder)/*.c))
17 |
18 | ifneq "$(strip $(SOURCES))" ""
19 | _OBJECTS = $(patsubst %.c,%.o,$(notdir $(SOURCES)))
20 | endif
21 |
22 | OBJECTS = $(patsubst %,$(BUILD_FOLDER)/%,$(_OBJECTS))
23 |
24 | INCLUDE_FLAGS += \
25 | $(addprefix -I,$(INCLUDE_FOLDERS)) $(addprefix -I,$(SOURCE_FOLDERS)) -Iinclude
26 |
27 | define run-cc
28 | @ echo "CC $<"
29 | @ $(CC) -c $(CFLAGS) $(INCLUDE_FLAGS) $< -o $(BUILD_FOLDER)/$%
30 | endef
31 |
32 | start:
33 | @ echo "-- Creating $(TARGET)..."
34 |
35 | end:
36 | @ echo "done"
37 | @ echo ""
38 |
39 | clean:
40 | @ echo $@
41 | @ rm -rf $(BUILD_FOLDER)
42 | @ make -C ./t clean
43 |
44 | $(BUILD_FOLDER):
45 | @ mkdir -p $@
46 |
47 | (%.o): %.c
48 | $(run-cc)
49 |
50 | $(TARGET): $(BUILD_FOLDER)/($(_OBJECTS))
51 | @ echo "LD $@"
52 | @ $(CC) $(OBJECTS) $(CFLAGS) $(LDFLAGS) -L$(BUILD_FOLDER) -o $(BUILD_FOLDER)/$@
53 |
54 | run: all
55 | @ echo "-- Running $(TARGET)"
56 | @ BASIC_PATH=./examples $(BUILD_FOLDER)/$(TARGET)
57 |
58 | test: all
59 | @ make -C ./t run
60 |
61 | testdebug: all
62 | @ make -C ./t debug
63 |
64 | debug: all
65 | @ echo "-- Debugging $(TARGET)"
66 | @ echo "run" | gdb $(BUILD_FOLDER)/$(TARGET)
67 |
--------------------------------------------------------------------------------
/Makefile.xmega:
--------------------------------------------------------------------------------
1 | ARCH = XMEGA
2 |
3 | DEVICE = atxmega128a4u
4 | CLOCK = 32000000
5 |
6 | TARGET = basic
7 |
8 | BUILD_FOLDER = build/xmega
9 |
10 | SOURCE_FOLDERS += ./arch/xmega ./src
11 |
12 | CC = avr-gcc
13 | CFLAGS = -g -Wall -Werror -std=c99 -Os
14 | CFLAGS += -DF_CPU=$(CLOCK) -mmcu=$(DEVICE) -DARCH_OSX=1 -DARCH_XMEGA=2 -DARCH=2
15 | CFLAGS += -DBASIC_READLINE_ECHO
16 | CFLAGS += -Wl,-u,vfscanf -lscanf_flt -Wl,-u,vfprintf -lprintf_flt -lm
17 |
18 | VPATH = $(SOURCE_FOLDERS)
19 |
20 | .PHONY: start end all clean run
21 |
22 | all: start $(BUILD_FOLDER) $(TARGET) end
23 |
24 | SOURCES = $(foreach folder,$(SOURCE_FOLDERS),$(wildcard $(folder)/*.c))
25 |
26 | ifneq "$(strip $(SOURCES))" ""
27 | _OBJECTS = $(patsubst %.c,%.o,$(notdir $(SOURCES)))
28 | endif
29 |
30 | OBJECTS = $(patsubst %,$(BUILD_FOLDER)/%,$(_OBJECTS))
31 |
32 | INCLUDE_FLAGS += \
33 | $(addprefix -I,$(INCLUDE_FOLDERS)) $(addprefix -I,$(SOURCE_FOLDERS)) -Iinclude
34 |
35 | define run-cc
36 | @ echo "CC $<"
37 | @ $(CC) -c $(CFLAGS) $(INCLUDE_FLAGS) $< -o $(BUILD_FOLDER)/$%
38 | endef
39 |
40 | start:
41 | @ echo "-- Creating $(TARGET)..."
42 |
43 | end:
44 | @ echo "done"
45 | @ echo ""
46 |
47 | clean:
48 | @ echo $@
49 | @ rm -rf $(BUILD_FOLDER)
50 | @ make -C ./t clean
51 |
52 | $(BUILD_FOLDER):
53 | @ mkdir -p $@
54 |
55 | (%.o): %.c
56 | $(run-cc)
57 |
58 | $(TARGET): $(BUILD_FOLDER)/($(_OBJECTS))
59 | @ echo "LD $@"
60 | @ $(CC) $(OBJECTS) $(CFLAGS) $(LDFLAGS) -L$(BUILD_FOLDER) -o $(BUILD_FOLDER)/$@
61 | @ avr-objcopy -j .text -j .data -O ihex $(BUILD_FOLDER)/$@ $(BUILD_FOLDER)/$(TARGET).hex
62 | @ avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O ihex $(BUILD_FOLDER)/$@ $(BUILD_FOLDER)/$(TARGET)_eeprom.hex
63 |
64 | flash: all
65 | @ dfu-programmer $(DEVICE) erase
66 | @ dfu-programmer $(DEVICE) flash $(BUILD_FOLDER)/$(TARGET).hex
67 | @ dfu-programmer $(DEVICE) launch
68 |
69 | launch:
70 | @ dfu-programmer $(DEVICE) launch
71 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | A from-scratch BASIC interpreter with a focus on being easy to extend and port.
4 |
5 | [](https://asciinema.org/a/37018)
6 |
7 | # Introduction
8 |
9 | This is a BASIC interpreter written from scratch in C. For the moment two architectures are supported, POSIX and AVR XMega via the avr-gcc toolchain.
10 |
11 | Most of the common BASIC keywords are supported:
12 |
13 | * PRINT expression-list [ ; ]
14 | * IF relation-expression THEN statement
15 | * GOTO expression
16 | * INPUT variable-list
17 | * LET variable = expression
18 | * GOSUB expression
19 | * RETURN
20 | * FOR numeric\_variable '=' numeric\_expression TO numeric_expression [ STEP number ]
21 | * CLEAR, NEW
22 | * LIST
23 | * RUN
24 | * END
25 | * DIM variable "(" expression ")"
26 | * ABS, AND, ATN, COS, EXP, INT, LOG, NOT, OR, RND, SGN, SIN, SQR, TAN
27 | * LEN, CHR$, MID$, LEFT$, RIGHT$, ASC
28 |
29 | # Extend
30 |
31 | It should be easy to register a new BASIC function, as shown here with a `sleep` function for the XMEGA.
32 |
33 | ```C
34 | register_function_1(basic_function_type_keyword, "SLEEP", do_sleep, kind_numeric);
35 | ...
36 | int do_sleep(basic_type* delay, basic_type* rv)
37 | {
38 | delay_ms(delay->value.number);
39 |
40 | rv->kind = kind_numeric;
41 | rv->value.number = 0;
42 |
43 | return 0;
44 | }
45 | ```
46 |
47 | Let's use that new keyword.
48 |
49 | ```REALbasic
50 | 10 INPUT "YOUR NAME?", NAME$
51 | 20 CLS
52 | 30 FOR I=1 TO LEN(NAME$)
53 | 40 PRINT MID$(NAME$,I,1);
54 | 50 SLEEP(500)
55 | 60 NEXT
56 | 70 PRINT
57 | ```
58 |
59 | # Port
60 |
61 | It should be easy to port the interpreter to other architectures. As an example there is a port to an XMega 128A4U included using the [Batsocks breadmate board](http://www.batsocks.co.uk/products/BreadMate/XMega%20PDI%20AV.htm).
62 |
63 | # Use
64 |
65 | There is a simple REPL for the BASIC interpreter. You can use it in an interactive way, just as you would do on a 80's era computer.
66 |
67 | ```
68 | _ _
69 | | |__ __ _ ___(_) ___
70 | | '_ \ / _` / __| |/ __|
71 | | |_) | (_| \__ \ | (__
72 | |_.__/ \__,_|___/_|\___|
73 | (c) 2015-2016 Johan Van den Brande
74 | 10 PRINT "HELLO"
75 | 20 GOTO 10
76 | ```
77 |
78 | You can give it a BASIC file on the command line.
79 |
80 | ```
81 | $> basic examples/diamond.bas
82 | *
83 | ***
84 | *****
85 | *******
86 | *********
87 | ***********
88 | *************
89 | ***************
90 | *****************
91 | ***************
92 | *************
93 | ***********
94 | *********
95 | *******
96 | *****
97 | ***
98 | *
99 | ```
100 |
101 | You can also use the shebang operator to make standalone BASIC scripts
102 |
103 | ```
104 | #!/usr/bin/env basic
105 |
106 | 10 RADIUS=10
107 | 20 FOR I=1 TO RADIUS-1
108 | 30 W=INT(RADIUS*SIN(180/RADIUS*I*3.1415/180))
109 | 40 PRINT SPC(RADIUS-W);:FOR J=1 TO 2*W:PRINT "*";:NEXT J:PRINT
110 | 50 NEXT I
111 | ```
112 |
113 | ```
114 | $> ./examples/circle.bas
115 | ******
116 | **********
117 | ****************
118 | ******************
119 | ********************
120 | ******************
121 | ****************
122 | **********
123 | ******
124 | ```
125 |
126 | It is easy to embed the interpreter into your own application.
127 |
128 | ```C
129 | basic_init(2048, 512); // memory size, stack size
130 | basic_register_io(putchar, getchar);
131 | basic_eval("10 PRINT \"HELLO\"");
132 | basic_eval("RUN");
133 | basic_destroy();
134 | ```
135 |
136 | On OSX/POSIX you can use the 'BASIC\_PATH' environment variable to set the folder used for loading and saving BASIC programs. The 'BASIC\_PATH' defaults to '.'.
137 | BASIC programs are expected to end with '.bas'. You can use LOAD, SAVE, DELETE and DIR.
138 |
139 | # Copyright
140 |
141 | (c) 2015 - 2016 Johan Van den Brande
142 |
--------------------------------------------------------------------------------
/Windows/BASIC.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30611.23
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BASIC", "BASIC.vcxproj", "{EBBF5532-8DA0-4B71-9EF7-89C7824F88D8}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {EBBF5532-8DA0-4B71-9EF7-89C7824F88D8}.Debug|x64.ActiveCfg = Debug|x64
17 | {EBBF5532-8DA0-4B71-9EF7-89C7824F88D8}.Debug|x64.Build.0 = Debug|x64
18 | {EBBF5532-8DA0-4B71-9EF7-89C7824F88D8}.Debug|x86.ActiveCfg = Debug|Win32
19 | {EBBF5532-8DA0-4B71-9EF7-89C7824F88D8}.Debug|x86.Build.0 = Debug|Win32
20 | {EBBF5532-8DA0-4B71-9EF7-89C7824F88D8}.Release|x64.ActiveCfg = Release|x64
21 | {EBBF5532-8DA0-4B71-9EF7-89C7824F88D8}.Release|x64.Build.0 = Release|x64
22 | {EBBF5532-8DA0-4B71-9EF7-89C7824F88D8}.Release|x86.ActiveCfg = Release|Win32
23 | {EBBF5532-8DA0-4B71-9EF7-89C7824F88D8}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {6C82D241-BA84-4707-A390-675647BE8056}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/Windows/BASIC.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 16.0
23 | Win32Proj
24 | {ebbf5532-8da0-4b71-9ef7-89c7824f88d8}
25 | BASIC
26 | 10.0
27 |
28 |
29 |
30 | Application
31 | true
32 | v142
33 | Unicode
34 |
35 |
36 | Application
37 | false
38 | v142
39 | true
40 | Unicode
41 |
42 |
43 | Application
44 | true
45 | v142
46 | Unicode
47 |
48 |
49 | Application
50 | false
51 | v142
52 | true
53 | Unicode
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | true
75 |
76 |
77 | false
78 |
79 |
80 | true
81 |
82 |
83 | false
84 |
85 |
86 |
87 | Level3
88 | true
89 | WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
90 | true
91 | ../include
92 | CompileAsC
93 |
94 |
95 | Console
96 | true
97 |
98 |
99 |
100 |
101 | Level3
102 | true
103 | true
104 | true
105 | WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
106 | true
107 | ../include
108 |
109 |
110 | Console
111 | true
112 | true
113 | true
114 |
115 |
116 |
117 |
118 | Level3
119 | true
120 | _DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
121 | true
122 | ../include
123 |
124 |
125 | Console
126 | true
127 |
128 |
129 |
130 |
131 | Level3
132 | true
133 | true
134 | true
135 | NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
136 | true
137 | ../include
138 |
139 |
140 | Console
141 | true
142 | true
143 | true
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
--------------------------------------------------------------------------------
/Windows/BASIC.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 | Source Files
23 |
24 |
25 | Source Files
26 |
27 |
28 | Source Files
29 |
30 |
31 | Source Files
32 |
33 |
34 | Source Files
35 |
36 |
37 | Source Files
38 |
39 |
40 | Source Files
41 |
42 |
43 | Source Files
44 |
45 |
46 | Source Files
47 |
48 |
49 | Source Files
50 |
51 |
52 | Source Files
53 |
54 |
55 |
--------------------------------------------------------------------------------
/Windows/BASIC.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/arch/osx/arch.c:
--------------------------------------------------------------------------------
1 | #define _GNU_SOURCE
2 | #include "arch.h"
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | int
10 | arch_init(void)
11 | {
12 | // stub
13 | return 0;
14 | }
15 |
16 | static char*
17 | _get_path(void)
18 | {
19 | static char* _path = NULL;
20 | _path = getenv("BASIC_PATH");
21 | if (_path == NULL) {
22 | _path = ".";
23 | }
24 | if(_path[strlen(_path)-1] == '/'){
25 | _path[strlen(_path)-1] = '\0';
26 | }
27 | return _path;
28 | }
29 |
30 | int
31 | arch_load(char* name, arch_load_out_cb cb, void* context)
32 | {
33 | char* filename;
34 | asprintf(&filename, "%s/%s.bas", _get_path(), name);
35 | FILE* fp = fopen(filename, "r");
36 | if(!fp){
37 | return 1;
38 | }
39 | char line[256];
40 | while(fgets(line, 256, fp) != NULL) {
41 | cb(line, context);
42 | }
43 | fclose(fp);
44 | free(filename);
45 | return 0;
46 | }
47 |
48 | int
49 | arch_save(char* name, arch_save_cb cb, void* context)
50 | {
51 | char* line;
52 | char* filename;
53 | asprintf(&filename, "%s/%s.bas", _get_path(), name);
54 |
55 | FILE* fp = fopen(filename, "w");
56 | if(!fp){
57 | return 1;
58 | }
59 | for(;;){
60 | uint16_t number = cb(&line, context);
61 | if (line == NULL){
62 | break;
63 | }
64 | fprintf(fp, "%d %s\n",number, line);
65 | }
66 | fclose(fp);
67 |
68 | free(filename);
69 |
70 | return 0;
71 | }
72 |
73 | int
74 | arch_dir(arch_dir_out_cb cb, void* context)
75 | {
76 | char out[256];
77 | snprintf(out, sizeof(out), "dir: %s", _get_path());
78 | cb(out, 0, true, context);
79 |
80 | struct stat stats;
81 | struct dirent *ent;
82 | DIR *dir;
83 | dir = opendir(_get_path());
84 | while ((ent = readdir(dir)) != NULL) {
85 | char* name = ent->d_name;
86 | if (strlen(name)>4){
87 | char *ext = name + strlen(name) - 4;
88 | if (strncmp(ext, ".bas", 4)==0){
89 | snprintf(out,sizeof(out),"%s/%s", _get_path(), name);
90 | stat(out, &stats);
91 | name[strlen(name)-4] = '\0';
92 | cb(name, stats.st_size, false, context);
93 | }
94 | }
95 | }
96 | closedir(dir);
97 |
98 | return 0;
99 | }
100 |
101 | int
102 | arch_delete(char* name){
103 | char* filename;
104 | asprintf(&filename, "%s/%s.bas", _get_path(), name);
105 | remove(filename);
106 | free(filename);
107 | return 0;
108 | }
109 |
110 |
111 |
--------------------------------------------------------------------------------
/arch/osx/error.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | // or inttypes.h
6 |
7 | extern uint16_t __line;
8 |
9 | const char *last_error = NULL;
10 |
11 | void
12 | error(const char *error_msg)
13 | {
14 | void *array[10];
15 | size_t size;
16 | char **strings;
17 | size_t i;
18 |
19 | last_error = error_msg;
20 |
21 | printf("--- ERROR: %d %s\n", __line, error_msg);
22 |
23 | size = backtrace (array, 10);
24 | strings = backtrace_symbols (array, size);
25 |
26 | printf ("SHOW %zd STACK FRAMES:\n", size);
27 |
28 | for (i = 0; i < size; i++)
29 | {
30 | printf (" %s\n", strings[i]);
31 | }
32 |
33 | free (strings);
34 | }
35 |
--------------------------------------------------------------------------------
/arch/osx/kbhit.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | int kbhit(void) {
8 | static const int STDIN = 0;
9 | static bool initialized = false;
10 |
11 | if (! initialized) {
12 | // Use termios to turn off line buffering
13 | struct termios term;
14 | tcgetattr(STDIN, &term);
15 | term.c_lflag &= ~ICANON;
16 | tcsetattr(STDIN, TCSANOW, &term);
17 | setbuf(stdin, NULL);
18 | initialized = true;
19 | }
20 |
21 | int bytesWaiting;
22 | ioctl(STDIN, FIONREAD, &bytesWaiting);
23 | return bytesWaiting;
24 | }
25 |
--------------------------------------------------------------------------------
/arch/osx/main.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include "parser.h"
10 |
11 | extern bool __RUNNING;
12 | extern bool __STOPPED;
13 |
14 | static void
15 | sigint_handler(int signum)
16 | {
17 | signal(SIGINT, sigint_handler);
18 | if(__RUNNING){
19 | __RUNNING = false;
20 | __STOPPED = true;
21 | printf("STOP\n");
22 | fflush(stdout);
23 | }
24 | }
25 |
26 | static char *
27 | readline_gets ()
28 | {
29 | char * line_read = readline ("");
30 |
31 | if (line_read && *line_read) {
32 | add_history (line_read);
33 | }
34 |
35 | return line_read;
36 | }
37 |
38 | int out(int ch)
39 | {
40 | putchar(ch);
41 | return 1;
42 | }
43 |
44 | int in(void)
45 | {
46 | return getchar();
47 | }
48 |
49 | void repl(void)
50 | {
51 | puts(" _ _ ");
52 | puts("| |__ __ _ ___(_) ___ ");
53 | puts("| '_ \\ / _` / __| |/ __|");
54 | puts("| |_) | (_| \\__ \\ | (__ ");
55 | puts("|_.__/ \\__,_|___/_|\\___|");
56 | puts("(c) 2015-2016 Johan Van den Brande");
57 |
58 | using_history();
59 |
60 | char *input;
61 | while ((input = readline_gets()) != NULL )
62 | {
63 | if (strcmp(input, "QUIT") == 0) {
64 | free(input);
65 | break;
66 | }
67 |
68 | basic_eval(input);
69 |
70 | if (evaluate_last_error()) {
71 | printf("ERROR: %s\n", evaluate_last_error());
72 | clear_last_error();
73 | }
74 |
75 | free(input);
76 | }
77 |
78 | clear_history();
79 | }
80 |
81 | void run(char *file_name){
82 | FILE* file = fopen(file_name, "r");
83 |
84 | if (file == NULL) {
85 | fprintf(stderr, "Can't open %s\n", file_name);
86 | return;
87 | }
88 |
89 | char line[tokenizer_string_length];
90 | while (fgets(line, sizeof(line), file)) {
91 | if(line[strlen(line)-1]!='\n')
92 | {
93 | printf("ERROR: NO EOL\n");
94 | exit(1);
95 | }
96 | basic_eval(line);
97 | }
98 | fclose(file);
99 |
100 | basic_run();
101 | }
102 |
103 | int main(int argc, char *argv[])
104 | {
105 | signal(SIGINT, sigint_handler);
106 |
107 | basic_init(1024*8, 2048);
108 | basic_register_io(out, in);
109 |
110 | if (argc > 1){
111 | run(argv[1]);
112 | } else {
113 | repl();
114 | }
115 |
116 | basic_destroy();
117 |
118 | return EXIT_SUCCESS;
119 | }
120 |
--------------------------------------------------------------------------------
/arch/windows/arch.c:
--------------------------------------------------------------------------------
1 | #define _GNU_SOURCE
2 | #include "arch.h"
3 | #include
4 | #include
5 | #include
6 | //#include
7 | #include
8 |
9 | int
10 | arch_init(void)
11 | {
12 | // stub
13 | return 0;
14 | }
15 |
16 | static char*
17 | _get_path(void)
18 | {
19 | static char* _path = NULL;
20 | _path = getenv("BASIC_PATH");
21 | if (_path == NULL) {
22 | _path = ".";
23 | }
24 | if(_path[strlen(_path)-1] == '/'){
25 | _path[strlen(_path)-1] = '\0';
26 | }
27 | return _path;
28 | }
29 |
30 | int
31 | arch_load(char* name, arch_load_out_cb cb, void* context)
32 | {
33 | char* filename = malloc(256);
34 | sprintf(&filename, "%s/%s.bas", _get_path(), name);
35 | FILE* fp = fopen(filename, "r");
36 | if(!fp){
37 | return 1;
38 | }
39 | char line[256];
40 | while(fgets(line, 256, fp) != NULL) {
41 | cb(line, context);
42 | }
43 | fclose(fp);
44 | free(filename);
45 | return 0;
46 | }
47 |
48 | int
49 | arch_save(char* name, arch_save_cb cb, void* context)
50 | {
51 | char* line;
52 | char* filename = malloc(256);
53 | sprintf(&filename, "%s/%s.bas", _get_path(), name);
54 |
55 | FILE* fp = fopen(filename, "w");
56 | if(!fp){
57 | return 1;
58 | }
59 | for(;;){
60 | uint16_t number = cb(&line, context);
61 | if (line == NULL){
62 | break;
63 | }
64 | fprintf(fp, "%d %s\n",number, line);
65 | }
66 | fclose(fp);
67 |
68 | free(filename);
69 |
70 | return 0;
71 | }
72 |
73 | int
74 | arch_dir(arch_dir_out_cb cb, void* context)
75 | {
76 | //char out[256];
77 | //snprintf(out, sizeof(out), "dir: %s", _get_path());
78 | //cb(out, 0, true, context);
79 |
80 | //struct stat stats;
81 | //struct dirent *ent;
82 | //DIR *dir;
83 | //dir = opendir(_get_path());
84 | //while ((ent = readdir(dir)) != NULL) {
85 | // char* name = ent->d_name;
86 | // if (strlen(name)>4){
87 | // char *ext = name + strlen(name) - 4;
88 | // if (strncmp(ext, ".bas", 4)==0){
89 | // snprintf(out,sizeof(out),"%s/%s", _get_path(), name);
90 | // stat(out, &stats);
91 | // name[strlen(name)-4] = '\0';
92 | // cb(name, stats.st_size, false, context);
93 | // }
94 | // }
95 | //}
96 | //closedir(dir);
97 |
98 | return 0;
99 | }
100 |
101 | int
102 | arch_delete(char* name){
103 | char* filename = malloc(256);
104 | sprintf(&filename, "%s/%s.bas", _get_path(), name);
105 | remove(filename);
106 | free(filename);
107 | return 0;
108 | }
109 |
110 |
111 |
--------------------------------------------------------------------------------
/arch/windows/error.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | //#include
4 | #include
5 | // or inttypes.h
6 |
7 | extern uint16_t __line;
8 |
9 | const char *last_error = NULL;
10 |
11 | void
12 | error(const char *error_msg)
13 | {
14 | void *array[10];
15 | size_t size;
16 | //char **strings;
17 | size_t i;
18 |
19 | last_error = error_msg;
20 |
21 | printf("--- ERROR: %d %s\n", __line, error_msg);
22 |
23 | //size = backtrace (array, 10);
24 | //strings = backtrace_symbols (array, size);
25 |
26 | //printf ("SHOW %zd STACK FRAMES:\n", size);
27 |
28 | //for (i = 0; i < size; i++)
29 | //{
30 | // printf (" %s\n", strings[i]);
31 | //}
32 |
33 | //free (strings);
34 | }
35 |
--------------------------------------------------------------------------------
/arch/windows/kbhit.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | //#include
4 | //#include
5 | //#include
6 |
7 | int kbhit(void) {
8 | return getchar();
9 | }
10 |
--------------------------------------------------------------------------------
/arch/windows/main.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | //#include
4 | //#include
5 | #include
6 | #include
7 | #include
8 |
9 | #include "parser.h"
10 |
11 | extern bool __RUNNING;
12 | extern bool __STOPPED;
13 |
14 | static void
15 | sigint_handler(int signum)
16 | {
17 | signal(SIGINT, sigint_handler);
18 | if(__RUNNING){
19 | __RUNNING = false;
20 | __STOPPED = true;
21 | printf("STOP\n");
22 | fflush(stdout);
23 | }
24 | }
25 |
26 | static char *
27 | readline_gets ()
28 | {
29 | char * line_read = readline ("");
30 |
31 | if (line_read && *line_read) {
32 | add_history (line_read);
33 | }
34 |
35 | return line_read;
36 | }
37 |
38 | int out(int ch)
39 | {
40 | putchar(ch);
41 | return 1;
42 | }
43 |
44 | int in(void)
45 | {
46 | return getchar();
47 | }
48 |
49 | void repl(void)
50 | {
51 | puts(" _ _ ");
52 | puts("| |__ __ _ ___(_) ___ ");
53 | puts("| '_ \\ / _` / __| |/ __|");
54 | puts("| |_) | (_| \\__ \\ | (__ ");
55 | puts("|_.__/ \\__,_|___/_|\\___|");
56 | puts("(c) 2015-2016 Johan Van den Brande");
57 |
58 | //using_history();
59 |
60 | char input[1024];
61 | while ((gets(input)) != NULL )
62 | {
63 | if (strcmp(input, "QUIT") == 0) {
64 | memset(input, 0, 1024);
65 | break;
66 | }
67 |
68 | basic_eval(input);
69 |
70 | if (evaluate_last_error()) {
71 | printf("ERROR: %s\n", evaluate_last_error());
72 | clear_last_error();
73 | }
74 |
75 | memset(input, 0, 1024);
76 | }
77 |
78 | //clear_history();
79 | }
80 |
81 | void run(char *file_name){
82 | FILE* file = fopen(file_name, "r");
83 |
84 | if (file == NULL) {
85 | fprintf(stderr, "Can't open %s\n", file_name);
86 | return;
87 | }
88 |
89 | char line[tokenizer_string_length];
90 | while (fgets(line, sizeof(line), file)) {
91 | if(line[strlen(line)-1]!='\n')
92 | {
93 | printf("ERROR: NO EOL\n");
94 | exit(1);
95 | }
96 | basic_eval(line);
97 | }
98 | fclose(file);
99 |
100 | basic_run();
101 | }
102 |
103 | int main(int argc, char *argv[])
104 | {
105 | signal(SIGINT, sigint_handler);
106 |
107 | basic_init(1024*8, 2048);
108 | basic_register_io(out, in);
109 |
110 | if (argc > 1){
111 | run(argv[1]);
112 | } else {
113 | repl();
114 | }
115 |
116 | basic_destroy();
117 |
118 | return EXIT_SUCCESS;
119 | }
120 |
--------------------------------------------------------------------------------
/arch/xmega/arch.c:
--------------------------------------------------------------------------------
1 | #include "arch.h"
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | #include "spi.h"
8 | #include "ff.h"
9 |
10 | int
11 | asprintf(char **str, const char *format, ...)
12 | {
13 | va_list argp;
14 | va_start(argp, format);
15 |
16 | char one_char[1];
17 | int len = vsnprintf(one_char, 1, format, argp);
18 | if (len < 1){
19 | *str = NULL;
20 | return len;
21 | }
22 | va_end(argp);
23 | *str = malloc(len+1);
24 | if (!str) {
25 | return -1;
26 | }
27 | va_start(argp, format);
28 | vsnprintf(*str, len+1, format, argp);
29 | va_end(argp);
30 | return len;
31 | }
32 |
33 | float
34 | strtof(const char *restrict nptr, char **restrict endptr)
35 | {
36 | float f;
37 | sscanf(nptr, "%f", &f);
38 | return f;
39 | }
40 |
41 | char*
42 | strndup(const char *s, size_t n)
43 | {
44 | size_t len = strnlen (s, n);
45 | char *new = (char *) malloc (len + 1);
46 | if (new == NULL)
47 | {
48 | return NULL;
49 | }
50 | new[len] = '\0';
51 | return (char *) memcpy (new, s, len);
52 | }
53 |
54 | // -- SD Card specific
55 |
56 | FATFS FatFs;
57 |
58 | int
59 | arch_init(void)
60 | {
61 | spi_init();
62 | f_mount(&FatFs, "", 0);
63 | return 0;
64 | }
65 |
66 | int
67 | arch_load(char* name, arch_load_out_cb cb, void* context)
68 | {
69 | char filename[13]; // 8 + '.' + 3 + '\0'
70 | char line[128];
71 | FIL fil;
72 | snprintf(filename, sizeof(filename), "%s.bas", name);
73 | f_open(&fil, filename, FA_READ);
74 | while (f_gets(line, sizeof line, &fil)){
75 | cb(line, context);
76 | }
77 | f_close(&fil);
78 | return 0;
79 | }
80 |
81 | int
82 | arch_save(char* name, arch_save_cb cb, void* context)
83 | {
84 | char filename[13];
85 | char* line;
86 | char buffer[128];
87 | FIL fil;
88 | snprintf(filename, sizeof(filename), "%s.bas", name);
89 | f_open(&fil, filename, FA_WRITE | FA_CREATE_ALWAYS);
90 | for(;;){
91 | uint16_t number = cb(&line, context);
92 | if (line == NULL){
93 | break;
94 | }
95 | snprintf(buffer, sizeof(buffer), "%d %s\n", number, line);
96 | f_puts(buffer, &fil);
97 | }
98 | f_close(&fil);
99 | return 0;
100 | }
101 |
102 | int
103 | arch_dir(arch_dir_out_cb cb, void* context)
104 | {
105 | DIR dir;
106 | FRESULT res;
107 | FILINFO fno;
108 | char out[24];
109 | f_getlabel("", out, 0);
110 | cb(out, 0, true, context);
111 | res = f_findfirst(&dir, &fno, "", "*.bas");
112 | while (res == FR_OK && fno.fname[0]){
113 | fno.fname[strlen(fno.fname)-4] = '\0';
114 | cb(fno.fname, (size_t) fno.fsize, false, context);
115 | res = f_findnext(&dir, &fno);
116 | }
117 | f_closedir(&dir);
118 | return 0;
119 | }
120 |
121 | int
122 | arch_delete(char* name){
123 | char filename[13];
124 | snprintf(filename, sizeof(filename), "%s.bas", name);
125 | f_unlink(filename);
126 | return 0;
127 | }
128 |
129 |
130 |
--------------------------------------------------------------------------------
/arch/xmega/console.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "io.h"
6 |
7 | void
8 | console_def_char(unsigned char code, char* definition)
9 | {
10 | char buf[20];
11 | putchar(0x1b);
12 | putchar('T');
13 | snprintf(buf, sizeof(buf), "%02x", code);
14 | basic_io_print(buf);
15 | for(int i=0; i<18; i++){
16 | buf[i] = tolower(definition[i]);
17 | }
18 | buf[18] = '\0';
19 | basic_io_print(buf);
20 | }
21 |
22 | void
23 | console_move_cursor(int x, int y)
24 | {
25 | putchar(0x1b);
26 | putchar('Y');
27 | putchar(' ' + y);
28 | putchar(' ' + x);
29 | }
30 |
31 | void
32 | console_plot(int x, int y, unsigned char code)
33 | {
34 | console_move_cursor(x, y);
35 | if(code < 32){
36 | putchar(0x10); // Data link escape
37 | }
38 | putchar(code);
39 | }
40 |
41 | void
42 | console_cursor(int cursor)
43 | {
44 | putchar(0x1b);
45 | if(cursor){
46 | putchar('e');
47 | } else {
48 | putchar('f');
49 | }
50 | }
51 |
52 | void
53 | console_cursor_type(int block)
54 | {
55 | putchar(0x1b);
56 | if(block){
57 | putchar('x');
58 | } else {
59 | putchar('y');
60 | }
61 | putchar('4');
62 | }
63 |
64 | void
65 | console_line_overflow(int overflow)
66 | {
67 | putchar(0x1b);
68 | if(overflow){
69 | putchar('v');
70 | } else {
71 | putchar('w');
72 | }
73 | }
74 |
75 | void
76 | console_fontbank(int row, int bank)
77 | {
78 | char banks[] = {'6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@'};
79 |
80 | // save cursor
81 | putchar(0x1b);
82 | putchar('j');
83 |
84 | // set cursor
85 | putchar(0x1b);
86 | putchar('Y');
87 | putchar(' ' + row);
88 | putchar(' ' + 0);
89 |
90 | // set bank for actual row
91 | putchar(0x1b);
92 | putchar('_');
93 | if(bank<0) bank = 0;
94 | if(bank>10) bank = 10;
95 | putchar(banks[bank]);
96 |
97 | // restore cursor
98 | putchar(0x1b);
99 | putchar('k');
100 | }
101 |
102 | void
103 | console_cls(void)
104 | {
105 | putchar(0x1b);
106 | putchar('E');
107 | }
108 |
109 | void
110 | console_invert(int invert)
111 | {
112 | putchar(0x1b);
113 | if(invert){
114 | putchar('x');
115 | } else {
116 | putchar('y');
117 | }
118 | putchar('>');
119 | }
120 |
--------------------------------------------------------------------------------
/arch/xmega/console.h:
--------------------------------------------------------------------------------
1 | #ifndef __CONSOLE_H__
2 | #define __CONSOLE_H__
3 |
4 | void console_def_char(unsigned char code, char* definition);
5 | void console_plot(int x, int y, unsigned char code);
6 | void console_cursor(int cursor);
7 | void console_cursor_type(int block);
8 | void console_line_overflow(int overflow);
9 | void console_fontbank(int row, int bank);
10 | void console_cls(void);
11 | void console_move_cursor(int x, int y);
12 | void console_invert(int invert);
13 |
14 | #endif
15 |
--------------------------------------------------------------------------------
/arch/xmega/diskio.h:
--------------------------------------------------------------------------------
1 | /*-----------------------------------------------------------------------
2 | / Low level disk interface modlue include file (C)ChaN, 2014
3 | /-----------------------------------------------------------------------*/
4 |
5 | #ifndef _DISKIO_DEFINED
6 | #define _DISKIO_DEFINED
7 |
8 | #ifdef __cplusplus
9 | extern "C" {
10 | #endif
11 |
12 | #define _USE_WRITE 1 /* 1: Enable disk_write function */
13 | #define _USE_IOCTL 1 /* 1: Enable disk_ioctl fucntion */
14 | #define _USE_ISDIO 1 /* 1: Enable iSDIO controls via disk_ioctl */
15 |
16 | #include "integer.h"
17 |
18 |
19 | /* Status of Disk Functions */
20 | typedef BYTE DSTATUS;
21 |
22 | /* Results of Disk Functions */
23 | typedef enum {
24 | RES_OK = 0, /* 0: Successful */
25 | RES_ERROR, /* 1: R/W Error */
26 | RES_WRPRT, /* 2: Write Protected */
27 | RES_NOTRDY, /* 3: Not Ready */
28 | RES_PARERR /* 4: Invalid Parameter */
29 | } DRESULT;
30 |
31 | /* Command structure for iSDIO ioctl command */
32 | typedef struct {
33 | BYTE func; /* Function number: 0..7 */
34 | WORD ndata; /* Number of bytes to transfer: 1..512, or mask + data */
35 | DWORD addr; /* Register address: 0..0x1FFFF */
36 | void* data; /* Pointer to the data (to be written | read buffer) */
37 | } SDIO_CTRL;
38 |
39 |
40 | /*---------------------------------------*/
41 | /* Prototypes for disk control functions */
42 |
43 |
44 | DSTATUS disk_initialize (BYTE pdrv);
45 | DSTATUS disk_status (BYTE pdrv);
46 | DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
47 | DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
48 | DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
49 | void disk_timerproc (void);
50 |
51 |
52 | /* Disk Status Bits (DSTATUS) */
53 | #define STA_NOINIT 0x01 /* Drive not initialized */
54 | #define STA_NODISK 0x02 /* No medium in the drive */
55 | #define STA_PROTECT 0x04 /* Write protected */
56 |
57 |
58 | /* Command code for disk_ioctrl fucntion */
59 |
60 | /* Generic command (Used by FatFs) */
61 | #define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */
62 | #define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */
63 | #define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */
64 | #define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */
65 | #define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */
66 |
67 | /* Generic command (Not used by FatFs) */
68 | #define CTRL_FORMAT 5 /* Create physical format on the media */
69 | #define CTRL_POWER_IDLE 6 /* Put the device idle state */
70 | #define CTRL_POWER_OFF 7 /* Put the device off state */
71 | #define CTRL_LOCK 8 /* Lock media removal */
72 | #define CTRL_UNLOCK 9 /* Unlock media removal */
73 | #define CTRL_EJECT 10 /* Eject media */
74 |
75 | /* MMC/SDC specific command (Not used by FatFs) */
76 | #define MMC_GET_TYPE 50 /* Get card type */
77 | #define MMC_GET_CSD 51 /* Get CSD */
78 | #define MMC_GET_CID 52 /* Get CID */
79 | #define MMC_GET_OCR 53 /* Get OCR */
80 | #define MMC_GET_SDSTAT 54 /* Get SD status */
81 | #define ISDIO_READ 55 /* Read data form SD iSDIO register */
82 | #define ISDIO_WRITE 56 /* Write data to SD iSDIO register */
83 | #define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */
84 |
85 | /* ATA/CF specific command (Not used by FatFs) */
86 | #define ATA_GET_REV 60 /* Get F/W revision */
87 | #define ATA_GET_MODEL 61 /* Get model name */
88 | #define ATA_GET_SN 62 /* Get serial number */
89 |
90 |
91 | /* MMC card type flags (MMC_GET_TYPE) */
92 | #define CT_MMC 0x01 /* MMC ver 3 */
93 | #define CT_SD1 0x02 /* SD ver 1 */
94 | #define CT_SD2 0x04 /* SD ver 2 */
95 | #define CT_SDC (CT_SD1|CT_SD2) /* SD */
96 | #define CT_BLOCK 0x08 /* Block addressing */
97 |
98 |
99 | #ifdef __cplusplus
100 | }
101 | #endif
102 |
103 | #endif
104 |
--------------------------------------------------------------------------------
/arch/xmega/error.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include
5 |
6 | const char *last_error = NULL;
7 |
8 | void
9 | error(const char *error_msg)
10 | {
11 | last_error = error_msg;
12 | }
13 |
14 |
--------------------------------------------------------------------------------
/arch/xmega/ext.c:
--------------------------------------------------------------------------------
1 | #include "parser.h"
2 |
3 |
4 |
--------------------------------------------------------------------------------
/arch/xmega/ff.h:
--------------------------------------------------------------------------------
1 | /*---------------------------------------------------------------------------/
2 | / FatFs - FAT file system module include R0.12 (C)ChaN, 2016
3 | /----------------------------------------------------------------------------/
4 | / FatFs module is a free software that opened under license policy of
5 | / following conditions.
6 | /
7 | / Copyright (C) 2016, ChaN, all right reserved.
8 | /
9 | / 1. Redistributions of source code must retain the above copyright notice,
10 | / this condition and the following disclaimer.
11 | /
12 | / This software is provided by the copyright holder and contributors "AS IS"
13 | / and any warranties related to this software are DISCLAIMED.
14 | / The copyright owner or contributors be NOT LIABLE for any damages caused
15 | / by use of this software.
16 | /---------------------------------------------------------------------------*/
17 |
18 |
19 | #ifndef _FATFS
20 | #define _FATFS 88100 /* Revision ID */
21 |
22 | #ifdef __cplusplus
23 | extern "C" {
24 | #endif
25 |
26 | #include "integer.h" /* Basic integer types */
27 | #include "ffconf.h" /* FatFs configuration options */
28 | #if _FATFS != _FFCONF
29 | #error Wrong configuration file (ffconf.h).
30 | #endif
31 |
32 |
33 |
34 | /* Definitions of volume management */
35 |
36 | #if _MULTI_PARTITION /* Multiple partition configuration */
37 | typedef struct {
38 | BYTE pd; /* Physical drive number */
39 | BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
40 | } PARTITION;
41 | extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
42 | #define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */
43 | #define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */
44 |
45 | #else /* Single partition configuration */
46 | #define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */
47 | #define LD2PT(vol) 0 /* Find first valid partition or in SFD */
48 |
49 | #endif
50 |
51 |
52 |
53 | /* Type of path name strings on FatFs API */
54 |
55 | #if _LFN_UNICODE /* Unicode string */
56 | #if _USE_LFN == 0
57 | #error _LFN_UNICODE must be 0 at non-LFN cfg.
58 | #endif
59 | #ifndef _INC_TCHAR
60 | typedef WCHAR TCHAR;
61 | #define _T(x) L ## x
62 | #define _TEXT(x) L ## x
63 | #endif
64 |
65 | #else /* ANSI/OEM string */
66 | #ifndef _INC_TCHAR
67 | typedef char TCHAR;
68 | #define _T(x) x
69 | #define _TEXT(x) x
70 | #endif
71 |
72 | #endif
73 |
74 |
75 |
76 | /* File system object structure (FATFS) */
77 |
78 | typedef struct {
79 | BYTE fs_type; /* File system type (0:N/A) */
80 | BYTE drv; /* Physical drive number */
81 | BYTE n_fats; /* Number of FATs (1 or 2) */
82 | BYTE wflag; /* win[] flag (b0:dirty) */
83 | BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
84 | WORD id; /* File system mount ID */
85 | WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
86 | WORD csize; /* Cluster size [sectors] */
87 | #if _MAX_SS != _MIN_SS
88 | WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */
89 | #endif
90 | #if _FS_EXFAT
91 | BYTE* dirbuf; /* Directory entry block scratchpad buffer */
92 | #endif
93 | #if _FS_REENTRANT
94 | _SYNC_t sobj; /* Identifier of sync object */
95 | #endif
96 | #if !_FS_READONLY
97 | DWORD last_clst; /* Last allocated cluster */
98 | DWORD free_clst; /* Number of free clusters */
99 | #endif
100 | #if _FS_RPATH != 0
101 | DWORD cdir; /* Current directory start cluster (0:root) */
102 | #if _FS_EXFAT
103 | DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */
104 | DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */
105 | DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */
106 | #endif
107 | #endif
108 | DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */
109 | DWORD fsize; /* Size of an FAT [sectors] */
110 | DWORD volbase; /* Volume base sector */
111 | DWORD fatbase; /* FAT base sector */
112 | DWORD dirbase; /* Root directory base sector/cluster */
113 | DWORD database; /* Data base sector */
114 | DWORD winsect; /* Current sector appearing in the win[] */
115 | BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
116 | } FATFS;
117 |
118 |
119 |
120 | /* Type of file size variables and object identifier */
121 |
122 | #if _FS_EXFAT
123 | #if _USE_LFN == 0
124 | #error LFN must be enabled when enable exFAT
125 | #endif
126 | typedef QWORD FSIZE_t;
127 | #else
128 | typedef DWORD FSIZE_t;
129 | #endif
130 |
131 |
132 |
133 | /* Object ID and allocation information (_FDID) */
134 |
135 | typedef struct {
136 | FATFS* fs; /* Pointer to the owner file system object */
137 | WORD id; /* Owner file system mount ID */
138 | BYTE attr; /* Object attribute */
139 | BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous (no data on FAT), =3:got flagmented, b2:sub-directory stretched) */
140 | DWORD sclust; /* Object start cluster (0:no cluster or root directory) */
141 | FSIZE_t objsize; /* Object size (valid when sclust != 0) */
142 | #if _FS_EXFAT
143 | DWORD n_cont; /* Size of coutiguous part, clusters - 1 (valid when stat == 3) */
144 | DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */
145 | DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */
146 | DWORD c_ofs; /* Offset in the containing directory (valid when sclust != 0) */
147 | #endif
148 | #if _FS_LOCK != 0
149 | UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
150 | #endif
151 | } _FDID;
152 |
153 |
154 |
155 | /* File object structure (FIL) */
156 |
157 | typedef struct {
158 | _FDID obj; /* Object identifier */
159 | BYTE flag; /* File status flags */
160 | BYTE err; /* Abort flag (error code) */
161 | FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */
162 | DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */
163 | DWORD sect; /* Sector number appearing in buf[] (0:invalid) */
164 | #if !_FS_READONLY
165 | DWORD dir_sect; /* Sector number containing the directory entry */
166 | BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */
167 | #endif
168 | #if _USE_FASTSEEK
169 | DWORD* cltbl; /* Pointer to the cluster link map table (Nulled on file open) */
170 | #endif
171 | #if !_FS_TINY
172 | BYTE buf[_MAX_SS]; /* File private data read/write window */
173 | #endif
174 | } FIL;
175 |
176 |
177 |
178 | /* Directory object structure (DIR) */
179 |
180 | typedef struct {
181 | _FDID obj; /* Object identifier */
182 | DWORD dptr; /* Current read/write offset */
183 | DWORD clust; /* Current cluster */
184 | DWORD sect; /* Current sector */
185 | BYTE* dir; /* Pointer to the directory item in the win[] */
186 | BYTE* fn; /* Pointer to the SFN (in/out) {body[8],ext[3],status[1]} */
187 | #if _USE_LFN != 0
188 | DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
189 | WCHAR* lfn; /* Pointer to the LFN working buffer */
190 | #endif
191 | #if _USE_FIND
192 | const TCHAR* pat; /* Pointer to the name matching pattern */
193 | #endif
194 | } DIR;
195 |
196 |
197 |
198 | /* File information structure (FILINFO) */
199 |
200 | typedef struct {
201 | FSIZE_t fsize; /* File size */
202 | WORD fdate; /* Modified date */
203 | WORD ftime; /* Modified time */
204 | BYTE fattrib; /* File attribute */
205 | #if _USE_LFN != 0
206 | TCHAR altname[13]; /* Altenative file name */
207 | TCHAR fname[_MAX_LFN + 1]; /* Primary file name */
208 | #else
209 | TCHAR fname[13]; /* File name */
210 | #endif
211 | } FILINFO;
212 |
213 |
214 |
215 | /* File function return code (FRESULT) */
216 |
217 | typedef enum {
218 | FR_OK = 0, /* (0) Succeeded */
219 | FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */
220 | FR_INT_ERR, /* (2) Assertion failed */
221 | FR_NOT_READY, /* (3) The physical drive cannot work */
222 | FR_NO_FILE, /* (4) Could not find the file */
223 | FR_NO_PATH, /* (5) Could not find the path */
224 | FR_INVALID_NAME, /* (6) The path name format is invalid */
225 | FR_DENIED, /* (7) Access denied due to prohibited access or directory full */
226 | FR_EXIST, /* (8) Access denied due to prohibited access */
227 | FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
228 | FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
229 | FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
230 | FR_NOT_ENABLED, /* (12) The volume has no work area */
231 | FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
232 | FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */
233 | FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
234 | FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
235 | FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
236 | FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_LOCK */
237 | FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
238 | } FRESULT;
239 |
240 |
241 |
242 | /*--------------------------------------------------------------*/
243 | /* FatFs module application interface */
244 |
245 | FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
246 | FRESULT f_close (FIL* fp); /* Close an open file object */
247 | FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from a file */
248 | FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to a file */
249 | FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of a file object */
250 | FRESULT f_truncate (FIL* fp); /* Truncate file */
251 | FRESULT f_sync (FIL* fp); /* Flush cached data of a writing file */
252 | FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */
253 | FRESULT f_closedir (DIR* dp); /* Close an open directory */
254 | FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */
255 | FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */
256 | FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */
257 | FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */
258 | FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
259 | FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
260 | FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
261 | FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of the file/dir */
262 | FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of the file/dir */
263 | FRESULT f_chdir (const TCHAR* path); /* Change current directory */
264 | FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
265 | FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
266 | FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */
267 | FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
268 | FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
269 | FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
270 | FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */
271 | FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
272 | FRESULT f_mkfs (const TCHAR* path, BYTE sfd, UINT au); /* Create a file system on the volume */
273 | FRESULT f_fdisk (BYTE pdrv, const DWORD szt[], void* work); /* Divide a physical drive into some partitions */
274 | int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
275 | int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
276 | int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
277 | TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
278 |
279 | #define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize))
280 | #define f_error(fp) ((fp)->err)
281 | #define f_tell(fp) ((fp)->fptr)
282 | #define f_size(fp) ((fp)->obj.objsize)
283 | #define f_rewind(fp) f_lseek((fp), 0)
284 | #define f_rewinddir(dp) f_readdir((dp), 0)
285 |
286 | #ifndef EOF
287 | #define EOF (-1)
288 | #endif
289 |
290 |
291 |
292 |
293 | /*--------------------------------------------------------------*/
294 | /* Additional user defined functions */
295 |
296 | /* RTC function */
297 | #if !_FS_READONLY && !_FS_NORTC
298 | DWORD get_fattime (void);
299 | #endif
300 |
301 | /* Unicode support functions */
302 | #if _USE_LFN != 0 /* Unicode - OEM code conversion */
303 | WCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */
304 | WCHAR ff_wtoupper (WCHAR chr); /* Unicode upper-case conversion */
305 | #if _USE_LFN == 3 /* Memory functions */
306 | void* ff_memalloc (UINT msize); /* Allocate memory block */
307 | void ff_memfree (void* mblock); /* Free memory block */
308 | #endif
309 | #endif
310 |
311 | /* Sync functions */
312 | #if _FS_REENTRANT
313 | int ff_cre_syncobj (BYTE vol, _SYNC_t* sobj); /* Create a sync object */
314 | int ff_req_grant (_SYNC_t sobj); /* Lock sync object */
315 | void ff_rel_grant (_SYNC_t sobj); /* Unlock sync object */
316 | int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */
317 | #endif
318 |
319 |
320 |
321 |
322 | /*--------------------------------------------------------------*/
323 | /* Flags and offset address */
324 |
325 |
326 | /* File access control and file status flags (FIL.flag) */
327 |
328 | #define FA_READ 0x01
329 | #define FA_WRITE 0x02
330 | #define FA_OPEN_EXISTING 0x00
331 | #define FA_CREATE_NEW 0x04
332 | #define FA_CREATE_ALWAYS 0x08
333 | #define FA_OPEN_ALWAYS 0x10
334 | #define _FA_MODIFIED 0x20
335 | #define _FA_DIRTY 0x40
336 |
337 |
338 | /* FAT sub type (FATFS.fs_type) */
339 |
340 | #define FS_FAT12 1
341 | #define FS_FAT16 2
342 | #define FS_FAT32 3
343 | #define FS_EXFAT 4
344 |
345 |
346 | /* File attribute bits for directory entry */
347 |
348 | #define AM_RDO 0x01 /* Read only */
349 | #define AM_HID 0x02 /* Hidden */
350 | #define AM_SYS 0x04 /* System */
351 | #define AM_VOL 0x08 /* Volume label */
352 | #define AM_LFN 0x0F /* LFN entry */
353 | #define AM_DIR 0x10 /* Directory */
354 | #define AM_ARC 0x20 /* Archive */
355 | #define AM_MASK 0x3F /* Mask of defined bits */
356 |
357 |
358 | /* Fast seek controls */
359 | #define CREATE_LINKMAP ((FSIZE_t)0 - 1)
360 |
361 |
362 | #ifdef __cplusplus
363 | }
364 | #endif
365 |
366 | #endif /* _FATFS */
367 |
--------------------------------------------------------------------------------
/arch/xmega/ffconf.h:
--------------------------------------------------------------------------------
1 | /*---------------------------------------------------------------------------/
2 | / FatFs - FAT file system module configuration file R0.12 (C)ChaN, 2016
3 | /---------------------------------------------------------------------------*/
4 |
5 | #define _FFCONF 88100 /* Revision ID */
6 |
7 | /*---------------------------------------------------------------------------/
8 | / Function Configurations
9 | /---------------------------------------------------------------------------*/
10 |
11 | #define _FS_READONLY 0
12 | /* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
13 | / Read-only configuration removes writing API functions, f_write(), f_sync(),
14 | / f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
15 | / and optional writing functions as well. */
16 |
17 |
18 | #define _FS_MINIMIZE 0
19 | /* This option defines minimization level to remove some basic API functions.
20 | /
21 | / 0: All basic functions are enabled.
22 | / 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename()
23 | / are removed.
24 | / 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
25 | / 3: f_lseek() function is removed in addition to 2. */
26 |
27 |
28 | #define _USE_STRFUNC 1
29 | /* This option switches string functions, f_gets(), f_putc(), f_puts() and
30 | / f_printf().
31 | /
32 | / 0: Disable string functions.
33 | / 1: Enable without LF-CRLF conversion.
34 | / 2: Enable with LF-CRLF conversion. */
35 |
36 |
37 | #define _USE_FIND 1
38 | /* This option switches filtered directory read functions, f_findfirst() and
39 | / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
40 |
41 |
42 | #define _USE_MKFS 1
43 | /* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
44 |
45 |
46 | #define _USE_FASTSEEK 0
47 | /* This option switches fast seek function. (0:Disable or 1:Enable) */
48 |
49 |
50 | #define _USE_EXPAND 0
51 | /* This option switches f_expand function. (0:Disable or 1:Enable) */
52 |
53 |
54 | #define _USE_CHMOD 1
55 | /* This option switches attribute manipulation functions, f_chmod() and f_utime().
56 | / (0:Disable or 1:Enable) Also _FS_READONLY needs to be 0 to enable this option. */
57 |
58 |
59 | #define _USE_LABEL 1
60 | /* This option switches volume label functions, f_getlabel() and f_setlabel().
61 | / (0:Disable or 1:Enable) */
62 |
63 |
64 | #define _USE_FORWARD 0
65 | /* This option switches f_forward() function. (0:Disable or 1:Enable)
66 | / To enable it, also _FS_TINY need to be 1. */
67 |
68 |
69 | /*---------------------------------------------------------------------------/
70 | / Locale and Namespace Configurations
71 | /---------------------------------------------------------------------------*/
72 |
73 | #define _CODE_PAGE 1
74 | /* This option specifies the OEM code page to be used on the target system.
75 | / Incorrect setting of the code page can cause a file open failure.
76 | /
77 | / 1 - ASCII (No extended character. Non-LFN cfg. only)
78 | / 437 - U.S.
79 | / 720 - Arabic
80 | / 737 - Greek
81 | / 771 - KBL
82 | / 775 - Baltic
83 | / 850 - Latin 1
84 | / 852 - Latin 2
85 | / 855 - Cyrillic
86 | / 857 - Turkish
87 | / 860 - Portuguese
88 | / 861 - Icelandic
89 | / 862 - Hebrew
90 | / 863 - Canadian French
91 | / 864 - Arabic
92 | / 865 - Nordic
93 | / 866 - Russian
94 | / 869 - Greek 2
95 | / 932 - Japanese (DBCS)
96 | / 936 - Simplified Chinese (DBCS)
97 | / 949 - Korean (DBCS)
98 | / 950 - Traditional Chinese (DBCS)
99 | */
100 |
101 |
102 | #define _USE_LFN 0
103 | #define _MAX_LFN 128
104 | /* The _USE_LFN switches the support of long file name (LFN).
105 | /
106 | / 0: Disable support of LFN. _MAX_LFN has no effect.
107 | / 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
108 | / 2: Enable LFN with dynamic working buffer on the STACK.
109 | / 3: Enable LFN with dynamic working buffer on the HEAP.
110 | /
111 | / To enable the LFN, Unicode handling functions (option/unicode.c) must be added
112 | / to the project. The working buffer occupies (_MAX_LFN + 1) * 2 bytes and
113 | / additional 608 bytes at exFAT enabled. _MAX_LFN can be in range from 12 to 255.
114 | / It should be set 255 to support full featured LFN operations.
115 | / When use stack for the working buffer, take care on stack overflow. When use heap
116 | / memory for the working buffer, memory management functions, ff_memalloc() and
117 | / ff_memfree(), must be added to the project. */
118 |
119 |
120 | #define _LFN_UNICODE 0
121 | /* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode)
122 | / To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1.
123 | / This option also affects behavior of string I/O functions. */
124 |
125 |
126 | #define _STRF_ENCODE 3
127 | /* When _LFN_UNICODE == 1, this option selects the character encoding on the file to
128 | / be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
129 | /
130 | / 0: ANSI/OEM
131 | / 1: UTF-16LE
132 | / 2: UTF-16BE
133 | / 3: UTF-8
134 | /
135 | / This option has no effect when _LFN_UNICODE == 0. */
136 |
137 |
138 | #define _FS_RPATH 2
139 | /* This option configures support of relative path.
140 | /
141 | / 0: Disable relative path and remove related functions.
142 | / 1: Enable relative path. f_chdir() and f_chdrive() are available.
143 | / 2: f_getcwd() function is available in addition to 1.
144 | */
145 |
146 |
147 | /*---------------------------------------------------------------------------/
148 | / Drive/Volume Configurations
149 | /---------------------------------------------------------------------------*/
150 |
151 | #define _VOLUMES 1
152 | /* Number of volumes (logical drives) to be used. */
153 |
154 |
155 | #define _STR_VOLUME_ID 0
156 | #define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3"
157 | /* _STR_VOLUME_ID switches string support of volume ID.
158 | / When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
159 | / number in the path name. _VOLUME_STRS defines the drive ID strings for each
160 | / logical drives. Number of items must be equal to _VOLUMES. Valid characters for
161 | / the drive ID strings are: A-Z and 0-9. */
162 |
163 |
164 | #define _MULTI_PARTITION 0
165 | /* This option switches support of multi-partition on a physical drive.
166 | / By default (0), each logical drive number is bound to the same physical drive
167 | / number and only an FAT volume found on the physical drive will be mounted.
168 | / When multi-partition is enabled (1), each logical drive number can be bound to
169 | / arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()
170 | / funciton will be available. */
171 |
172 |
173 | #define _MIN_SS 512
174 | #define _MAX_SS 512
175 | /* These options configure the range of sector size to be supported. (512, 1024,
176 | / 2048 or 4096) Always set both 512 for most systems, all type of memory cards and
177 | / harddisk. But a larger value may be required for on-board flash memory and some
178 | / type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured
179 | / to variable sector size and GET_SECTOR_SIZE command must be implemented to the
180 | / disk_ioctl() function. */
181 |
182 |
183 | #define _USE_TRIM 0
184 | /* This option switches support of ATA-TRIM. (0:Disable or 1:Enable)
185 | / To enable Trim function, also CTRL_TRIM command should be implemented to the
186 | / disk_ioctl() function. */
187 |
188 |
189 | #define _FS_NOFSINFO 0
190 | /* If you need to know correct free space on the FAT32 volume, set bit 0 of this
191 | / option, and f_getfree() function at first time after volume mount will force
192 | / a full FAT scan. Bit 1 controls the use of last allocated cluster number.
193 | /
194 | / bit0=0: Use free cluster count in the FSINFO if available.
195 | / bit0=1: Do not trust free cluster count in the FSINFO.
196 | / bit1=0: Use last allocated cluster number in the FSINFO if available.
197 | / bit1=1: Do not trust last allocated cluster number in the FSINFO.
198 | */
199 |
200 |
201 |
202 | /*---------------------------------------------------------------------------/
203 | / System Configurations
204 | /---------------------------------------------------------------------------*/
205 |
206 | #define _FS_TINY 1
207 | /* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
208 | / At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS bytes.
209 | / Instead of private sector buffer eliminated from the file object, common sector
210 | / buffer in the file system object (FATFS) is used for the file data transfer. */
211 |
212 |
213 | #define _FS_EXFAT 0
214 | /* This option switches support of exFAT file system in addition to the traditional
215 | / FAT file system. (0:Disable or 1:Enable) To enable exFAT, also LFN must be enabled.
216 | / Note that enabling exFAT discards C89 compatibility. */
217 |
218 |
219 | #define _FS_NORTC 1
220 | #define _NORTC_MON 3
221 | #define _NORTC_MDAY 1
222 | #define _NORTC_YEAR 2016
223 | /* The option _FS_NORTC switches timestamp functiton. If the system does not have
224 | / any RTC function or valid timestamp is not needed, set _FS_NORTC = 1 to disable
225 | / the timestamp function. All objects modified by FatFs will have a fixed timestamp
226 | / defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR in local time.
227 | / To enable timestamp function (_FS_NORTC = 0), get_fattime() function need to be
228 | / added to the project to get current time form real-time clock. _NORTC_MON,
229 | / _NORTC_MDAY and _NORTC_YEAR have no effect.
230 | / These options have no effect at read-only configuration (_FS_READONLY = 1). */
231 |
232 |
233 | #define _FS_LOCK 0
234 | /* The option _FS_LOCK switches file lock function to control duplicated file open
235 | / and illegal operation to open objects. This option must be 0 when _FS_READONLY
236 | / is 1.
237 | /
238 | / 0: Disable file lock function. To avoid volume corruption, application program
239 | / should avoid illegal open, remove and rename to the open objects.
240 | / >0: Enable file lock function. The value defines how many files/sub-directories
241 | / can be opened simultaneously under file lock control. Note that the file
242 | / lock control is independent of re-entrancy. */
243 |
244 |
245 | #define _FS_REENTRANT 0
246 | #define _FS_TIMEOUT 1000
247 | #define _SYNC_t HANDLE
248 | /* The option _FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs
249 | / module itself. Note that regardless of this option, file access to different
250 | / volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
251 | / and f_fdisk() function, are always not re-entrant. Only file/directory access
252 | / to the same volume is under control of this function.
253 | /
254 | / 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect.
255 | / 1: Enable re-entrancy. Also user provided synchronization handlers,
256 | / ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()
257 | / function, must be added to the project. Samples are available in
258 | / option/syscall.c.
259 | /
260 | / The _FS_TIMEOUT defines timeout period in unit of time tick.
261 | / The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
262 | / SemaphoreHandle_t and etc.. A header file for O/S definitions needs to be
263 | / included somewhere in the scope of ff.c. */
264 |
265 |
266 | /*--- End of configuration options ---*/
267 |
--------------------------------------------------------------------------------
/arch/xmega/integer.h:
--------------------------------------------------------------------------------
1 | /*-------------------------------------------*/
2 | /* Integer type definitions for FatFs module */
3 | /*-------------------------------------------*/
4 |
5 | #ifndef _FF_INTEGER
6 | #define _FF_INTEGER
7 |
8 | #ifdef _WIN32 /* FatFs development platform */
9 |
10 | #include
11 | #include
12 | typedef unsigned __int64 QWORD;
13 |
14 |
15 | #else /* Embedded platform */
16 |
17 | /* These types MUST be 16-bit or 32-bit */
18 | typedef int INT;
19 | typedef unsigned int UINT;
20 |
21 | /* This type MUST be 8-bit */
22 | typedef unsigned char BYTE;
23 |
24 | /* These types MUST be 16-bit */
25 | typedef short SHORT;
26 | typedef unsigned short WORD;
27 | typedef unsigned short WCHAR;
28 |
29 | /* These types MUST be 32-bit */
30 | typedef long LONG;
31 | typedef unsigned long DWORD;
32 |
33 | /* This type MUST be 64-bit (Remove this for C89 compatibility) */
34 | typedef unsigned long long QWORD;
35 |
36 | #endif
37 |
38 | #endif
39 |
--------------------------------------------------------------------------------
/arch/xmega/joystick.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | void
8 | joystick_init(void)
9 | {
10 | PORTA.DIRCLR = PIN0_bm | PIN1_bm | PIN2_bm | PIN3_bm | PIN4_bm;
11 | PORTA.PIN0CTRL|=PORT_OPC_PULLUP_gc;
12 | PORTA.PIN1CTRL|=PORT_OPC_PULLUP_gc;
13 | PORTA.PIN2CTRL|=PORT_OPC_PULLUP_gc;
14 | PORTA.PIN3CTRL|=PORT_OPC_PULLUP_gc;
15 | PORTA.PIN4CTRL|=PORT_OPC_PULLUP_gc;
16 | }
17 |
18 | int
19 | joystick_read_button(void){
20 | return (int) 0 == (PORTA.IN & PIN0_bm);
21 | }
22 |
23 | int
24 | joystick_read_stick(void){
25 |
26 | // R L D U S bits N LABEL
27 | // --+----+----+----+------+------+----+-------
28 | // 1 1 1 1 15 1111 0 N
29 | // 1 1 1 0 14 1110 1 U
30 | // 0 1 1 0 6 0110 2 UR
31 | // 0 1 1 1 7 0111 3 R
32 | // 0 1 0 1 5 0101 4 DR
33 | // 1 1 0 1 13 1101 5 D
34 | // 1 0 0 1 9 1001 6 DL
35 | // 1 0 1 1 11 1011 7 L
36 | // 1 0 1 0 10 1010 8 UL
37 |
38 | uint8_t stick = PORTA.IN >> 1;
39 | switch(stick){
40 | case 15:
41 | return 0;
42 | case 14:
43 | return 1;
44 | case 6:
45 | return 2;
46 | case 7:
47 | return 3;
48 | case 5:
49 | return 4;
50 | case 13:
51 | return 5;
52 | case 9:
53 | return 6;
54 | case 11:
55 | return 7;
56 | case 10:
57 | return 8;
58 | default:
59 | return 0;
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/arch/xmega/joystick.h:
--------------------------------------------------------------------------------
1 | #ifndef __JOYSTICK_H__
2 | #define __JOYSTICK_H__
3 |
4 | void joystick_init(void);
5 |
6 | // 0: neutral
7 | // 1: U
8 | // 2: UR
9 | // 3: R
10 | // 4: DR
11 | // 5: D
12 | // 6: DL
13 | // 7: L
14 | // 8: UL
15 | int joystick_read_stick(void);
16 |
17 | // 1: pressed
18 | int joystick_read_button(void);
19 |
20 | #endif
21 |
--------------------------------------------------------------------------------
/arch/xmega/kbhit.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int kbhit(void) {
4 | return USARTD0.STATUS & USART_RXCIF_bm;
5 | }
6 |
--------------------------------------------------------------------------------
/arch/xmega/main.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | #include "parser.h"
12 | #include "sound.h"
13 | #include "joystick.h"
14 | #include "console.h"
15 |
16 | #include "diskio.h"
17 |
18 | #include "error.h"
19 |
20 | #include "ff.h"
21 |
22 | extern uint16_t __line;
23 | extern bool __STOPPED;
24 |
25 | extern token sym;
26 | extern bool accept(token t);
27 | extern void get_sym(void);
28 | static token t_keyword_batch;
29 |
30 | // 100 Hz
31 | ISR(TCC0_OVF_vect)
32 | {
33 | disk_timerproc();
34 | sound_timerproc();
35 | }
36 |
37 | void init_xtal(void)
38 | {
39 | // Use an external 16Mhz crystal and x 2 PLL to give a clock of 32Mhz
40 |
41 | // Enable the external oscillator
42 | OSC.XOSCCTRL = OSC_FRQRANGE_12TO16_gc | OSC_XOSCSEL_XTAL_16KCLK_gc ;
43 | OSC.CTRL |= OSC_XOSCEN_bm ;
44 | while( (OSC.STATUS & OSC_XOSCRDY_bm) == 0 ){} // wait until stable
45 |
46 | // Now configure the PLL to be eXternal OSCillator * 2
47 | OSC.PLLCTRL = OSC_PLLSRC_XOSC_gc | 2 ;
48 | OSC.CTRL |= OSC_PLLEN_bm ; // enable the PLL...
49 | while( (OSC.STATUS & OSC_PLLRDY_bm) == 0 ){} // wait until stable
50 |
51 | // And now switch to the PLL as the clocksource
52 | CCP = CCP_IOREG_gc; // protected write follows
53 | CLK.CTRL = CLK_SCLKSEL_PLL_gc;
54 | }
55 |
56 | void set_usartctrl( USART_t *usart, uint8_t bscale, uint16_t bsel)
57 | {
58 | usart->BAUDCTRLA = (bsel & USART_BSEL_gm);
59 | usart->BAUDCTRLB = ((bscale << USART_BSCALE0_bp) & USART_BSCALE_gm) | ((bsel >> 8) & ~USART_BSCALE_gm);
60 | }
61 |
62 | void init_uart_bscale_bsel(USART_t *usart, int8_t bscale, int16_t bsel)
63 | {
64 | usart->CTRLA = 0;
65 | usart->CTRLB = USART_TXEN_bm | USART_RXEN_bm;
66 | usart->CTRLC = USART_CMODE_ASYNCHRONOUS_gc | USART_PMODE_DISABLED_gc | USART_CHSIZE_8BIT_gc;
67 | set_usartctrl(usart, bscale, bsel);
68 | }
69 |
70 |
71 | int _uart_putc(int ch)
72 | {
73 | while ( ! (USARTE0.STATUS & USART_DREIF_bm) ) {};
74 | USARTE0.DATA = (char) ch;
75 | return 1;
76 | }
77 |
78 |
79 | int uart_putc(int ch)
80 | {
81 | _uart_putc(ch);
82 | if (ch == '\n')
83 | {
84 | _uart_putc('\r');
85 | }
86 | return 1;
87 | }
88 |
89 | void uart_puts(unsigned char* s)
90 | {
91 | while(*s){
92 | uart_putc(*s);
93 | s++;
94 | }
95 | }
96 |
97 | int uart_getc(void)
98 | {
99 | while ( ! (USARTE0.STATUS & USART_RXCIF_bm) ) {};
100 | char ch = (char) USARTE0.DATA;
101 | return ch;
102 | }
103 |
104 | int uart_fputc(char c, FILE* stream)
105 | {
106 | uart_putc(c);
107 | return 0;
108 | }
109 |
110 | int keyboard_getc(void)
111 | {
112 | while ( ! (USARTD0.STATUS & USART_RXCIF_bm) ) {};
113 | unsigned char ch = (unsigned char) USARTD0.DATA;
114 | return ch;
115 | }
116 |
117 | int uart_fgetc(FILE* stream)
118 | {
119 | return keyboard_getc();
120 | }
121 |
122 | void tellymate_enable_transmit(void)
123 | {
124 | uart_putc(0x1b);
125 | for(int i=0; i<4; i++){
126 | uart_putc('~');
127 | }
128 | }
129 |
130 | int console_charat(int x, int y)
131 | {
132 | putchar(0x1b);
133 | putchar('`');
134 | putchar(' ' + y);
135 | putchar(' ' + x);
136 | return uart_getc();
137 | }
138 |
139 | FILE uart_stdio = FDEV_SETUP_STREAM(uart_fputc, uart_fgetc, _FDEV_SETUP_RW);
140 |
141 | void init_xmega(void)
142 | {
143 | PORTE.DIRSET = PIN3_bm;
144 | PORTE.DIRCLR = PIN2_bm;
145 | // init_uart_bscale_bsel(&USARTE0, -5, 3301); // 19K2 @ 32MHz
146 | init_uart_bscale_bsel(&USARTE0, -5, 1079); // 57K6 @ 32MHz
147 | PORTD.DIRSET = PIN3_bm;
148 | PORTD.DIRCLR = PIN2_bm;
149 | init_uart_bscale_bsel(&USARTD0, -5, 3301); // 19K2 @ 32MHz
150 | stdout = stdin = &uart_stdio;
151 |
152 | _delay_ms(500);
153 |
154 | _uart_putc(0x1b);
155 | _uart_putc('E');
156 | }
157 |
158 | static int
159 | do_joystick(basic_type* rv)
160 | {
161 | rv->kind = kind_numeric;
162 | rv->value.number = joystick_read_stick();
163 | return 0;
164 | }
165 |
166 | static int
167 | do_button(basic_type* rv)
168 | {
169 | rv->kind = kind_numeric;
170 | rv->value.number = joystick_read_button();
171 | return 0;
172 | }
173 |
174 | static int
175 | do_led(basic_type* status, basic_type* rv)
176 | {
177 | if(status->value.number>0){
178 | PORTE.OUTSET = PIN0_bm;
179 | } else {
180 | PORTE.OUTCLR = PIN0_bm;
181 | }
182 | rv->kind = kind_numeric;
183 | rv->value.number = 0;
184 | return 0;
185 | }
186 |
187 | static int
188 | do_sound(basic_type* freq, basic_type* duration, basic_type* rv)
189 | {
190 | sound_play((uint16_t)freq->value.number, (uint16_t)(1000*duration->value.number));
191 | rv->kind = kind_numeric;
192 | rv->value.number = 0;
193 | return 0;
194 | }
195 |
196 | static int
197 | do_plot(basic_type* x, basic_type* y, basic_type* code, basic_type* rv)
198 | {
199 | console_plot((int)x->value.number, (int)y->value.number, (unsigned char)code->value.number);
200 | rv->kind = kind_numeric;
201 | rv->value.number = 0;
202 | return 0;
203 | }
204 |
205 | static int
206 | do_defchar(basic_type* code, basic_type* definition, basic_type* rv)
207 | {
208 | console_def_char((unsigned char)code->value.number,definition->value.string);
209 | rv->kind = kind_numeric;
210 | rv->value.number = 0;
211 | return 0;
212 | }
213 |
214 | static int
215 | do_cursor(basic_type* cursor, basic_type* rv)
216 | {
217 | console_cursor((int)cursor->value.number);
218 | rv->kind = kind_numeric;
219 | rv->value.number = 0;
220 | return 0;
221 | }
222 |
223 | static int
224 | do_charat(basic_type* x, basic_type* y, basic_type* rv)
225 | {
226 | unsigned char at = console_charat((int)x->value.number, (int)y->value.number);
227 | rv->kind = kind_numeric;
228 | rv->value.number = at;
229 | return 0;
230 | }
231 |
232 | static int
233 | do_fontbank(basic_type* p1, basic_type* p2, basic_type* rv)
234 | {
235 | if(p2->empty){ // Called with 1 parameter
236 | int bank = (int) p1->value.number;
237 | for(int row=0; row<25; row++){
238 | console_fontbank(row, bank);
239 | }
240 | } else {
241 | int row = (int) p1->value.number;
242 | int bank = (int) p2->value.number;
243 | console_fontbank(row, bank);
244 | }
245 | rv->kind = kind_numeric;
246 | rv->value.number = 0;
247 | return 0;
248 | }
249 |
250 | static int
251 | do_gfx(basic_type* gfx, basic_type* rv)
252 | {
253 | if(gfx->value.number>0){
254 | console_cursor(0);
255 | console_cls();
256 | console_line_overflow(0);
257 | for(int row=0; row<25; row++){
258 | console_fontbank(row, 1);
259 | }
260 | } else {
261 | console_cursor(1);
262 | console_cls();
263 | console_line_overflow(1);
264 | for(int row=0; row<25; row++){
265 | console_fontbank(row, 0);
266 | }
267 | }
268 | rv->kind = kind_numeric;
269 | rv->value.number = 0;
270 | return 0;
271 | }
272 |
273 | static int
274 | do_hplot(basic_type* _x, basic_type* _y, basic_type* _set, basic_type* rv)
275 | {
276 | unsigned char x = (unsigned char)_x->value.number;
277 | unsigned char y = (unsigned char)_y->value.number;
278 | unsigned char set = (unsigned char)_set->value.number;
279 |
280 | unsigned char row ;
281 | unsigned char col ;
282 | unsigned char screen ;
283 |
284 | static unsigned char s_row = -1;
285 | static unsigned char s_col = -1;
286 | static unsigned char s_s = 0 ;
287 |
288 | row = y / 3 ; // 3 pixels down per character
289 | col = x / 2 ; // 2 pixels across per character
290 |
291 | if ((row == s_row) & (col == s_col))
292 | {
293 | screen = s_s;
294 | }
295 | else
296 | {
297 | screen = console_charat(col, row);
298 | }
299 |
300 | if (screen >= 0)
301 | {
302 | s_row = row;
303 | s_col = col;
304 |
305 | unsigned char s = screen;
306 | s = s & 0b00111111 ;
307 |
308 | unsigned char yy = row * 3;
309 | unsigned char xx = col * 2;
310 |
311 | unsigned char shift = 0;
312 | if (x > xx) shift += 1;
313 | if (y > yy) shift += 2;
314 | if (y > (yy+1)) shift += 2;
315 | unsigned char bitvalue = 1 << shift ;
316 |
317 | if (set)
318 | {
319 | s = s | bitvalue ; // set the bit
320 | }
321 | else
322 | {
323 | s = s & ~bitvalue ; // clear the bit
324 | }
325 | s = 0b11000000 | s ;
326 |
327 | s_s = s ;
328 |
329 | if (s != screen)
330 | {
331 | console_plot(col, row, s);
332 | }
333 | }
334 |
335 | rv->kind = kind_numeric;
336 | rv->value.number = 0;
337 | return 0;
338 | }
339 |
340 | static int
341 | do_overflow(basic_type* overflow, basic_type* rv)
342 | {
343 | if(overflow->value.number>0){
344 | console_line_overflow(1);
345 | } else {
346 | console_line_overflow(0);
347 | }
348 | rv->kind = kind_numeric;
349 | rv->value.number = 0;
350 | return 0;
351 | }
352 |
353 | static int
354 | do_invert(basic_type* invert, basic_type* rv)
355 | {
356 | if(invert->value.number>0){
357 | console_invert(1);
358 | } else {
359 | console_invert(0);
360 | }
361 | rv->kind = kind_numeric;
362 | rv->value.number = 0;
363 | return 0;
364 | }
365 |
366 | static int
367 | do_at(basic_type* x, basic_type* y, basic_type* rv)
368 | {
369 | rv->kind = kind_numeric;
370 | rv->value.number = 10;
371 | console_move_cursor((int)x->value.number, (int)y->value.number);
372 | return 0;
373 | }
374 |
375 | static void
376 | batch(char *filename)
377 | {
378 | FIL fil;
379 | FRESULT fr;
380 | char line[tokenizer_string_length];
381 | fr = f_open(&fil, filename, FA_READ);
382 | if(fr) return;
383 | while (f_gets(line, sizeof line, &fil)){
384 | basic_eval(line);
385 | }
386 | f_close(&fil);
387 | }
388 |
389 | static int
390 | do_batch(basic_type* rv)
391 | {
392 | char filename[8+1+3+1];
393 | accept(t_keyword_batch);
394 | if (sym != T_STRING) {
395 | error("EXPECTED LITERAL STRING");
396 | return 0;
397 | }
398 | char *name = tokenizer_get_string();
399 | accept(T_STRING);
400 | strncpy(filename,name,9);
401 | strcat(filename,".BAS");
402 | batch(filename);
403 | return 0;
404 | }
405 |
406 | int main(int argc, char *argv[])
407 | {
408 | char input[64];
409 |
410 | init_xtal();
411 | init_xmega();
412 | sound_init();
413 | joystick_init();
414 |
415 | PORTE.DIRSET = PIN0_bm; // LED
416 | PORTE.OUTSET = PIN0_bm; // on
417 |
418 | // timer
419 | TCC0.CTRLB = TC_WGMODE_NORMAL_gc;
420 | TCC0.CTRLA = TC_CLKSEL_DIV256_gc;
421 | TCC0.INTCTRLA = TC_OVFINTLVL_LO_gc;
422 | TCC0.PER = 1249; // t = N * (PER+1) / f
423 | PMIC.CTRL |= PMIC_LOLVLEN_bm;
424 | sei();
425 |
426 | tellymate_enable_transmit();
427 | console_cursor(1);
428 | console_cursor_type(1);
429 | console_line_overflow(1);
430 | puts(" (\\/)");
431 | puts(" ( ..)");
432 | puts("C(\")(\")");
433 | puts("");
434 | puts("~BASIC-1~");
435 | puts("(c) 2015-2017 JVdB");
436 | puts("");
437 |
438 | for(uint16_t i=0; i<3; i++){
439 | sound_play(1000, 50);
440 | sound_play(0, 50);
441 | }
442 | sound_play(1000, 100);
443 |
444 | basic_register_io(uart_putc, keyboard_getc);
445 | basic_init(3072, 256);
446 |
447 | register_function_2(basic_function_type_keyword, "SOUND", do_sound, kind_numeric, kind_numeric);
448 | register_function_1(basic_function_type_keyword, "LED", do_led, kind_numeric);
449 | register_function_0(basic_function_type_numeric, "JOYSTICK", do_joystick);
450 | register_function_0(basic_function_type_numeric, "BUTTON", do_button);
451 | register_function_3(basic_function_type_keyword, "PLOT", do_plot, kind_numeric, kind_numeric, kind_numeric);
452 | register_function_2(basic_function_type_keyword, "DEFCHAR", do_defchar, kind_numeric, kind_string);
453 | register_function_1(basic_function_type_keyword, "CURSOR", do_cursor, kind_numeric);
454 | register_function_2(basic_function_type_numeric, "CHARAT", do_charat, kind_numeric, kind_numeric);
455 | register_function_2(basic_function_type_keyword, "FONTBANK", do_fontbank, kind_numeric, kind_numeric);
456 | register_function_1(basic_function_type_keyword, "GFX", do_gfx, kind_numeric);
457 | register_function_3(basic_function_type_keyword, "HPLOT", do_hplot, kind_numeric, kind_numeric, kind_numeric);
458 | register_function_1(basic_function_type_keyword, "OVERFLOW", do_overflow, kind_numeric);
459 | register_function_1(basic_function_type_keyword, "INVERT", do_invert, kind_numeric);
460 | register_function_2(basic_function_type_keyword, "AT", do_at, kind_numeric, kind_numeric);
461 | t_keyword_batch = register_function_0(basic_function_type_keyword, "BATCH", do_batch);
462 |
463 | batch("AUTORUN.BAS");
464 |
465 | while(1)
466 | {
467 | basic_io_readline("", input, sizeof(input));
468 | basic_eval(input);
469 | if (evaluate_last_error()) {
470 | printf("ERR LINE %d: %s\n", __line, evaluate_last_error());
471 | clear_last_error();
472 | }
473 | if(__STOPPED){
474 | console_cursor(1);
475 | __STOPPED = false;
476 | }
477 | }
478 |
479 | return EXIT_SUCCESS;
480 | }
481 |
--------------------------------------------------------------------------------
/arch/xmega/mmc.c:
--------------------------------------------------------------------------------
1 | /*-----------------------------------------------------------------------*/
2 | /* MMCv3/SDv1/SDv2 Controls via AVR USART-SPI */
3 | /*-----------------------------------------------------------------------*/
4 | /*
5 | / Copyright (C) 2016, ChaN, all right reserved.
6 | /
7 | / * This software is a free software and there is NO WARRANTY.
8 | / * No restriction on use. You can use, modify and redistribute it for
9 | / any purpose as you like UNDER YOUR RESPONSIBILITY.
10 | / * Redistributions of source code must retain the above copyright notice.
11 | /
12 | /-------------------------------------------------------------------------*/
13 |
14 | #include
15 | #include "diskio.h"
16 |
17 | #include "spi.h"
18 |
19 | /*--------------------------------------------------------------------------
20 |
21 | Module Private Functions
22 |
23 | ---------------------------------------------------------------------------*/
24 |
25 | /* Definitions for MMC/SDC command */
26 | #define CMD0 (0) /* GO_IDLE_STATE */
27 | #define CMD1 (1) /* SEND_OP_COND (MMC) */
28 | #define ACMD41 (0x80+41) /* SEND_OP_COND (SDC) */
29 | #define CMD8 (8) /* SEND_IF_COND */
30 | #define CMD9 (9) /* SEND_CSD */
31 | #define CMD10 (10) /* SEND_CID */
32 | #define CMD12 (12) /* STOP_TRANSMISSION */
33 | #define ACMD13 (0x80+13) /* SD_STATUS (SDC) */
34 | #define CMD16 (16) /* SET_BLOCKLEN */
35 | #define CMD17 (17) /* READ_SINGLE_BLOCK */
36 | #define CMD18 (18) /* READ_MULTIPLE_BLOCK */
37 | #define CMD23 (23) /* SET_BLOCK_COUNT (MMC) */
38 | #define ACMD23 (0x80+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */
39 | #define CMD24 (24) /* WRITE_BLOCK */
40 | #define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */
41 | #define CMD32 (32) /* ERASE_ER_BLK_START */
42 | #define CMD33 (33) /* ERASE_ER_BLK_END */
43 | #define CMD38 (38) /* ERASE */
44 | #define CMD48 (48) /* READ_EXTR_SINGLE */
45 | #define CMD49 (49) /* WRITE_EXTR_SINGLE */
46 | #define CMD55 (55) /* APP_CMD */
47 | #define CMD58 (58) /* READ_OCR */
48 |
49 |
50 | static volatile
51 | DSTATUS Stat = STA_NOINIT; /* Disk status */
52 |
53 | static volatile
54 | BYTE Timer1, Timer2; /* 100Hz decrement timer */
55 |
56 | static
57 | BYTE CardType; /* Card type flags (b0:MMC, b1:SDv1, b2:SDv2, b3:Block addressing) */
58 |
59 |
60 | /*-----------------------------------------------------------------------*/
61 | /* Power Control (Platform dependent) */
62 | /*-----------------------------------------------------------------------*/
63 | /* When the target system does not support socket power control, there */
64 | /* is nothing to do in these functions and chk_power always returns 1. */
65 |
66 | static
67 | void power_on (void)
68 | {}
69 |
70 |
71 | static
72 | void power_off (void)
73 | {}
74 |
75 |
76 |
77 | /*-----------------------------------------------------------------------*/
78 | /* Transmit/Receive data from/to MMC via SPI (Platform dependent) */
79 | /*-----------------------------------------------------------------------*/
80 |
81 | /* Exchange a byte */
82 | static
83 | BYTE xchg_spi ( /* Returns received data */
84 | BYTE dat /* Data to be sent */
85 | )
86 | {
87 | return spi_transfer(dat);
88 | }
89 |
90 | /* Receive a data block fast */
91 | static
92 | void rcvr_spi_multi (
93 | BYTE *p, /* Data read buffer */
94 | UINT cnt /* Size of data block */
95 | )
96 | {
97 | while(cnt--) *p++ = spi_read();
98 | }
99 |
100 |
101 | /* Send a data block fast */
102 | static
103 | void xmit_spi_multi (
104 | const BYTE *p, /* Data block to be sent */
105 | UINT cnt /* Size of data block */
106 | )
107 | {
108 | while(cnt--) spi_write(*p++);
109 | }
110 |
111 | #define FCLK_SLOW() spi_slow()
112 | #define FCLK_FAST() spi_fast()
113 | #define MMC_WP 0
114 | #define MMC_CD 1
115 |
116 | /*-----------------------------------------------------------------------*/
117 | /* Wait for card ready */
118 | /*-----------------------------------------------------------------------*/
119 |
120 | static
121 | int wait_ready ( /* 1:Ready, 0:Timeout */
122 | UINT wt /* Timeout [ms] */
123 | )
124 | {
125 | BYTE d;
126 |
127 |
128 | Timer2 = wt / 10;
129 | do
130 | d = xchg_spi(0xFF);
131 | while (d != 0xFF && Timer2);
132 |
133 | return (d == 0xFF) ? 1 : 0;
134 | }
135 |
136 |
137 |
138 | /*-----------------------------------------------------------------------*/
139 | /* Deselect the card and release SPI bus */
140 | /*-----------------------------------------------------------------------*/
141 |
142 | static
143 | void deselect (void)
144 | {
145 | spi_cs_high(); /* Set CS# high */
146 | xchg_spi(0xFF); /* Dummy clock (force DO hi-z for multiple slave SPI) */
147 | }
148 |
149 |
150 |
151 | /*-----------------------------------------------------------------------*/
152 | /* Select the card and wait for ready */
153 | /*-----------------------------------------------------------------------*/
154 |
155 | static
156 | int select (void) /* 1:Successful, 0:Timeout */
157 | {
158 | spi_cs_low(); /* Set CS# low */
159 | xchg_spi(0xFF); /* Dummy clock (force DO enabled) */
160 | if (wait_ready(500)) return 1; /* Wait for card ready */
161 |
162 | deselect();
163 | return 0; /* Timeout */
164 | }
165 |
166 |
167 |
168 | /*-----------------------------------------------------------------------*/
169 | /* Receive a data packet from MMC */
170 | /*-----------------------------------------------------------------------*/
171 |
172 | static
173 | int rcvr_datablock (
174 | BYTE *buff, /* Data buffer to store received data */
175 | UINT btr /* Byte count (must be multiple of 4) */
176 | )
177 | {
178 | BYTE token;
179 |
180 |
181 | Timer1 = 20;
182 | do { /* Wait for data packet in timeout of 200ms */
183 | token = xchg_spi(0xFF);
184 | } while ((token == 0xFF) && Timer1);
185 | if (token != 0xFE) return 0; /* If not valid data token, retutn with error */
186 |
187 | rcvr_spi_multi(buff, btr); /* Receive the data block into buffer */
188 | xchg_spi(0xFF); /* Discard CRC */
189 | xchg_spi(0xFF);
190 |
191 | return 1; /* Return with success */
192 | }
193 |
194 |
195 |
196 | /*-----------------------------------------------------------------------*/
197 | /* Send a data packet to MMC */
198 | /*-----------------------------------------------------------------------*/
199 |
200 | #if _USE_WRITE
201 | static
202 | int xmit_datablock (
203 | const BYTE *buff, /* 512 byte data block to be transmitted */
204 | BYTE token /* Data/Stop token */
205 | )
206 | {
207 | BYTE resp;
208 |
209 |
210 | if (!wait_ready(500)) return 0;
211 |
212 | xchg_spi(token); /* Xmit data token */
213 | if (token != 0xFD) { /* Is data token */
214 | xmit_spi_multi(buff, 512); /* Xmit the data block to the MMC */
215 | xchg_spi(0xFF); /* CRC (Dummy) */
216 | xchg_spi(0xFF);
217 | resp = xchg_spi(0xFF); /* Reveive data response */
218 | if ((resp & 0x1F) != 0x05) /* If not accepted, return with error */
219 | return 0;
220 | }
221 |
222 | return 1;
223 | }
224 | #endif
225 |
226 |
227 |
228 | /*-----------------------------------------------------------------------*/
229 | /* Send a command packet to MMC */
230 | /*-----------------------------------------------------------------------*/
231 |
232 | static
233 | BYTE send_cmd ( /* Returns R1 resp (bit7==1:Send failed) */
234 | BYTE cmd, /* Command index */
235 | DWORD arg /* Argument */
236 | )
237 | {
238 | BYTE n, res;
239 |
240 |
241 | if (cmd & 0x80) { /* ACMD is the command sequense of CMD55-CMD */
242 | cmd &= 0x7F;
243 | res = send_cmd(CMD55, 0);
244 | if (res > 1) return res;
245 | }
246 |
247 | /* Select the card and wait for ready except to stop multiple block read */
248 | if (cmd != CMD12) {
249 | deselect();
250 | if (!select()) return 0xFF;
251 | }
252 |
253 | /* Send command packet */
254 | xchg_spi(0x40 | cmd); /* Start + Command index */
255 | xchg_spi((BYTE)(arg >> 24)); /* Argument[31..24] */
256 | xchg_spi((BYTE)(arg >> 16)); /* Argument[23..16] */
257 | xchg_spi((BYTE)(arg >> 8)); /* Argument[15..8] */
258 | xchg_spi((BYTE)arg); /* Argument[7..0] */
259 | n = 0x01; /* Dummy CRC + Stop */
260 | if (cmd == CMD0) n = 0x95; /* Valid CRC for CMD0(0) + Stop */
261 | if (cmd == CMD8) n = 0x87; /* Valid CRC for CMD8(0x1AA) Stop */
262 | xchg_spi(n);
263 |
264 | /* Receive command response */
265 | if (cmd == CMD12) xchg_spi(0xFF); /* Skip a stuff byte when stop reading */
266 | n = 10; /* Wait for a valid response in timeout of 10 attempts */
267 | do
268 | res = xchg_spi(0xFF);
269 | while ((res & 0x80) && --n);
270 |
271 | return res; /* Return with the response value */
272 | }
273 |
274 |
275 |
276 | /*--------------------------------------------------------------------------
277 |
278 | Public Functions
279 |
280 | ---------------------------------------------------------------------------*/
281 |
282 |
283 | /*-----------------------------------------------------------------------*/
284 | /* Initialize Disk Drive */
285 | /*-----------------------------------------------------------------------*/
286 |
287 | DSTATUS disk_initialize (BYTE pdrv)
288 | {
289 | BYTE n, cmd, ty, ocr[4];
290 |
291 |
292 | power_off(); /* Turn off the socket power to reset the card */
293 | for (Timer1 = 10; Timer1; ) ; /* Wait for 100ms */
294 | if (Stat & STA_NODISK) return Stat; /* No card in the socket? */
295 |
296 | power_on(); /* Turn on the socket power */
297 | FCLK_SLOW();
298 | for (n = 10; n; n--) xchg_spi(0xFF); /* 80 dummy clocks */
299 |
300 | ty = 0;
301 | if (send_cmd(CMD0, 0) == 1) { /* Put the card SPI mode */
302 | Timer1 = 100; /* Initialization timeout of 1000 msec */
303 | if (send_cmd(CMD8, 0x1AA) == 1) { /* Is the card SDv2? */
304 | for (n = 0; n < 4; n++) ocr[n] = xchg_spi(0xFF); /* Get trailing return value of R7 resp */
305 | if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */
306 | while (Timer1 && send_cmd(ACMD41, 1UL << 30)); /* Wait for leaving idle state (ACMD41 with HCS bit) */
307 | if (Timer1 && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */
308 | for (n = 0; n < 4; n++) ocr[n] = xchg_spi(0xFF);
309 | ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* Check if the card is SDv2 */
310 | }
311 | }
312 | } else { /* SDv1 or MMCv3 */
313 | if (send_cmd(ACMD41, 0) <= 1) {
314 | ty = CT_SD1; cmd = ACMD41; /* SDv1 */
315 | } else {
316 | ty = CT_MMC; cmd = CMD1; /* MMCv3 */
317 | }
318 | while (Timer1 && send_cmd(cmd, 0)); /* Wait for leaving idle state */
319 | if (!Timer1 || send_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */
320 | ty = 0;
321 | }
322 | }
323 | CardType = ty;
324 | deselect();
325 |
326 | if (ty) { /* Initialization succeded */
327 | Stat &= ~STA_NOINIT; /* Clear STA_NOINIT */
328 | FCLK_FAST();
329 | } else { /* Initialization failed */
330 | power_off();
331 | }
332 |
333 | return Stat;
334 | }
335 |
336 |
337 |
338 | /*-----------------------------------------------------------------------*/
339 | /* Get Disk Status */
340 | /*-----------------------------------------------------------------------*/
341 |
342 | DSTATUS disk_status (BYTE pdrv)
343 | {
344 | return Stat;
345 | }
346 |
347 |
348 |
349 | /*-----------------------------------------------------------------------*/
350 | /* Read Sector(s) */
351 | /*-----------------------------------------------------------------------*/
352 |
353 | DRESULT disk_read (
354 | BYTE pdrv,
355 | BYTE *buff, /* Pointer to the data buffer to store read data */
356 | DWORD sector, /* Start sector number (LBA) */
357 | UINT count /* Sector count (1..128) */
358 | )
359 | {
360 | BYTE cmd;
361 |
362 |
363 | if (!count) return RES_PARERR;
364 | if (Stat & STA_NOINIT) return RES_NOTRDY;
365 |
366 | if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */
367 |
368 | cmd = count > 1 ? CMD18 : CMD17; /* READ_MULTIPLE_BLOCK : READ_SINGLE_BLOCK */
369 | if (send_cmd(cmd, sector) == 0) {
370 | do {
371 | if (!rcvr_datablock(buff, 512)) break;
372 | buff += 512;
373 | } while (--count);
374 | if (cmd == CMD18) send_cmd(CMD12, 0); /* STOP_TRANSMISSION */
375 | }
376 | deselect();
377 |
378 | return count ? RES_ERROR : RES_OK;
379 | }
380 |
381 |
382 |
383 | /*-----------------------------------------------------------------------*/
384 | /* Write Sector(s) */
385 | /*-----------------------------------------------------------------------*/
386 |
387 | #if _USE_WRITE
388 | DRESULT disk_write (
389 | BYTE pdrv,
390 | const BYTE *buff, /* Pointer to the data to be written */
391 | DWORD sector, /* Start sector number (LBA) */
392 | UINT count /* Sector count (1..128) */
393 | )
394 | {
395 | if (!count) return RES_PARERR;
396 | if (Stat & STA_NOINIT) return RES_NOTRDY;
397 | if (Stat & STA_PROTECT) return RES_WRPRT;
398 |
399 | if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */
400 |
401 | if (count == 1) { /* Single block write */
402 | if ((send_cmd(CMD24, sector) == 0) /* WRITE_BLOCK */
403 | && xmit_datablock(buff, 0xFE))
404 | count = 0;
405 | }
406 | else { /* Multiple block write */
407 | if (CardType & CT_SDC) send_cmd(ACMD23, count);
408 | if (send_cmd(CMD25, sector) == 0) { /* WRITE_MULTIPLE_BLOCK */
409 | do {
410 | if (!xmit_datablock(buff, 0xFC)) break;
411 | buff += 512;
412 | } while (--count);
413 | if (!xmit_datablock(0, 0xFD)) /* STOP_TRAN token */
414 | count = 1;
415 | }
416 | }
417 | deselect();
418 |
419 | return count ? RES_ERROR : RES_OK;
420 | }
421 | #endif
422 |
423 |
424 | /*-----------------------------------------------------------------------*/
425 | /* Miscellaneous Functions */
426 | /*-----------------------------------------------------------------------*/
427 |
428 | #if _USE_IOCTL
429 | DRESULT disk_ioctl (
430 | BYTE pdrv,
431 | BYTE cmd, /* Control code */
432 | void *buff /* Buffer to send/receive control data */
433 | )
434 | {
435 | DRESULT res;
436 | BYTE n, csd[16], *ptr = buff;
437 | DWORD csize;
438 | #if _USE_ISDIO
439 | SDIO_CTRL *sdi;
440 | BYTE rc, *bp;
441 | UINT dc;
442 | #endif
443 |
444 | if (Stat & STA_NOINIT) return RES_NOTRDY;
445 |
446 | res = RES_ERROR;
447 | switch (cmd) {
448 | case CTRL_SYNC : /* Make sure that no pending write process. Do not remove this or written sector might not left updated. */
449 | if (select()) res = RES_OK;
450 | deselect();
451 | break;
452 |
453 | case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */
454 | if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) {
455 | if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */
456 | csize = csd[9] + ((WORD)csd[8] << 8) + ((DWORD)(csd[7] & 63) << 16) + 1;
457 | *(DWORD*)buff = csize << 10;
458 | } else { /* SDC ver 1.XX or MMC*/
459 | n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
460 | csize = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1;
461 | *(DWORD*)buff = csize << (n - 9);
462 | }
463 | res = RES_OK;
464 | }
465 | deselect();
466 | break;
467 |
468 | case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */
469 | if (CardType & CT_SD2) { /* SDv2? */
470 | if (send_cmd(ACMD13, 0) == 0) { /* Read SD status */
471 | xchg_spi(0xFF);
472 | if (rcvr_datablock(csd, 16)) { /* Read partial block */
473 | for (n = 64 - 16; n; n--) xchg_spi(0xFF); /* Purge trailing data */
474 | *(DWORD*)buff = 16UL << (csd[10] >> 4);
475 | res = RES_OK;
476 | }
477 | }
478 | } else { /* SDv1 or MMCv3 */
479 | if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { /* Read CSD */
480 | if (CardType & CT_SD1) { /* SDv1 */
481 | *(DWORD*)buff = (((csd[10] & 63) << 1) + ((WORD)(csd[11] & 128) >> 7) + 1) << ((csd[13] >> 6) - 1);
482 | } else { /* MMCv3 */
483 | *(DWORD*)buff = ((WORD)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3) << 3) + ((csd[11] & 224) >> 5) + 1);
484 | }
485 | res = RES_OK;
486 | }
487 | }
488 | deselect();
489 | break;
490 |
491 | /* Following commands are never used by FatFs module */
492 |
493 | case MMC_GET_TYPE : /* Get card type flags (1 byte) */
494 | *ptr = CardType;
495 | res = RES_OK;
496 | break;
497 |
498 | case MMC_GET_CSD : /* Receive CSD as a data block (16 bytes) */
499 | if (send_cmd(CMD9, 0) == 0 && rcvr_datablock(ptr, 16)) /* READ_CSD */
500 | res = RES_OK;
501 | deselect();
502 | break;
503 |
504 | case MMC_GET_CID : /* Receive CID as a data block (16 bytes) */
505 | if (send_cmd(CMD10, 0) == 0 && rcvr_datablock(ptr, 16)) /* READ_CID */
506 |
507 | res = RES_OK;
508 | deselect();
509 | break;
510 |
511 | case MMC_GET_OCR : /* Receive OCR as an R3 resp (4 bytes) */
512 | if (send_cmd(CMD58, 0) == 0) { /* READ_OCR */
513 | for (n = 4; n; n--) *ptr++ = xchg_spi(0xFF);
514 | res = RES_OK;
515 | }
516 | deselect();
517 | break;
518 |
519 | case MMC_GET_SDSTAT : /* Receive SD statsu as a data block (64 bytes) */
520 | if (send_cmd(ACMD13, 0) == 0) { /* SD_STATUS */
521 | xchg_spi(0xFF);
522 | if (rcvr_datablock(ptr, 64)) res = RES_OK;
523 | }
524 | deselect();
525 | break;
526 |
527 | case CTRL_POWER_OFF : /* Power off */
528 | power_off();
529 | Stat |= STA_NOINIT;
530 | res = RES_OK;
531 | break;
532 | #if _USE_ISDIO
533 | case ISDIO_READ:
534 | sdi = buff;
535 | if (send_cmd(CMD48, 0x80000000 | (DWORD)sdi->func << 28 | (DWORD)sdi->addr << 9 | ((sdi->ndata - 1) & 0x1FF)) == 0) {
536 | for (Timer1 = 100; (rc = xchg_spi(0xFF)) == 0xFF && Timer1; ) ;
537 | if (rc == 0xFE) {
538 | for (bp = sdi->data, dc = sdi->ndata; dc; dc--) *bp++ = xchg_spi(0xFF);
539 | for (dc = 514 - sdi->ndata; dc; dc--) xchg_spi(0xFF);
540 | res = RES_OK;
541 | }
542 | }
543 | deselect();
544 | break;
545 |
546 | case ISDIO_WRITE:
547 | sdi = buff;
548 | if (send_cmd(CMD49, 0x80000000 | (DWORD)sdi->func << 28 | (DWORD)sdi->addr << 9 | ((sdi->ndata - 1) & 0x1FF)) == 0) {
549 | xchg_spi(0xFF); xchg_spi(0xFE);
550 | for (bp = sdi->data, dc = sdi->ndata; dc; dc--) xchg_spi(*bp++);
551 | for (dc = 514 - sdi->ndata; dc; dc--) xchg_spi(0xFF);
552 | if ((xchg_spi(0xFF) & 0x1F) == 0x05) res = RES_OK;
553 | }
554 | deselect();
555 | break;
556 |
557 | case ISDIO_MRITE:
558 | sdi = buff;
559 | if (send_cmd(CMD49, 0x84000000 | (DWORD)sdi->func << 28 | (DWORD)sdi->addr << 9 | sdi->ndata >> 8) == 0) {
560 | xchg_spi(0xFF); xchg_spi(0xFE);
561 | xchg_spi(sdi->ndata);
562 | for (dc = 513; dc; dc--) xchg_spi(0xFF);
563 | if ((xchg_spi(0xFF) & 0x1F) == 0x05) res = RES_OK;
564 | }
565 | deselect();
566 | break;
567 | #endif
568 | default:
569 | res = RES_PARERR;
570 | }
571 |
572 | return res;
573 | }
574 | #endif
575 |
576 |
577 | /*-----------------------------------------------------------------------*/
578 | /* Device Timer Interrupt Procedure */
579 | /*-----------------------------------------------------------------------*/
580 | /* This function must be called in period of 10ms */
581 |
582 | void disk_timerproc (void)
583 | {
584 | BYTE n, s;
585 |
586 |
587 | n = Timer1; /* 100Hz decrement timer */
588 | if (n) Timer1 = --n;
589 | n = Timer2;
590 | if (n) Timer2 = --n;
591 |
592 | s = Stat;
593 |
594 | if (MMC_WP) /* Write protected */
595 | s |= STA_PROTECT;
596 | else /* Write enabled */
597 | s &= ~STA_PROTECT;
598 |
599 | if (MMC_CD) /* Card inserted */
600 | s &= ~STA_NODISK;
601 | else /* Socket empty */
602 | s |= (STA_NODISK | STA_NOINIT);
603 |
604 | Stat = s; /* Update MMC status */
605 | }
606 |
607 |
--------------------------------------------------------------------------------
/arch/xmega/mmc.h:
--------------------------------------------------------------------------------
1 | #ifndef __MMC_H__
2 | #define __MMC_H__
3 |
4 | #include "diskio.h"
5 |
6 | #endif // __MMC_H__
7 |
--------------------------------------------------------------------------------
/arch/xmega/sound.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | static volatile size_t _sound_ticks;
8 |
9 | void sound_timerproc(void)
10 | {
11 | if(_sound_ticks>0){
12 | _sound_ticks--;
13 | return;
14 | }
15 | }
16 |
17 | void sound_init(void)
18 | {
19 | PORTE.OUTCLR = PIN1_bm;
20 | PORTE.DIRSET = PIN1_bm;
21 | TCE0.CTRLA = TC_CLKSEL_OFF_gc;
22 | TCE0.CTRLB = TC0_CCBEN_bm| TC_WGMODE_FRQ_gc;
23 | }
24 |
25 | void sound_play(uint16_t f, uint16_t ms)
26 | {
27 | _sound_ticks = ms / 10;
28 | if (f>0){
29 | TCE0.CCABUF = (((uint32_t) F_CPU/f) >> 2) - 1;
30 | TCE0.CNT = 0; // reset timer/counter
31 | TCE0.CTRLA = TC_CLKSEL_DIV2_gc; // prescaling
32 | }
33 | while(_sound_ticks > 0){
34 | __asm__ volatile ("nop");
35 | }
36 | if(f>0){
37 | TCE0.CTRLA = TC_CLKSEL_OFF_gc; // timer/counter off
38 | TCE0.CTRLC = 0; // outputs low
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/arch/xmega/sound.h:
--------------------------------------------------------------------------------
1 | #ifndef __SOUND_H__
2 | #define __SOUND_H__
3 |
4 | void sound_timerproc(void);
5 | void sound_init(void);
6 | void sound_play(uint16_t freq, uint16_t duration);
7 |
8 | #endif
9 |
--------------------------------------------------------------------------------
/arch/xmega/spi.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include "spi.h"
3 |
4 | #define SPI_SS_bm 0x10
5 | #define SPI_MOSI_bm 0x20
6 | #define SPI_MISO_bm 0x40
7 | #define SPI_SCK_bm 0x80
8 |
9 | #define FOO 0x00
10 |
11 | void spi_init(void)
12 | {
13 | PORTC.DIRSET = SPI_SCK_bm | SPI_MOSI_bm | SPI_SS_bm;
14 | PORTC.DIRCLR = SPI_MISO_bm;
15 | PORTC.OUTSET = SPI_SS_bm;
16 | spi_fast();
17 | }
18 |
19 | void spi_fast(void)
20 | {
21 | SPIC.CTRL = SPI_ENABLE_bm | SPI_MASTER_bm | SPI_MODE_0_gc | SPI_PRESCALER_DIV4_gc;
22 | }
23 |
24 | void spi_slow(void)
25 | {
26 | SPIC.CTRL = SPI_ENABLE_bm | SPI_MASTER_bm | SPI_MODE_0_gc | SPI_PRESCALER_DIV128_gc;
27 | }
28 |
29 | uint8_t spi_transfer(uint8_t data)
30 | {
31 | SPIC.DATA = data;
32 | while(!(SPIC.STATUS & (SPI_IF_bm)));
33 | return SPIC.DATA;
34 | }
35 |
36 | void spi_write(uint8_t data)
37 | {
38 | // PORTC.OUTCLR = SPI_SS_bm;
39 | spi_transfer(data);
40 | // PORTC.OUTSET = SPI_SS_bm;
41 | }
42 |
43 | uint8_t spi_read(void)
44 | {
45 | uint8_t data;
46 |
47 | // PORTC.OUTCLR = SPI_SS_bm;
48 | data = spi_transfer(FOO);
49 | // PORTC.OUTSET = SPI_SS_bm;
50 |
51 | return data;
52 | }
53 |
54 | void spi_cs_high(void)
55 | {
56 | PORTC.OUTSET = SPI_SS_bm;
57 | // PORTC.OUTCLR = SPI_SS_bm;
58 | }
59 |
60 | void spi_cs_low(void)
61 | {
62 | PORTC.OUTCLR = SPI_SS_bm;
63 | // PORTC.OUTSET = SPI_SS_bm;
64 | }
65 |
--------------------------------------------------------------------------------
/arch/xmega/spi.h:
--------------------------------------------------------------------------------
1 | #ifndef __SPI_H__
2 | #define __SPI_H__
3 |
4 | void spi_init(void);
5 | uint8_t spi_transfer(uint8_t data);
6 | void spi_write(uint8_t data);
7 | uint8_t spi_read(void);
8 | void spi_cs_high(void);
9 | void spi_cs_low(void);
10 | void spi_fast(void);
11 | void spi_slow(void);
12 |
13 | #endif // __SPI_H__
14 |
--------------------------------------------------------------------------------
/basic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nanoflite/basic/10e52bc52aa107890580aef659f8180ddbff3125/basic.png
--------------------------------------------------------------------------------
/examples/FORY.bas:
--------------------------------------------------------------------------------
1 | 10 FOR X=1 TO 30
2 | 20 LET Y=X
3 | 30 PRINT Y
4 | 40 NEXT X
5 |
--------------------------------------------------------------------------------
/examples/autolist:
--------------------------------------------------------------------------------
1 | ./examples/FORY.bas
2 | ./examples/circle.bas
3 | ./examples/data.bas
4 | ./examples/data_array.bas
5 | ./examples/data_numeric.bas
6 | ./examples/diamond.bas
7 | ./examples/dim.bas
8 | ./examples/expr.bas
9 | ./examples/for.bas
10 | ./examples/for_colon.bas
11 | ./examples/gosub.bas
12 | ./examples/goto.bas
13 | ./examples/if.bas
14 | ./examples/if_and_or.bas
15 | ./examples/if_goto.bas
16 | ./examples/left.bas
17 | ./examples/math.bas
18 | ./examples/mid.bas
19 | ./examples/nested_for.bas
20 | ./examples/on_goto.bas
21 | ./examples/right.bas
22 | ./examples/sine_wave.bas
23 | ./examples/sleep.bas
24 | ./examples/strings.bas
25 | ./examples/test_for.bas
26 | ./examples/the_first_basic_program.bas
27 |
--------------------------------------------------------------------------------
/examples/circle.bas:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env basic
2 |
3 | 10 RADIUS=10
4 | 20 FOR I=1 TO RADIUS-1
5 | 30 W=INT(RADIUS*SIN(180/RADIUS*I*3.1415/180))
6 | 40 PRINT SPC(RADIUS-W);:FOR J=1 TO 2*W:PRINT "*";:NEXT J:PRINT
7 | 50 NEXT I
8 |
--------------------------------------------------------------------------------
/examples/data.bas:
--------------------------------------------------------------------------------
1 | 100 PRINT "DATA TEST"
2 | 110 READ A$
3 | 115 PRINT "VALUE A"
4 | 120 PRINT A$
5 | 130 READ B$
6 | 135 PRINT "VALUE B"
7 | 140 PRINT B$
8 | 150 RESTORE
9 | 160 READ A$
10 | 170 PRINT "VALUE A: ";
11 | 180 PRINT A$
12 | 190 END
13 | 200 DATA "Ik ben DATA", "En ik ook"
14 |
--------------------------------------------------------------------------------
/examples/data_array.bas:
--------------------------------------------------------------------------------
1 | 1000 PRINT "### DATA READ INTO ARRAY ###"
2 | 1010 DIM A(5)
3 | 1025 PRINT "READ DATA"
4 | 1020 FOR I=1 TO 5
5 | 1025 PRINT "READ INDEX ";I
6 | 1030 READ A(I)
7 | 1035 PRINT "DONE"
8 | 1040 NEXT
9 | 1050 PRINT "PRINT DATA"
10 | 1060 FOR I=1 TO 5
11 | 1070 PRINT A(I)
12 | 1080 NEXT
13 | 1090 PRINT "DONE"
14 | 1050 END
15 | 2000 DATA 10,20,30,40,50
16 |
--------------------------------------------------------------------------------
/examples/data_numeric.bas:
--------------------------------------------------------------------------------
1 | 100 PRINT "DATA/READ/RESTORE TEST"
2 | 110 READ A, B, C
3 | 120 PRINT A
4 | 130 PRINT B
5 | 140 PRINT C
6 | 150 RESTORE
7 | 160 READ D, E, F
8 | 170 PRINT D
9 | 180 PRINT E
10 | 190 PRINT F
11 | 200 DATA 1,2
12 | 205 REM MORE DATA
13 | 210 DATA 3
14 |
--------------------------------------------------------------------------------
/examples/data_test.bas:
--------------------------------------------------------------------------------
1 | 100 FOR I=0 TO 31
2 | 110 READ D$
3 | 120 PRINT D$
4 | 130 NEXT I
5 | 1000 END
6 | 5000 DATA "000000030C10207C82","000000F028444A4A22"
7 | 5010 DATA "827C20180601000000","1E215E221CE0000000"
8 | 5020 DATA "000000030C10788482","C64438080601000000"
9 | 5030 DATA "000000030C10204040","7E8182844E39000000"
10 | 5040 DATA "0000000000000000FC","043434370404353535"
11 | 5050 DATA "040535353404053535","3404C4C4C400000000"
12 | 5060 DATA "000000000000070404","050505FC0405B5B5B4"
13 | 5070 DATA "04B5B5B50404B5B5B5","0404E5E5E500000000"
14 | 5080 DATA "1F1010131313F00000","999999000099999900"
15 | 5090 DATA "009999990000999999","000099999900000000"
16 | 5100 DATA "E0202020202020203F","A0A0AC2C2CA0A0AC2C"
17 | 5110 DATA "2CA0ACAC2C20A0ACAC","2C20ADADA100000000"
18 | 5120 DATA "191919191919191919","F8F8F8F8F8F8F8F8F8"
19 | 5130 DATA "FFFFC0C0CFCFFFFF00","FFFF0303FFFFFFFF00"
20 | 5140 DATA "00FFFFCFCFC0C0FFFF","00FFFFFFFF0303FFFF"
21 | 5150 DATA "FFFEFCF8F0E0C08000","0103070F1F3F7FFF00"
22 |
--------------------------------------------------------------------------------
/examples/diamond.bas:
--------------------------------------------------------------------------------
1 | #!/Users/johan/Projects/BASIC/basic/build/basic/basic
2 |
3 | 10 LINES=17
4 | 20 FOR I=1 TO LINES/2+1
5 | 30 FOR J=1 TO (LINES+1)/2-I+1:PRINT " ";:NEXT
6 | 40 FOR J=1 TO I*2-1:PRINT "*";:NEXT
7 | 50 PRINT
8 | 60 NEXT I
9 | 70 FOR I=1 TO LINES/2
10 | 80 FOR J=1 TO I+1:PRINT " ";:NEXT
11 | 90 FOR J=1 TO ((LINES+1)/2-I)*2-1:PRINT "*";:NEXT
12 | 100 PRINT
13 | 110 NEXT I
14 |
--------------------------------------------------------------------------------
/examples/dim.bas:
--------------------------------------------------------------------------------
1 | 1000 DIM A(5, 7)
2 | 1010 FOR I=1 TO 5
3 | 1020 FOR J=1 TO 7
4 | 1030 PRINT "PUT ";I;", ";J
5 | 1040 A(I,J) = I*10 + J
6 | 1050 NEXT J
7 | 1060 NEXT I
8 | 1070 FOR I=1 TO 5
9 | 1080 FOR J=1 TO 7
10 | 1090 PRINT "GET ";I;", ";J
11 | 1100 PRINT A(I, J)
12 | 1110 NEXT J
13 | 1120 NEXT I
14 |
--------------------------------------------------------------------------------
/examples/expr.bas:
--------------------------------------------------------------------------------
1 | 10 Q=RND(1)
2 | 20 N=1
3 | 30 R=.592*(1/TAN(Q/N+Q))/SIN(N*2+Q)-COS(N)
4 | 40 PRINT R
5 |
--------------------------------------------------------------------------------
/examples/for.bas:
--------------------------------------------------------------------------------
1 | 100 PRINT "FOR test"
2 | 110 FOR A=0 TO 10
3 | 120 PRINT A
4 | 130 NEXT
5 | 140 PRINT "done"
6 |
--------------------------------------------------------------------------------
/examples/for_colon.bas:
--------------------------------------------------------------------------------
1 | 100 FOR A=1 TO 10: FOR B=1 TO 5
2 | 110 PRINT A*B
3 | 120 NEXT B: NEXT A
4 |
--------------------------------------------------------------------------------
/examples/get.bas:
--------------------------------------------------------------------------------
1 | 100 PRINT "Type max. 20 chars, please: ";:GOSUB 1000
2 | 200 PRINT: PRINT "You have written: ";B$
3 | 300 END
4 | 1000 REM simple GET-INPUT-Routine
5 | 1010 A$="": B$="": A=0: REM initialize variables
6 | 1020 GET A$: IF A$="" THEN 1020
7 | 1030 A=ASC(A$): IF (A<32 OR A>127) AND A<>13 THEN 1020
8 | 1040 REM B$=B$+A$: PRINT A$;: IF LEN(B$)<20 AND A$<>CHR$(13) THEN 1020
9 | 1045 B$=B$+A$: IF LEN(B$)<20 AND A$<>CHR$(13) THEN 1020
10 | 1050 RETURN
11 |
--------------------------------------------------------------------------------
/examples/gosub.bas:
--------------------------------------------------------------------------------
1 | 100 GOSUB 500
2 | 110 PRINT "B"
3 | 120 END
4 | 500 PRINT "A"
5 | 510 RETURN
6 |
--------------------------------------------------------------------------------
/examples/goto.bas:
--------------------------------------------------------------------------------
1 | 1000 GOTO 2000
2 | 1010 PRINT "END"
3 | 1020 END
4 | 2000 PRINT "A"
5 | 2010 GOTO 3000
6 | 3000 PRINT "B"
7 | 3010 GOTO 1010
8 |
--------------------------------------------------------------------------------
/examples/if.bas:
--------------------------------------------------------------------------------
1 | 100 FOR A=1 TO 10
2 | 110 IF A=5 THEN PRINT "FIVE"
3 | 120 NEXT
4 |
--------------------------------------------------------------------------------
/examples/if_and_or.bas:
--------------------------------------------------------------------------------
1 | 100 FOR A=1 TO 2
2 | 110 FOR B=1 TO 2
3 | 120 PRINT "A=";A;" B=";B
4 | 130 IF A=1 AND B=2 THEN PRINT " --> A=1 AND B=2"
5 | 140 IF A=2 OR B=2 THEN PRINT " --> A=2 OR B=2"
6 | 150 IF A=2 AND B=2 THEN PRINT " --> A AND B ARE 2";:PRINT "... AND THIS SHOWS UP ALSO"
7 | 160 NEXT
8 | 170 NEXT
9 |
--------------------------------------------------------------------------------
/examples/if_goto.bas:
--------------------------------------------------------------------------------
1 | 10 A=1
2 | 20 IF A=1 THEN 40
3 | 30 END
4 | 40 PRINT "OK"
5 |
--------------------------------------------------------------------------------
/examples/input.bas:
--------------------------------------------------------------------------------
1 | 10 PRINT "what is your name?"
2 | 20 INPUT "...(Enter Your Name)...", A$
3 | 30 PRINT
4 | 40 PRINT "hello, "; A$; ", I am your computer, nice to meet you."
5 |
--------------------------------------------------------------------------------
/examples/left.bas:
--------------------------------------------------------------------------------
1 | 10 A$="BASIC"
2 | 20 B$=LEFT$(A$, 3)
3 | 30 PRINT B$
4 |
--------------------------------------------------------------------------------
/examples/math.bas:
--------------------------------------------------------------------------------
1 | 10 INPUT"ENTER A NUMBER";N
2 | 20 ?"ABS(N)=";ABS(N)
3 | 25 ?"ATN(N)=";ATN(N)
4 | 30 ?"COS(N)=";COS(N)
5 | 40 ?"EXP(N)=";EXP(N)
6 | 50 ?"INT(N)=";INT(N)
7 | 60 ?"LOG(N)=";LOG(N)
8 | 70 ?"SGN(N)=";SGN(N)
9 | 80 ?"SQR(N)=";SQR(N)
10 | 90 ?"TAN(N)=";TAN(N)
11 |
--------------------------------------------------------------------------------
/examples/mid.bas:
--------------------------------------------------------------------------------
1 | 10 A$="GOOD"
2 | 20 B$="MORNING EVENING AFTERNOON"
3 | 30 PRINT A$;
4 | 40 PRINT MID$(B$, 8, 8)
5 |
--------------------------------------------------------------------------------
/examples/nested_for.bas:
--------------------------------------------------------------------------------
1 | 100 FOR A=1 TO 5
2 | 110 FOR B=10 TO 15
3 | 120 PRINT A+B
4 | 130 NEXT
5 | 140 NEXT
6 |
--------------------------------------------------------------------------------
/examples/on_goto.bas:
--------------------------------------------------------------------------------
1 | 10 A=1
2 | 20 ON A GOTO 100,200,300
3 | 30 A=A+1
4 | 40 IF A>3 THEN 60
5 | 50 GOTO 20
6 | 60 END
7 | 100 PRINT "1"
8 | 110 GOTO 30
9 | 200 PRINT "2"
10 | 210 GOTO 30
11 | 300 PRINT "3"
12 | 310 GOTO 30
13 |
--------------------------------------------------------------------------------
/examples/right.bas:
--------------------------------------------------------------------------------
1 | 10 A$="DISK BASIC"
2 | 20 PRINT RIGHT$(A$, 5)
3 |
--------------------------------------------------------------------------------
/examples/simple-basic/happy_birthday.bas:
--------------------------------------------------------------------------------
1 | 10 CLS
2 | 20 LET A$="HAPPY BIRTHDAY"
3 | 30 PRINT:PRINT:PRINT
4 | 40 FOR K=1 TO LEN(A$)
5 | 50 PRINT MID$(A$,K,1);
6 | 60 FOR L=1 TO 10000: NEXT L
7 | 70 NEXT K
8 | 80 PRINT:PRINT:PRINT
9 | 90 PRINT "LOVE FROM"
10 | 100 PRINT "YOUR COMPUTER"
11 |
--------------------------------------------------------------------------------
/examples/simple-basic/input.bas:
--------------------------------------------------------------------------------
1 | 10 REM CLS
2 | 20 PRINT "WHAT'S YOUR NAME?"
3 | 30 INPUT N$
4 | 40 PRINT "HOW OLD ARE YOU?"
5 | 50 INPUT A
6 | 60 REM CLS
7 | 70 PRINT N$;" IS ";A
8 | 80 PRINT "YEARS OLD"
9 |
--------------------------------------------------------------------------------
/examples/sine_wave.bas:
--------------------------------------------------------------------------------
1 | 100 PRINT SPC(20);"SINE WAVE"
2 | 110 PRINT SPC(10);"CREATIVE BASIC - JOHAN VDB"
3 | 120 PRINT: PRINT: PRINT: PRINT: PRINT
4 | 200 B=0
5 | 210 FOR I=0 TO 40 STEP 0.25
6 | 220 A=INT(40+40*SIN(I))
7 | 230 PRINT SPC(A);
8 | 240 IF B=1 THEN GOTO 280
9 | 250 PRINT "CREATIVE"
10 | 260 B=1
11 | 270 GOTO 300
12 | 280 PRINT "BASIC"
13 | 290 B=0
14 | 300 NEXT
15 | 310 END
16 |
--------------------------------------------------------------------------------
/examples/sleep.bas:
--------------------------------------------------------------------------------
1 | 10 INPUT "YOUR NAME", NAME$
2 | 20 CLS
3 | 30 FOR I=1 TO LEN(NAME$)
4 | 40 PRINT MID$(NAME$,I,1);
5 | 50 SLEEP(500)
6 | 60 NEXT
7 |
--------------------------------------------------------------------------------
/examples/strings.bas:
--------------------------------------------------------------------------------
1 | 10 REM INPUT"ENTER A STRING";A$
2 | 20 REM INPUT"ENTER A NUMBER";N
3 | 25 A$="HALLO": N=2
4 | 26 PRINT "STRING=";A$;", NUMBER=";N
5 | 30 ?"ASC(A$)=";ASC(A$)
6 | 40 ?"CHR$(N)=";CHR$(N)
7 | 50 ?"LEFT$(A$,N)=";LEFT$(A$,N)
8 | 60 ?"MID$(A$,N)=";MID$(A$,N)
9 | 70 ?"MID$(A$,N,3)=";MID$(A$,N,3)
10 | 80 ?"RIGHT$(A$,N)=";RIGHT$(A$,N)
11 | 90 ?"LEN(A$)=";LEN(A$)
12 | 100 ?"VAL(A$)=";VAL(A$)
13 | 110 ?"STR$(N)=";STR$(N)
14 | 120 ?"SPC(N)='";SPC(N);"'"
15 |
--------------------------------------------------------------------------------
/examples/test_for.bas:
--------------------------------------------------------------------------------
1 | 100 FOR A=1 TO 2
2 | 200 FOR B=1 TO 2
3 | 300 PRINT "A=";A;", B=";B
4 | 400 IF A=1 THEN PRINT "--> A=1"
5 | 500 NEXT B
6 | 600 NEXT A
7 |
--------------------------------------------------------------------------------
/examples/the_first_basic_program.bas:
--------------------------------------------------------------------------------
1 | 10 LET X = (7 + 8) / 3
2 | 20 PRINT X
3 | 30 END
4 |
--------------------------------------------------------------------------------
/examples/toss_a_coin.bas:
--------------------------------------------------------------------------------
1 | 100 REM TOSS A COIN
2 | 110 C=INT(RND(1)*2)
3 | 120 IF C=0 THEN GOTO 180
4 | 130 PRINT "TAILS"
5 | 140 PRINT "TRY AGAIN?";
6 | 150 INPUT T$
7 | 160 IF T$="Y" THEN GOTO 110
8 | 170 END
9 | 180 PRINT "HEADS"
10 | 190 GOTO 140
11 |
--------------------------------------------------------------------------------
/examples/var.bas:
--------------------------------------------------------------------------------
1 | 10 A=1
2 | 20 A=2
3 | 30 A=3
4 | 40 PRINT A
5 |
--------------------------------------------------------------------------------
/include/arch.h:
--------------------------------------------------------------------------------
1 | #ifndef __ARCH_H__
2 | #define __ARCH_H__
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | #ifndef _WIN32
9 | #if ARCH==ARCH_XMEGA
10 | int asprintf(char **ret, const char *format, ...);
11 | float strtof(const char *restrict nptr, char **restrict endptr);
12 | char *strndup(const char *s1, size_t n);
13 | #endif
14 | #endif
15 |
16 | int arch_init(void);
17 |
18 | typedef void (*arch_load_out_cb)(char *line, void* context);
19 | int arch_load(char* filename, arch_load_out_cb cb, void* context);
20 |
21 | typedef uint16_t (*arch_save_cb)(char** line, void* context);
22 | int arch_save(char* filename, arch_save_cb cb, void* context);
23 |
24 | typedef void (*arch_dir_out_cb)(char *name, size_t size, bool label, void* context);
25 | int arch_dir(arch_dir_out_cb cb, void* context);
26 |
27 | int arch_delete(char* filename);
28 |
29 | #endif // __ARCH_H__
30 |
--------------------------------------------------------------------------------
/include/array.h:
--------------------------------------------------------------------------------
1 | #ifndef __ARRAY_H__
2 | #define __ARRAY_H__
3 |
4 | typedef struct array array;
5 |
6 | array* array_new(size_t element_size);
7 |
8 | array* array_alloc(array* array, size_t size);
9 |
10 | void array_destroy(array* array);
11 |
12 | void* array_push(array* array, void* value);
13 |
14 | void* array_get(array* array, size_t index);
15 |
16 | void* array_set(array* array, size_t index, void* value);
17 |
18 | size_t array_size(array* array);
19 |
20 |
21 | #endif // __ARRAY_H__
22 |
--------------------------------------------------------------------------------
/include/callback.h:
--------------------------------------------------------------------------------
1 | #ifndef __CALLBACK_H__
2 | #define __CALLBACK_H__
3 |
4 | #include
5 |
6 | typedef struct
7 | error
8 | {
9 | int error;
10 | };
11 |
12 | typedef bool (*callback)(error err, void* data);
13 |
14 | #endif // __CALLBACK_H__
15 |
--------------------------------------------------------------------------------
/include/dictionary.h:
--------------------------------------------------------------------------------
1 | #ifndef __DICTIONARY_H__
2 | #define __DICTIONARY_H__
3 |
4 | #include
5 |
6 | typedef struct dictionary dictionary;
7 |
8 | typedef void (*dictionary_each_cb)(char* name, void* value, void* context);
9 |
10 | dictionary* dictionary_new(void);
11 | void dictionary_destroy(dictionary* d, dictionary_each_cb cb);
12 | void dictionary_put(dictionary* d, char* name, void* value);
13 | bool dictionary_has(dictionary* d, char* name);
14 | void* dictionary_get(dictionary* d, char* name);
15 | void dictionary_each(dictionary* d, dictionary_each_cb cb, void* context);
16 | void* dictionary_del(dictionary* d, char* name);
17 |
18 | #endif // __DICTIONARY_H__
19 |
--------------------------------------------------------------------------------
/include/error.h:
--------------------------------------------------------------------------------
1 | #ifndef __ERROR_H__
2 | #define __ERROR_H__
3 |
4 | extern char *last_error;
5 | void error(const char *error_msg);
6 |
7 | #endif
8 |
--------------------------------------------------------------------------------
/include/hexdump.h:
--------------------------------------------------------------------------------
1 | #ifndef __HEXDUMP_H__
2 | #define __HEXDUMP_H__
3 |
4 | void hexdump ( char *desc, void *addr, int len );
5 |
6 | #endif // __HEXDUMP_H__
7 |
--------------------------------------------------------------------------------
/include/io.h:
--------------------------------------------------------------------------------
1 | #ifndef __IO_H__
2 | #define __IO_H__
3 |
4 | #include
5 |
6 | typedef int (*basic_putchar)(int ch);
7 | typedef int (*basic_getchar)(void);
8 | void basic_io_print(char* buffer);
9 | char* basic_io_readline(char* prompt, char* buffer, size_t buffer_size);
10 |
11 | #endif // __IO_H__
12 |
--------------------------------------------------------------------------------
/include/kbhit.h:
--------------------------------------------------------------------------------
1 | #ifndef __KBHIT_H__
2 | #define __KBHIT_H__
3 |
4 | int kbhit(void);
5 |
6 | #endif // __KBHIT_H__
7 |
--------------------------------------------------------------------------------
/include/lines.h:
--------------------------------------------------------------------------------
1 | #ifndef __LINES_H__
2 | #define __LINES_H__
3 |
4 | #include
5 | #include
6 |
7 | typedef struct line line;
8 |
9 | struct line
10 | {
11 | uint16_t number;
12 | uint8_t length;
13 | char contents;
14 | };
15 |
16 | void lines_init(char *memory, size_t memory_size);
17 |
18 | size_t lines_memory_used(void);
19 | size_t lines_memory_available(void);
20 |
21 | bool lines_delete(uint16_t number);
22 |
23 | bool lines_store(uint16_t number, char* contents );
24 |
25 | typedef void (*lines_list_cb)(uint16_t number, char* contents);
26 |
27 | void lines_list(uint16_t start, uint16_t end, lines_list_cb out);
28 |
29 | void lines_clear(void);
30 |
31 | char* lines_get_contents(uint16_t number);
32 |
33 | uint16_t lines_first(void);
34 | uint16_t lines_next(uint16_t number);
35 |
36 | #endif // __LINES_H__
37 |
--------------------------------------------------------------------------------
/include/parser.h:
--------------------------------------------------------------------------------
1 | #ifndef __PARSER_H__
2 | #define __PARSER_H__
3 |
4 | #include
5 | #include
6 |
7 | #include
8 |
9 | float evaluate(char *expression_string);
10 |
11 | void evaluate_print(char *line);
12 |
13 | void evaluate_print_func_param( char *func, float param);
14 |
15 | const char* evaluate_last_error(void);
16 | void clear_last_error(void);
17 |
18 | void basic_init(size_t memory_size, size_t stack_size);
19 |
20 | void basic_destroy(void);
21 |
22 | void basic_register_io(basic_putchar putch, basic_getchar getch);
23 |
24 | char* basic_readline(char* prompt, char* buffer, size_t buffer_size);
25 |
26 | void basic_eval(char *line);
27 | void basic_run(void);
28 |
29 | // For extensions
30 |
31 | typedef float (*function)(float number);
32 |
33 | typedef struct
34 | {
35 | token _token;
36 | function _function;
37 | } token_to_function;
38 |
39 | typedef enum {
40 | basic_function_type_keyword,
41 | basic_function_type_op,
42 | basic_function_type_numeric,
43 | basic_function_type_string,
44 | basic_function_type_print
45 | } basic_function_type;
46 |
47 | typedef enum {
48 | kind_numeric,
49 | kind_string
50 | } kind;
51 |
52 | typedef union {
53 | float number;
54 | char* string;
55 | } value;
56 |
57 | typedef struct {
58 | kind kind;
59 | bool empty;
60 | bool mallocd;
61 | value value;
62 | } basic_type;
63 |
64 | typedef int (*function_0)(basic_type* rv);
65 | typedef int (*function_1)(basic_type* v1, basic_type* rv);
66 | typedef int (*function_2)(basic_type* v1, basic_type* v2, basic_type* rv);
67 | typedef int (*function_3)(basic_type* v1, basic_type* v2, basic_type* v3, basic_type* rv);
68 | typedef int (*function_4)(basic_type* v1, basic_type* v2, basic_type* v3, basic_type* v4, basic_type* rv);
69 | typedef int (*function_5)(basic_type* v1, basic_type* v2, basic_type* v3, basic_type* v4, basic_type* v5, basic_type* rv);
70 |
71 | token register_token(char* token_name);
72 | token register_function_0(basic_function_type type, char* keyword, function_0 function);
73 | token register_function_1(basic_function_type type, char* keyword, function_1 function, kind v1);
74 | token register_function_2(basic_function_type type, char* keyword, function_2 function, kind v1, kind v2);
75 | token register_function_3(basic_function_type type, char* keyword, function_3 function, kind v1, kind v2, kind v3);
76 | token register_function_4(basic_function_type type, char* keyword, function_4 function, kind v1, kind v2, kind v3, kind v4);
77 | token register_function_5(basic_function_type type, char* keyword, function_5 function, kind v1, kind v2, kind v3, kind v4, kind v5);
78 |
79 | #endif // __PARSER_H__
80 |
--------------------------------------------------------------------------------
/include/tokenizer.h:
--------------------------------------------------------------------------------
1 | #ifndef __TOKENIZER_H__
2 | #define __TOKENIZER_H__
3 |
4 | #include
5 |
6 | #define tokenizer_string_length 64
7 | #define tokenizer_variable_length 8
8 |
9 | typedef unsigned int token;
10 | typedef char* token_name;
11 | typedef char* token_keyword;
12 |
13 | typedef struct {
14 | token token;
15 | token_name name;
16 | } token_entry;
17 |
18 | #define add_token(t, k) \
19 | static token_entry _##t = { t, k };
20 |
21 | typedef enum {
22 | // Standard token types needed by the tokenizer
23 | T_THE_END,
24 | T_ERROR,
25 | T_EOF,
26 | T_NUMBER,
27 | T_STRING,
28 | T_VARIABLE_STRING,
29 | T_VARIABLE_NUMBER,
30 |
31 | // Some tokens that are standard as well
32 | T_PLUS,
33 | T_MINUS,
34 | T_MULTIPLY,
35 | T_DIVIDE,
36 | T_LEFT_BANANA,
37 | T_RIGHT_BANANA,
38 | T_COLON,
39 | T_SEMICOLON,
40 | T_EQUALS,
41 | T_LESS,
42 | T_GREATER,
43 | T_COMMA,
44 | TOKEN_TYPE_END
45 | } token_type;
46 |
47 | void tokenizer_setup(void);
48 | void tokenizer_init(char *input);
49 | token tokenizer_get_next_token(void);
50 |
51 | float tokenizer_get_number(void);
52 | char * tokenizer_get_string(void);
53 | void tokenizer_get_variable_name(char *name);
54 |
55 | char *tokenizer_token_name(token);
56 |
57 | char* tokenizer_char_pointer(char* set);
58 |
59 | void tokenizer_add_tokens( token_entry* tokens );
60 |
61 | void tokenizer_register_token( token_entry* entry );
62 | void tokenizer_free_registered_tokens(void);
63 |
64 | #endif // __TOKENIZER_H__
65 |
--------------------------------------------------------------------------------
/include/usingwin.h:
--------------------------------------------------------------------------------
1 | #ifndef __USINGWIN__
2 | #define __USINGWIN__
3 |
4 | #ifdef _WIN32
5 | #define C_STRDUP _strdup
6 | #else
7 | #define C_STRDUP strdup
8 | #endif
9 |
10 | #endif
11 |
--------------------------------------------------------------------------------
/include/variables.h:
--------------------------------------------------------------------------------
1 | #ifndef __VARIABLES_H__
2 | #define __VARIABLES_H__
3 |
4 | #include
5 |
6 | typedef enum {
7 | variable_type_unknown,
8 | variable_type_numeric,
9 | variable_type_string
10 | } variable_type;
11 |
12 | typedef struct variable variable;
13 |
14 | bool variables_init(void);
15 | void variables_destroy(void);
16 |
17 | variable* variable_get(char* name);
18 |
19 | char* variable_get_string(char* name);
20 | float variable_get_numeric(char* name);
21 |
22 | variable* variable_set_string(char* name, char* value);
23 | variable* variable_set_numeric(char* name, float value);
24 |
25 | variable_type variable_get_type(char* name);
26 |
27 | variable* variable_array_init(char* name, variable_type type, size_t dimensions, size_t* vector);
28 | variable* variable_array_set_string(char *name, char *value, size_t* vector);
29 | char* variable_array_get_string(char *name, size_t* vector);
30 | variable* variable_array_set_numeric(char *name, float value, size_t* vector);
31 | float variable_array_get_numeric(char *name, size_t* vector);
32 |
33 | typedef void (*variables_each_cb)(variable* var, void* context);
34 | void variables_each(variables_each_cb each, void* context);
35 |
36 | void variable_dump(variable* var);
37 |
38 | #endif // __VARIABLES_H__
39 |
--------------------------------------------------------------------------------
/src/array.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include
5 |
6 | #include "array.h"
7 | #include "usingwin.h"
8 |
9 | struct array {
10 | size_t element_size;
11 | size_t size;
12 | char* ptr;
13 | };
14 |
15 | array*
16 | array_new(size_t element_size)
17 | {
18 | // printf("array size: %ld\n", sizeof(array));
19 | array* a = malloc(sizeof(array));
20 | a->element_size = element_size;
21 | a->size = 0;
22 | a->ptr = NULL;
23 | return a;
24 | }
25 |
26 | array*
27 | array_alloc(array* array, size_t size)
28 | {
29 | array->size = size;
30 | array->ptr = realloc(array->ptr, array->element_size * array->size);
31 | // Always clear arrays
32 | memset(array->ptr, 0, array->element_size * array->size);
33 | return array;
34 | }
35 |
36 | void
37 | array_destroy(array* array)
38 | {
39 | free(array->ptr);
40 | free(array);
41 | }
42 |
43 | void*
44 | array_push(array* array, void* value)
45 | {
46 | array->size++;
47 | array->ptr = realloc(array->ptr, array->element_size * array->size);
48 | void* element = array->ptr + array->element_size * (array->size - 1);
49 | memcpy(element, value, array->element_size);
50 | return element;
51 | }
52 |
53 | void*
54 | array_get(array* array, size_t index)
55 | {
56 | return array->ptr + index * array->element_size;
57 | }
58 |
59 | void*
60 | array_set(array* array, size_t index, void* value)
61 | {
62 | void* element = array_get(array, index);
63 | memcpy(element, value, array->element_size);
64 | return element;
65 | }
66 |
67 | size_t
68 | array_size(array* array)
69 | {
70 | return array->size;
71 | }
72 |
73 |
--------------------------------------------------------------------------------
/src/dictionary.c:
--------------------------------------------------------------------------------
1 | #define _GNU_SOURCE
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include
9 | #include "usingwin.h"
10 |
11 | typedef struct entry entry;
12 | struct entry
13 | {
14 | entry* next;
15 | char* name;
16 | void* value;
17 | };
18 |
19 | #ifndef _WIN32
20 | #if ARCH!=ARCH_XMEGA
21 | # define HASHSIZE 13
22 | #else
23 | # define HASHSIZE 101
24 | #endif
25 | #else
26 | # define HASHSIZE 13
27 | #endif
28 |
29 | struct dictionary {
30 | entry *hashtab[HASHSIZE];
31 | };
32 |
33 | static unsigned int
34 | hash(char *name)
35 | {
36 | unsigned int hashval;
37 | for (hashval = 0; *name != '\0'; name++) {
38 | hashval = *name + 31 * hashval;
39 | }
40 | return hashval % HASHSIZE;
41 | }
42 |
43 | static entry* _get(dictionary* d, char *name)
44 | {
45 | // printf("get %p %s\n", d, name);
46 | entry* entry;
47 | for (entry = d->hashtab[hash(name)]; entry != NULL; entry = entry->next) {
48 | if (strcmp(name, entry->name) == 0) {
49 | // printf("\tgot %p\n", entry);
50 | return entry;
51 | }
52 | }
53 | // puts("not\n");
54 | return NULL;
55 | }
56 |
57 | void* dictionary_get(dictionary* d, char* name)
58 | {
59 | entry* entry = _get(d, name);
60 |
61 | if (entry) {
62 | return entry->value;
63 | }
64 |
65 | return NULL;
66 | }
67 |
68 | bool dictionary_has(dictionary* d, char *name)
69 | {
70 | entry* entry = _get(d, name);
71 |
72 | if (entry) {
73 | return true;
74 | }
75 |
76 | return false;
77 | }
78 |
79 | void
80 | dictionary_put(dictionary* d, char* name, void* value)
81 | {
82 | // printf("put %p %s\n", d, name);
83 | entry* element;
84 | unsigned int hashval;
85 |
86 | element = _get(d, name);
87 |
88 | if (element == NULL) {
89 | element = (entry*) malloc(sizeof(*element));
90 | if (element == NULL || (element->name = C_STRDUP(name)) == NULL) {
91 | return;
92 | }
93 | hashval = hash(name);
94 | element->next = d->hashtab[hashval];
95 | d->hashtab[hashval] = element;
96 | }
97 | // printf("entry %p\n", element);
98 | element->value = value;
99 | }
100 |
101 | void*
102 | dictionary_del(dictionary* d, char* name)
103 | {
104 | entry* root = d->hashtab[hash(name)];
105 |
106 | if(root==NULL){
107 | return NULL;
108 | }
109 |
110 | if(strcmp(name, root->name)==0){
111 | d->hashtab[hash(name)] = root->next;
112 | void *value = root->value;
113 | free(root->name);
114 | free(root);
115 | return value;
116 | }
117 |
118 | entry* element = root;
119 | while(element->next){
120 | entry *next = element->next;
121 | if(strcmp(name, next->name) == 0){
122 | element->next = next->next;
123 | void *value = next->value;
124 | free(next->name);
125 | free(next);
126 | return value;
127 | }
128 | }
129 |
130 | return NULL;
131 | }
132 |
133 | void
134 | dictionary_each(dictionary* d, dictionary_each_cb cb, void* context)
135 | {
136 | entry* next_entry = NULL;
137 |
138 | if (!cb) {
139 | return;
140 | }
141 |
142 | for(size_t i=0; i < HASHSIZE; i++) {
143 | entry* entry = d->hashtab[i];
144 | while(entry) {
145 | next_entry = entry->next;
146 | cb(entry->name, entry->value, context);
147 | entry = next_entry;
148 | }
149 | }
150 | }
151 |
152 | dictionary*
153 | dictionary_new()
154 | {
155 | // printf("dictionary size: %ld\n", sizeof(dictionary));
156 | dictionary* d = malloc(sizeof(dictionary));
157 | if (d == NULL) {
158 | return NULL;
159 | }
160 | for(size_t i=0; i < HASHSIZE; i++) {
161 | d->hashtab[i] = NULL;
162 | }
163 | return d;
164 | }
165 |
166 | typedef struct {
167 | dictionary* d;
168 | dictionary_each_cb cb;
169 | } _free_s;
170 |
171 | static void
172 | destroy_cb_pass_1(char* name, void* value, void* context)
173 | {
174 | _free_s *ctx = (_free_s*) context;
175 | // dictionary *d = ctx->d;
176 | dictionary_each_cb free_cb = ctx->cb;
177 | free_cb(name, value, NULL);
178 | // dictionary_del(d, name);
179 | }
180 |
181 | static void
182 | destroy_cb_pass_2(char* name, void* value, void* context)
183 | {
184 | _free_s *ctx = (_free_s*) context;
185 | dictionary *d = ctx->d;
186 | // dictionary_each_cb free_cb = ctx->cb;
187 | // free_cb(name, value, NULL);
188 | dictionary_del(d, name);
189 | }
190 |
191 |
192 | void
193 | dictionary_destroy(dictionary* d, dictionary_each_cb free_cb)
194 | {
195 | _free_s ctx = {
196 | .d = d,
197 | .cb = free_cb
198 | };
199 | dictionary_each(d, destroy_cb_pass_1, &ctx);
200 | dictionary_each(d, destroy_cb_pass_2, &ctx);
201 | free(d);
202 | }
203 |
--------------------------------------------------------------------------------
/src/hexdump.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | void
4 | hexdump (char *desc, void *addr, int len)
5 | {
6 | int i;
7 | unsigned char buff[17];
8 | unsigned char *pc = (unsigned char*) addr;
9 |
10 | if (desc != NULL)
11 | {
12 | printf ("%s:\n", desc);
13 | }
14 |
15 | for (i = 0; i < len; i++)
16 | {
17 | if ( (i % 16) == 0 )
18 | {
19 | if ( i != 0 )
20 | {
21 | printf (" %s\n", buff);
22 | }
23 | printf (" %04x ", i);
24 | }
25 |
26 | printf (" %02x", pc[i]);
27 |
28 | if ( (pc[i] < 0x20) || (pc[i] > 0x7e) )
29 | {
30 | buff[i % 16] = '.';
31 | }
32 | else
33 | {
34 | buff[i % 16] = pc[i];
35 | }
36 | buff[(i % 16) + 1] = '\0';
37 | }
38 |
39 | while ( (i % 16) != 0 )
40 | {
41 | printf (" ");
42 | i++;
43 | }
44 | printf (" %s\n", buff);
45 | }
46 |
--------------------------------------------------------------------------------
/src/io.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include
6 |
7 | extern basic_putchar __putch;
8 | extern basic_getchar __getch;
9 |
10 | void
11 | basic_io_print(char* buffer)
12 | {
13 | for(size_t i=0; i0){
36 | buffer[--len] = '\0';
37 | # ifdef BASIC_READLINE_ECHO
38 | __putch(' ');
39 | __putch('\b');
40 | # endif
41 | }
42 | break;
43 | default:
44 | buffer[len++] = ch;
45 | }
46 | }
47 | # ifdef BASIC_READLINE_ECHO
48 | __putch('\n');
49 | # endif
50 | buffer[len] = '\0';
51 | return buffer;
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/src/lines.c:
--------------------------------------------------------------------------------
1 | // -- Lines BASIC program storage
2 |
3 | // TODO:
4 | // v delete line
5 | // v wipe
6 | // v get_line
7 | // . clean up code
8 | // v integrate with parser
9 |
10 | #include
11 | #include
12 | #include
13 |
14 | #include "hexdump.h"
15 | #include "lines.h"
16 |
17 | static char* __memory;
18 | static char* __memory_end;
19 | static size_t __memory_size;
20 |
21 | static line*
22 | _next(line* l)
23 | {
24 | char* p = (char*) l;
25 | p += sizeof(line) - 1 + l->length;
26 | return (line*) p;
27 | }
28 |
29 | static bool
30 | _is_end(line* l)
31 | {
32 | return l && l->number == 0 && l->length == 0;
33 | }
34 |
35 | static line*
36 | _find_end(line* l)
37 | {
38 | line* n = l;
39 | while ( ! _is_end( n ) )
40 | {
41 | n = _next( n );
42 | }
43 | return n;
44 | }
45 |
46 | void
47 | lines_init(char *memory, size_t memory_size)
48 | {
49 | __memory = memory;
50 | __memory_end = memory;
51 | __memory_size = memory_size;
52 |
53 | // Signal end
54 | line* l = (line*) __memory;
55 | l->number = 0;
56 | l->length = 0;
57 | }
58 |
59 | size_t
60 | lines_memory_used(void)
61 | {
62 | char *p = __memory;
63 | line* start = (line*) p;
64 | line* end = _find_end(start);
65 | end = _next(end);
66 |
67 | char* m_start = (char*) start;
68 | char* m_end = (char*) end;
69 |
70 | return m_end - m_start;
71 | }
72 |
73 | size_t
74 | lines_memory_available(void)
75 | {
76 | return __memory_size - lines_memory_used();
77 | }
78 |
79 | bool
80 | lines_store(uint16_t number, char* contents)
81 | {
82 | // support insert
83 |
84 |
85 | char *p = __memory;
86 | line* l = (line*) p;
87 | while ( ! _is_end( l ) )
88 | {
89 | line* next = _next( l );
90 |
91 | // Find line that is to be insert after. That line has a line number < insert and the next line has a >
92 | if ( l->number < number && next->number > number )
93 | {
94 | // We need to insert
95 | // printf("insert %d\n", number);
96 |
97 | // The address of the insert is the same as the next line
98 | line* insert = next;
99 |
100 | // But we need to move the memory block holding the rest to the right.
101 | line* end = _find_end( insert );
102 | end = _next(end); // Move to next empty slot (we keep the sentinel in the copy)
103 |
104 | // We have the end*, calculate size to move
105 | char* m_src = (char*) insert;
106 | char* m_end = (char*) end;
107 | size_t m_size = m_end - m_src;
108 |
109 | // Calculate offset to move
110 | size_t insert_size = sizeof(line) - 1 + strlen(contents) + 1;
111 | char* m_dst = m_src + insert_size;
112 |
113 | // Move the memory block
114 | memmove( m_dst, m_src, m_size );
115 |
116 | // Set the data of the insert
117 | insert->number = number;
118 | insert->length = strlen(contents) + 1;
119 | strcpy( &(insert->contents), contents );
120 |
121 | // hexdump( "insert", __memory, 256 );
122 |
123 | return true;
124 | }
125 | // Replace
126 | if ( l->number == number )
127 | {
128 | // printf("replace %d\n", number);
129 |
130 | // We need to shift the memory to the new offset determined by the size of the line to be inserted
131 |
132 | line* end = _find_end( l );
133 | end = _next(end); // Move to next empty slot (we keep the sentinel in the copy)
134 |
135 | // Calculate size of bloack
136 | char* m_src = (char*) next;
137 | char* m_end = (char*) end;
138 | size_t m_size = m_end - m_src;
139 |
140 | // Calculate offset to move
141 | size_t replace_size = sizeof(line) - 1 + strlen(contents) + 1;
142 | size_t actual_size = sizeof(line) - 1 + strlen(&(l->contents)) + 1;
143 | int offset = replace_size - actual_size ;
144 | char* m_dst = m_src + offset;
145 |
146 | // Move the memory block
147 | memmove( m_dst, m_src, m_size );
148 |
149 | // Set the data of the replace
150 | l->length = strlen(contents) + 1;
151 | strcpy( &(l->contents), contents );
152 |
153 | // hexdump( "replace", __memory, 256 );
154 |
155 | return true;
156 | }
157 | // Prepend
158 | if ( l->number > number )
159 | {
160 | // printf("prepend %d\n", number);
161 |
162 | // The address of the insert is the same as the actual line
163 | line* insert = l;
164 |
165 | // But we need to move the memory block holding the rest to the right.
166 | line* end = _find_end( insert );
167 | end = _next(end); // Move to next empty slot (we keep the sentinel in the copy)
168 |
169 | // We have the end*, calculate size to move
170 | char* m_src = (char*) insert;
171 | char* m_end = (char*) end;
172 | size_t m_size = m_end - m_src;
173 |
174 | // Calculate offset to move
175 | size_t insert_size = sizeof(line) - 1 + strlen(contents) + 1;
176 | char* m_dst = m_src + insert_size;
177 |
178 | // Move the memory block
179 | memmove( m_dst, m_src, m_size );
180 |
181 | // Set the data of the insert
182 | insert->number = number;
183 | insert->length = strlen(contents) + 1;
184 | strcpy( &(insert->contents), contents );
185 |
186 | // hexdump( "prepend", __memory, 256 );
187 |
188 | return true;
189 | }
190 |
191 | l = next;
192 | }
193 |
194 | l->number = number;
195 | l->length = strlen(contents) + 1; // Length is offset to next line
196 | strcpy( &(l->contents), contents );
197 |
198 | line* end = _next( l );
199 | end->number = 0;
200 | end->length = 0;
201 |
202 | // hexdump( "append", __memory, 256 );
203 |
204 | return true;
205 | }
206 |
207 | bool
208 | lines_delete(uint16_t number)
209 | {
210 | // printf("delete line %d\n", number);
211 |
212 | // find the line
213 | line* l = (line*) __memory;
214 | while( ! _is_end( l ) && l->number != number)
215 | {
216 | l = _next( l );
217 | }
218 |
219 | if ( _is_end( l ) )
220 | {
221 | // printf("line %d not found\n", number);
222 | return false;
223 | }
224 |
225 | // l is the line to delete
226 | // check if this is the last line
227 | line* next = _next(l);
228 | if ( _is_end( next ) )
229 | {
230 | // printf("delete last line\n");
231 | memset( l, 0x00, sizeof(line) - 1 + strlen(&(l->contents)) + 1 );
232 | l->number = 0;
233 | l->length = 0;
234 | strcpy( &(l->contents), "" );
235 | }
236 | else
237 | {
238 | // printf("delete not last line\n");
239 | char* dst = (char*) l;
240 | char* src = (char*) next;
241 |
242 | line* lend = _find_end( next );
243 | lend = _next(lend); // Move to next empty slot (we keep the sentinel in the copy)
244 | char* end = (char*) lend;
245 | size_t size = (char*) end - src;
246 | memmove( dst, src, size );
247 |
248 | size_t rest = src - dst;
249 | memset( end - rest, 0x00, rest );
250 | }
251 |
252 | // hexdump( "delete", __memory, 256 );
253 |
254 | return true;
255 | }
256 |
257 | static bool
258 | _in_range(uint16_t i, uint16_t low, uint16_t high)
259 | {
260 | if(low==0 && high==0)
261 | {
262 | return true;
263 | }
264 | if(low==0 && i<=high)
265 | {
266 | return true;
267 | }
268 | if(high==0 && i>=low)
269 | {
270 | return true;
271 | }
272 | if(i>= low && i<=high)
273 | {
274 | return true;
275 | }
276 | return false;
277 | }
278 |
279 | void
280 | lines_list(uint16_t start, uint16_t end, lines_list_cb out)
281 | {
282 | char *p = __memory;
283 |
284 | line* l = (line*) p;
285 | while( ! _is_end( l ) )
286 | {
287 | if(_in_range(l->number, start, end))
288 | {
289 | out(l->number, &(l->contents) );
290 | }
291 | l = _next( l );
292 | }
293 | }
294 |
295 | void
296 | lines_clear(void)
297 | {
298 | char* end = (char*) _next( _find_end( (line*) __memory ) );
299 | memset( __memory, 0x00, end - __memory );
300 | line* l = (line*) __memory;
301 | l->number = 0;
302 | l->length = 0;
303 | // hexdump( "clear", __memory, 256 );
304 | }
305 |
306 | char*
307 | lines_get_contents(uint16_t number)
308 | {
309 | line* l = (line*) __memory;
310 | while( ! _is_end( l ) && l->number != number)
311 | {
312 | l = _next( l );
313 | }
314 |
315 | if ( _is_end( l ) )
316 | {
317 | return NULL;
318 | }
319 |
320 | return &(l->contents);
321 | }
322 |
323 | uint16_t
324 | lines_first(void)
325 | {
326 | line* l = (line*) __memory;
327 | return l->number;
328 | }
329 |
330 | uint16_t
331 | lines_next(uint16_t number)
332 | {
333 | line* l = (line*) __memory;
334 | while( ! _is_end( l ) && l->number <= number)
335 | {
336 | l = _next( l );
337 | }
338 |
339 | if ( number == l->number )
340 | {
341 | return 0;
342 | }
343 |
344 | return l->number;
345 | }
346 |
--------------------------------------------------------------------------------
/src/tokenizer.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include "arch.h"
9 | #include "tokenizer.h"
10 | #include "hexdump.h"
11 | #include "array.h"
12 |
13 | static array* token_array = NULL;
14 |
15 | add_token( T_ERROR, NULL );
16 | add_token( T_EOF, NULL );
17 | add_token( T_NUMBER, NULL );
18 | add_token( T_STRING, NULL );
19 | add_token( T_VARIABLE_STRING, NULL );
20 | add_token( T_VARIABLE_NUMBER, NULL );
21 | add_token( T_PLUS, "+" );
22 | add_token( T_MINUS, "-" );
23 | add_token( T_MULTIPLY, "*" );
24 | add_token( T_DIVIDE, "/" );
25 | add_token( T_LEFT_BANANA, "(" );
26 | add_token( T_RIGHT_BANANA, ")" );
27 | add_token( T_COLON, ":" );
28 | add_token( T_SEMICOLON, ";" );
29 | add_token( T_EQUALS, "=" );
30 | add_token( T_LESS, "<" );
31 | add_token( T_GREATER, ">" );
32 | add_token( T_COMMA, "," );
33 |
34 | char *tokenizer_line = NULL;
35 | char *tokenizer_p = NULL;
36 | char *tokenizer_next_p = NULL;
37 |
38 | token tokenizer_actual_token;
39 | float tokenizer_actual_number;
40 | char tokenizer_actual_char;
41 | char tokenizer_actual_string[tokenizer_string_length];
42 | char tokenizer_actual_variable[tokenizer_variable_length];
43 |
44 | void tokenizer_setup(void)
45 | {
46 | token_array = array_new(sizeof(token_entry));
47 | tokenizer_register_token( &_T_ERROR);
48 | tokenizer_register_token( &_T_EOF);
49 | tokenizer_register_token( &_T_NUMBER);
50 | tokenizer_register_token( &_T_STRING);
51 | tokenizer_register_token( &_T_VARIABLE_STRING);
52 | tokenizer_register_token( &_T_VARIABLE_NUMBER);
53 | tokenizer_register_token( &_T_PLUS);
54 | tokenizer_register_token( &_T_MINUS);
55 | tokenizer_register_token( &_T_MULTIPLY);
56 | tokenizer_register_token( &_T_DIVIDE);
57 | tokenizer_register_token( &_T_LEFT_BANANA);
58 | tokenizer_register_token( &_T_RIGHT_BANANA);
59 | tokenizer_register_token( &_T_COLON);
60 | tokenizer_register_token( &_T_SEMICOLON);
61 | tokenizer_register_token( &_T_EQUALS);
62 | tokenizer_register_token( &_T_LESS);
63 | tokenizer_register_token( &_T_GREATER);
64 | tokenizer_register_token( &_T_COMMA);
65 | }
66 |
67 | void tokenizer_init(char *input)
68 | {
69 | tokenizer_line = input;
70 | tokenizer_p = tokenizer_next_p = tokenizer_line;
71 | }
72 |
73 | char* tokenizer_char_pointer(char* set)
74 | {
75 | if ( set != NULL )
76 | {
77 | tokenizer_p = set;
78 | return NULL;
79 | }
80 |
81 | // Skip white space
82 | while ( *tokenizer_p && isspace(*tokenizer_p) ) {
83 | tokenizer_p++;
84 | }
85 | return tokenizer_p;
86 | }
87 |
88 | static bool
89 | isvarchar(char c)
90 | {
91 |
92 | if (c >= 'A' && c <= 'Z') {
93 | return true;
94 | }
95 |
96 | if ( c == '$' ) {
97 | return true;
98 | }
99 |
100 | if (c >= '0' && c <= '9'){
101 | return true;
102 | }
103 |
104 | return false;
105 | }
106 |
107 | token _find_registered(void)
108 | {
109 |
110 | // printf("_find registered\n");
111 |
112 | for(size_t i=0; iname);
118 |
119 | if ( entry->name == NULL ) continue;
120 |
121 | // printf("look for: '%s', in '%s'\n", entry->name, tokenizer_p);
122 |
123 | if (strncmp(tokenizer_p, entry->name, strlen(entry->name)) == 0) {
124 | // printf("found '%s'\n", entry->name);
125 | tokenizer_next_p = tokenizer_p + strlen(entry->name);
126 | tokenizer_p = tokenizer_next_p;
127 | return entry->token;
128 | }
129 | }
130 | return T_THE_END;
131 | }
132 |
133 | token tokenizer_get_next_token(void)
134 | {
135 | if ( ! *tokenizer_p ) {
136 | return T_EOF;
137 | }
138 |
139 | // Skip white space
140 | while ( *tokenizer_p && isspace(*tokenizer_p) ) {
141 | tokenizer_p++;
142 | }
143 |
144 | // Check for number
145 | if (isdigit(*tokenizer_p) || *tokenizer_p == '.') {
146 | // puts("read a number");
147 | tokenizer_next_p = tokenizer_p;
148 | size_t l=0;
149 | while (*tokenizer_next_p && ( isdigit(*tokenizer_next_p) || *tokenizer_next_p == '.') ) {
150 | l++;
151 | tokenizer_next_p++;
152 | }
153 | #ifdef _WIN32
154 | char *number;
155 | number = malloc(l + 1);
156 | #else
157 | char number[l+1];
158 | #endif
159 | memset(number, 0, l+1);
160 | // strlcpy(number, tokenizer_p, sizeof(number) );
161 | strncpy(number, tokenizer_p, l );
162 | number[l] = '\0';
163 | tokenizer_p = tokenizer_next_p;
164 | float f;
165 | // printf("[%s]\n", number);
166 | sscanf(number, "%f", &f);
167 | // printf("Got float: '%f'\n", f);
168 | tokenizer_actual_number = f;
169 |
170 | #ifdef _WIN32
171 | free(number);
172 | #endif
173 |
174 | return T_NUMBER;
175 | }
176 |
177 | // Check for string
178 | if ( '"' == *tokenizer_p ) {
179 | // puts("read string");
180 | tokenizer_p++; // skip "
181 | tokenizer_next_p = tokenizer_p;
182 | size_t l=0;
183 | while(*tokenizer_next_p && '"' != *tokenizer_next_p) {
184 | l++;
185 | tokenizer_next_p++;
186 | }
187 |
188 | if (*tokenizer_next_p) {
189 | tokenizer_next_p++; // skip trailing "
190 | }
191 |
192 | if(l>80){
193 | return T_ERROR;
194 | }
195 |
196 | memcpy(tokenizer_actual_string, tokenizer_p, l);
197 | tokenizer_actual_string[l] = '\0';
198 |
199 | tokenizer_p = tokenizer_next_p;
200 |
201 | return T_STRING;
202 | }
203 |
204 | token t = _find_registered();
205 | if ( t != T_THE_END )
206 | {
207 | return t;
208 | }
209 |
210 | // Check for variable
211 | tokenizer_next_p = tokenizer_p;
212 | size_t len = 0;
213 | while(*tokenizer_next_p && isvarchar(*tokenizer_next_p)) {
214 | len++;
215 | tokenizer_next_p++;
216 | }
217 |
218 | if(len>tokenizer_variable_length){
219 | return T_ERROR;
220 | }
221 |
222 | if (len > 0) {
223 | memcpy(tokenizer_actual_variable, tokenizer_p, len);
224 | tokenizer_actual_variable[len] = '\0';
225 | tokenizer_p = tokenizer_next_p;
226 | if (tokenizer_actual_variable[len-1] == '$') {
227 | return T_VARIABLE_STRING;
228 | }
229 | return T_VARIABLE_NUMBER;
230 | }
231 |
232 | return T_ERROR;
233 | }
234 |
235 | float tokenizer_get_number(void)
236 | {
237 | return tokenizer_actual_number;
238 | }
239 |
240 | char *tokenizer_get_string(void)
241 | {
242 | return tokenizer_actual_string;
243 | }
244 |
245 | void tokenizer_get_variable_name(char *name)
246 | {
247 | strncpy(name, tokenizer_actual_variable, sizeof(tokenizer_actual_variable));
248 | }
249 |
250 | void
251 | tokenizer_register_token( token_entry* entry )
252 | {
253 | /*
254 | // Create space for token_entry
255 | registered_tokens_count++;
256 | registered_tokens_ptr = realloc((char*)registered_tokens_ptr, sizeof(token_entry) * registered_tokens_count);
257 | // Copy data
258 | //token_entry* new = registered_tokens_ptr + sizeof(token_entry) * ( registered_tokens_count - 1 );
259 | token_entry* new = registered_tokens_ptr + registered_tokens_count - 1;
260 | // printf("n:%p, e:%p, i:%ld, s:%ld\n", new, entry, registered_tokens_count, sizeof(token_entry));
261 | memcpy(new, entry, sizeof(token_entry));
262 | // hexdump("tokens", new, sizeof(token_entry) * registered_tokens_count );
263 | */
264 | array_push(token_array, entry);
265 | }
266 |
267 | void
268 | tokenizer_free_registered_tokens(void)
269 | {
270 | array_destroy(token_array);
271 | /*
272 | registered_tokens_count = 0;
273 | free(registered_tokens_ptr);
274 | registered_tokens_ptr = NULL;
275 | */
276 | }
277 |
278 |
--------------------------------------------------------------------------------
/src/variables.c:
--------------------------------------------------------------------------------
1 | #define _GNU_SOURCE
2 | #include
3 | #include
4 | #include
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | #include "usingwin.h"
12 |
13 | typedef union
14 | {
15 | float num;
16 | char *string;
17 | } variable_value;
18 |
19 | struct variable
20 | {
21 | char *name;
22 | variable_type type;
23 | variable_value value;
24 | bool is_array;
25 | size_t nr_dimensions;
26 | size_t dimensions[5];
27 | array* array;
28 | };
29 |
30 | dictionary *_dictionary = NULL;
31 |
32 | const char* E_INDEX_OUT_OF_BOUNDS = "INDEX OUT OF BOUNDS";
33 | const char* E_VAR_NOT_FOUND = "VAR NOT FOUND";
34 |
35 | #if ARCH!=ARCH_XMEGA
36 | static void vector_print(size_t* vector, size_t dimensions);
37 | #endif
38 |
39 | bool
40 | variables_init(void)
41 | {
42 | _dictionary = dictionary_new();
43 | return _dictionary != NULL;
44 | }
45 |
46 |
47 | static void
48 | cb(char* name, void* value, void* context)
49 | {
50 | variable *var = (variable *) value;
51 | if(var->type == variable_type_string){
52 | if(var->value.string!=NULL) free(var->value.string);
53 | }
54 | if(var->is_array){
55 | array_destroy(var->array);
56 | }
57 | if(var->name!=NULL) free(var->name);
58 | free(var);
59 | }
60 |
61 | void
62 | variables_destroy(void)
63 | {
64 | dictionary_destroy(_dictionary, cb);
65 | }
66 |
67 | variable*
68 | variable_get(char* name)
69 | {
70 | return dictionary_get(_dictionary, name);
71 | }
72 |
73 | char*
74 | variable_get_string(char* name)
75 | {
76 | // printf("Var name: '%s'\n", name);
77 | variable *var = dictionary_get(_dictionary, name);
78 | if(!var){
79 | var = variable_set_string(name, "");
80 | }
81 | return var->value.string;
82 | }
83 |
84 | float
85 | variable_get_numeric(char* name)
86 | {
87 | // printf("Var name: '%s'\n", name);
88 | variable *var = dictionary_get(_dictionary, name);
89 | if(!var){
90 | var = variable_set_numeric(name, 0);
91 | }
92 | return var->value.num;
93 | }
94 |
95 | variable*
96 | variable_set_string(char* name, char* value)
97 | {
98 | // printf("set var '%s' to '%s'\n", name, value);
99 | variable *var = dictionary_get(_dictionary, name);
100 | if(var==NULL){
101 | var = (variable*) malloc(sizeof(variable));
102 | var->name = C_STRDUP(name);
103 | var->type = variable_type_string;
104 | var->is_array = false;
105 | } else {
106 | if(var->value.string!=NULL){
107 | free(var->value.string);
108 | }
109 | }
110 | var->value.string = C_STRDUP(value);
111 | dictionary_put(_dictionary, name, var);
112 | return var;
113 | }
114 |
115 | variable*
116 | variable_set_numeric(char* name, float value)
117 | {
118 | // printf("set var '%s' to %f\n", name, value);
119 | variable *var = dictionary_get(_dictionary, name);
120 | if(var==NULL){
121 | var = (variable*) malloc(sizeof(variable));
122 | var->name = C_STRDUP(name);
123 | var->type = variable_type_numeric;
124 | var->is_array = false;
125 | }
126 | var->value.num = value;
127 | dictionary_put(_dictionary, name, var);
128 | return var;
129 | }
130 |
131 | variable_type
132 | variable_get_type(char* name)
133 | {
134 | variable *var = dictionary_get(_dictionary, name);
135 | return var->type;
136 | }
137 |
138 |
139 | // Calculates array size
140 | // static size_t
141 | //calc_array_size(variable* var)
142 | //{
143 | // size_t size = 1;
144 | // for(size_t i=0; inr_dimensions; i++)
145 | // {
146 | // size *= var->dimensions[i];
147 | // }
148 | //
149 | // printf("size = %ld\n", size);
150 | //
151 | // return size;
152 | //}
153 | //
154 | // Calculates array size
155 | static size_t
156 | calc_size(variable* var)
157 | {
158 | size_t size = 1;
159 | for(size_t i=0; inr_dimensions; ++i)
160 | {
161 | size *= var->dimensions[i];
162 | }
163 |
164 | // printf("array size %s = %ld\n", var->name, size);
165 |
166 | return size;
167 | }
168 |
169 |
170 | static bool
171 | check_in_bounds(variable* var, size_t* vector)
172 | {
173 | // printf("check in bounds\n");
174 | // printf("dimensions %ld\n", var->nr_dimensions);
175 | for(size_t i=0; inr_dimensions; i++)
176 | {
177 | size_t vector_i = vector[i];
178 | // printf("vector_%ld = %ld\n", i, vector_i);
179 | // printf("dimension_%ld = %ld\n", i, var->dimensions[i]);
180 | // DIM A(3) -> A(1), A(2), A(3)
181 | if (vector_i > var->dimensions[i])
182 | {
183 | return false;
184 | }
185 | }
186 |
187 | return true;
188 | }
189 |
190 | /*
191 |
192 | DIM A(2,3)
193 | w h
194 | x y
195 | A(1,1) 0
196 | A(1,2) 1
197 | A(1,3) 2
198 | A(2,1) 3
199 | A(2,2) 4
200 | A(2,3) 5
201 |
202 | (x*ySize*zSize + y*zSize + z)
203 |
204 | v[0] = x
205 | v[1] = y
206 | v[2] = z
207 |
208 | v[0] * d[1] * ... d[n] + v[1] * d[2] ... d[n] + ... + v[n]
209 |
210 |
211 | */
212 |
213 | static size_t
214 | calc_index(variable* var, size_t* vector)
215 | {
216 | // printf("calc_index\n");
217 | // variable_dump(var);
218 |
219 | size_t index = 0;
220 | for(size_t i=0; inr_dimensions; ++i)
221 | {
222 | // size_t product = vector[i] - 1;
223 | size_t product = vector[i];
224 | for(size_t j=i+1; jnr_dimensions; ++j)
225 | {
226 | product *= var->dimensions[j];
227 | }
228 | index += product;
229 | }
230 |
231 | // printf("index[ %s", var->name);
232 | // for(size_t i=0; inr_dimensions; i++){
233 | // printf("%ld", vector[i]);
234 | // if (inr_dimensions-1) printf(",");
235 | // }
236 | // printf(") ] = %ld\n", index);
237 |
238 | return index;
239 | }
240 |
241 | variable*
242 | variable_array_init(char* name, variable_type type, size_t dimensions, size_t* vector)
243 | {
244 | variable* var = (variable*) malloc(sizeof(variable));
245 | var->name = C_STRDUP(name);
246 | var->is_array = true;
247 | var->value.string = NULL;
248 | var->value.num = 0;
249 | var->type = type;
250 | var->nr_dimensions = dimensions;
251 | var->dimensions[0] = vector[0] + 1;
252 | var->dimensions[1] = vector[1] + 1;
253 | var->dimensions[2] = vector[2] + 1;
254 | var->dimensions[3] = vector[3] + 1;
255 | var->dimensions[4] = vector[4] + 1;
256 | var->array = array_new(sizeof(variable_value));
257 | // array_alloc(var->array, calc_size(var, var->nr_dimensions, -1));
258 | array_alloc(var->array, calc_size(var));
259 | dictionary_put(_dictionary, name, var);
260 | return var;
261 | }
262 |
263 | variable*
264 | variable_array_set_string(char *name, char *value, size_t* vector)
265 | {
266 | variable* var = dictionary_get(_dictionary, name);
267 | if (var == NULL)
268 | {
269 | error(E_VAR_NOT_FOUND);
270 | return NULL;
271 | }
272 |
273 | if ( ! check_in_bounds(var, vector) )
274 | {
275 | error(E_INDEX_OUT_OF_BOUNDS);
276 | return NULL;
277 | }
278 |
279 | size_t index = calc_index(var, vector);
280 | variable_value val;
281 | val.string = C_STRDUP(value);
282 | array_set(var->array, index, &val);
283 |
284 | return var;
285 | }
286 |
287 | char*
288 | variable_array_get_string(char *name, size_t* vector)
289 | {
290 | variable* var = dictionary_get(_dictionary, name);
291 | if (var == NULL)
292 | {
293 | error(E_VAR_NOT_FOUND);
294 | return NULL;
295 | }
296 |
297 | if ( ! check_in_bounds(var, vector) )
298 | {
299 | error(E_INDEX_OUT_OF_BOUNDS);
300 | return NULL;
301 | }
302 |
303 | size_t index = calc_index(var, vector);
304 | variable_value* val = array_get(var->array, index);
305 |
306 | return val->string;
307 | }
308 |
309 | variable*
310 | variable_array_set_numeric(char *name, float value, size_t* vector)
311 | {
312 | // printf("set numeric %s, %f, %ld\n", name, value, vector[0]);
313 | variable* var = dictionary_get(_dictionary, name);
314 | if (var == NULL)
315 | {
316 | error(E_VAR_NOT_FOUND);
317 | return NULL;
318 | }
319 |
320 | if ( ! check_in_bounds(var, vector) )
321 | {
322 | error(E_INDEX_OUT_OF_BOUNDS);
323 | return NULL;
324 | }
325 |
326 | // variable_dump(var);
327 | size_t index = calc_index(var, vector);
328 | // printf("index = %ld\n", index);
329 | variable_value val;
330 | val.num = value;
331 | array_set(var->array, index, &val);
332 | // variable_dump(var);
333 |
334 | return var;
335 | }
336 |
337 | float
338 | variable_array_get_numeric(char *name, size_t* vector)
339 | {
340 | variable* var = dictionary_get(_dictionary, name);
341 | if (var == NULL)
342 | {
343 | error(E_VAR_NOT_FOUND);
344 | return 0;
345 | }
346 |
347 | if ( ! check_in_bounds(var, vector) )
348 | {
349 | error(E_INDEX_OUT_OF_BOUNDS);
350 | return 0;
351 | }
352 |
353 | size_t index = calc_index(var, vector);
354 | variable_value* val = array_get(var->array, index);
355 |
356 | return val->num;
357 | }
358 |
359 | struct each_v_ctx
360 | {
361 | variables_each_cb cb;
362 | void* context;
363 | };
364 |
365 | void each_v(char* name, void* value, void* context)
366 | {
367 | struct each_v_ctx* ctx = (struct each_v_ctx*) context;
368 | variable* var = (variable*) value;
369 | ctx->cb(var, ctx->context);
370 | }
371 |
372 | void
373 | variables_each(variables_each_cb each, void* context)
374 | {
375 | struct each_v_ctx ctx =
376 | {
377 | .cb = each,
378 | .context = context
379 | };
380 | dictionary_each(_dictionary, each_v, &ctx);
381 | }
382 |
383 | #if ARCH!=ARCH_XMEGA
384 |
385 | static void
386 | calc_vector(variable* var, size_t index, size_t* vector)
387 | {
388 | size_t product = 1;
389 | for(size_t i=1; inr_dimensions; ++i)
390 | {
391 | product *= var->dimensions[i];
392 | }
393 |
394 | for(int i=0; inr_dimensions; ++i)
395 | {
396 | vector[i] = index / product;
397 | index %= product;
398 | if( (i+1) < var->nr_dimensions )
399 | {
400 | product /= var->dimensions[i+1];
401 | }
402 | }
403 | }
404 |
405 | static void
406 | vector_print(size_t* vector, size_t dimensions)
407 | {
408 | for(size_t j=0; jname,
426 | (var->type == variable_type_numeric) ? "number" : "string"
427 | );
428 |
429 | if (var->is_array)
430 | {
431 | printf("\tdimensions: %ld\n", var->nr_dimensions);
432 | for(size_t d=0; dnr_dimensions; d++)
433 | {
434 | printf("\tdim %ld size = %ld\n", d, var->dimensions[d]);
435 | }
436 | printf("\tarray size: %ld\n", array_size(var->array));
437 | for(size_t i=0; iarray); i++)
438 | {
439 | size_t vector[5];
440 | calc_vector(var, i, vector);
441 | printf("\t%3ld %s", i, var->name);
442 | vector_print(vector, var->nr_dimensions);
443 | printf(") = ");
444 | variable_value* val = array_get(var->array, i);
445 | if (var->type == variable_type_string)
446 | {
447 | printf("%s\n", (val->string) ? val->string : "");
448 | }
449 | else
450 | {
451 | printf("%f\n", val->num);
452 | }
453 | }
454 | }
455 | else
456 | {
457 | if (var->type == variable_type_numeric)
458 | {
459 | printf("\tvalue: %f\n", var->value.num);
460 | }
461 | else
462 | {
463 | printf("\tvalue: '%s'\n", var->value.string);
464 | }
465 |
466 | }
467 | }
468 | #endif
469 |
--------------------------------------------------------------------------------
/t/Makefile:
--------------------------------------------------------------------------------
1 | root = ..
2 |
3 | CC = gcc-4.8
4 | SOURCES = main.c $(wildcard test_*.c)
5 |
6 | _OBJECTS = $(patsubst %.c,%.o,$(SOURCES))
7 | _OBJECTS += $(wildcard $(root)/build/*.o)
8 | OBJECTS = $(filter-out $(root)/build/main.o,$(_OBJECTS))
9 |
10 | INCLUDE_FOLDERS = $(root)/include
11 |
12 | CFLAGS += $(addprefix -I,$(INCLUDE_FOLDERS)) -std=c99
13 |
14 | CFLAGS += $(shell pkg-config --cflags cmocka)
15 | LDFLAGS += $(shell pkg-config --libs cmocka)
16 |
17 | .PHONY: test run clean start
18 |
19 | test: start $(OBJECTS)
20 | @ echo "LD $@"
21 | @ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS)
22 | @ echo "done"
23 | @ echo ""
24 |
25 | start:
26 | @ echo "-- Building unit tests"
27 |
28 | %.o : %.c
29 | @ echo "CC $@"
30 | @ $(CC) $(CFLAGS) -c $< -o $@
31 |
32 | run: test
33 | @ echo "-- Running unit tests"
34 | @ ./test
35 |
36 | debug: test
37 | @ echo "-- Debugging $(test)"
38 | @ echo "run" | gdb ./test
39 | clean:
40 | @ rm -f test
41 | @ rm -f *.o
42 |
--------------------------------------------------------------------------------
/t/main.c:
--------------------------------------------------------------------------------
1 | #include "test.h"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | extern void test_dictionary(void **state);
9 |
10 | extern void test_lines(void **state);
11 | extern int lines_setup(void **state);
12 | extern int lines_teardown(void **state);
13 |
14 | static void test_BASIC(void **state)
15 | {
16 | assert_true( true );
17 | }
18 |
19 | int main(void) {
20 | const struct CMUnitTest tests[] = {
21 | cmocka_unit_test(test_BASIC),
22 | cmocka_unit_test(test_dictionary),
23 | // cmocka_unit_test(test_lines)
24 | cmocka_unit_test_setup_teardown(test_lines, lines_setup, lines_teardown)
25 | };
26 | return cmocka_run_group_tests(tests, NULL, NULL);
27 | }
28 |
--------------------------------------------------------------------------------
/t/test.h:
--------------------------------------------------------------------------------
1 | #ifndef __TEST_H__
2 | #define __TEST_H__
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #endif // __TEST_H__
10 |
--------------------------------------------------------------------------------
/t/test_dictionary.c:
--------------------------------------------------------------------------------
1 | #include "test.h"
2 |
3 | #include
4 |
5 | #include
6 |
7 | void p(char *name, void* value)
8 | {
9 | printf("n: %s, v: %p\n", name, value);
10 | }
11 |
12 | void dump(dictionary* d)
13 | {
14 | dictionary_each(d, p);
15 | }
16 |
17 | void test_dictionary(void **state)
18 | {
19 | // assert_true(false);
20 |
21 | dictionary *d = dictionary_new();
22 | assert_non_null( d );
23 |
24 | int v1 = 1000;
25 | dictionary_put(d, "int", &v1);
26 |
27 | char *v2 = "text";
28 | dictionary_put(d, "string", &v2);
29 |
30 | assert_true( dictionary_has(d, "int") );
31 | assert_true( dictionary_has(d, "string") );
32 | assert_false( dictionary_has(d, "something") );
33 |
34 | assert_non_null( dictionary_del(d, "int") );
35 |
36 | dump(d);
37 |
38 | assert_false( dictionary_has(d, "int") );
39 |
40 | dictionary_destroy(d, NULL);
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/t/test_lines.c:
--------------------------------------------------------------------------------
1 | #include "test.h"
2 |
3 | #include
4 |
5 | #include
6 |
7 | static char __memory[1024];
8 | static size_t __memory_size = sizeof(__memory);
9 |
10 | int lines_setup(void **state)
11 | {
12 | lines_init(__memory, __memory_size);
13 | return 0;
14 | }
15 |
16 | int lines_teardown(void **state)
17 | {
18 | return 0;
19 | }
20 |
21 | static void out(uint16_t number, char* contents)
22 | {
23 | static int calls = 0;
24 |
25 | printf("(%d) '%s'\n", number, contents);
26 |
27 | calls++;
28 |
29 | // assert_int_equal( number, 10 * calls );
30 | }
31 |
32 |
33 | void test_lines(void **state)
34 | {
35 | /*
36 | assert_true
37 | (
38 | lines_insert(10, "XXX")
39 | );
40 |
41 | line* l10 = lines_get_by_number(10);
42 |
43 | assert_int_equal
44 | (
45 | l10->number, 10
46 | );
47 | assert_string_equal
48 | (
49 | l10->contents, "XXX"
50 | );
51 |
52 | assert_true
53 | (
54 | lines_store(20, "YYY")
55 | );
56 |
57 | line* l20 = lines_get_by_number(20);
58 |
59 | assert_int_equal
60 | (
61 | l20->number, 20
62 | );
63 | assert_string_equal
64 | (
65 | l20->contents, "YYY"
66 | );
67 |
68 | lines_list(out);
69 | */
70 |
71 | lines_store(10, "XXXX 10");
72 | lines_store(20, "XXXX 20");
73 | lines_store(30, "XXXX 30");
74 | lines_list(out);
75 |
76 | lines_store(15, "XXXX 15");
77 | lines_list(out);
78 |
79 | lines_store(20, "XXXX 20.2");
80 | lines_list(out);
81 |
82 | lines_store(20, "XXXX 20");
83 | lines_list(out);
84 |
85 | lines_store(5, "XXXX 5");
86 | lines_list(out);
87 |
88 | lines_store(40, "XXXX 40");
89 | lines_list(out);
90 |
91 | char* l15 = lines_get_contents( 15 );
92 | assert_string_equal( l15, "XXXX 15" );
93 |
94 | printf("iterate lines:\n");
95 | uint16_t line = lines_first();
96 | while (true)
97 | {
98 | printf(" %d\n", line);
99 | line = lines_next( line );
100 | if ( line == 0 )
101 | {
102 | break;
103 | }
104 | }
105 | printf("-- done\n");
106 |
107 | lines_delete( 11 );
108 | lines_list(out);
109 |
110 | lines_delete( 5 );
111 | lines_list(out);
112 |
113 | lines_delete( 40 );
114 | lines_list(out);
115 |
116 | lines_delete( 15 );
117 | lines_list(out);
118 |
119 | lines_clear();
120 | lines_list(out);
121 | }
122 |
--------------------------------------------------------------------------------
/test:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # command="./build/basic/basic"
4 | command="valgrind --leak-check=full --show-leak-kinds=all ./build/basic/basic"
5 |
6 | cat examples/autolist | while read bas; do echo $bas; $command $bas; done
7 |
--------------------------------------------------------------------------------