├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ ├── cmake.yml │ └── codeql-analysis.yml ├── .gitignore ├── CMakeLists.txt ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── COPYING ├── LANG.md ├── README.md ├── SECURITY.md ├── TODO.md ├── bin └── .gitignore ├── examples ├── guess.bas └── sample.bas ├── include ├── abs.h ├── addop.h ├── atn.h ├── buffer.h ├── command.h ├── config.h.in ├── cos.h ├── cot.h ├── eval.h ├── exp.h ├── expr_item.h ├── expr_list.h ├── expression.h ├── factor.h ├── int_.h ├── line.h ├── log.h ├── mulop.h ├── number.h ├── pi.h ├── primary.h ├── prng.h ├── readaline.h ├── relop.h ├── rem.h ├── rnd.h ├── runtime.h ├── sgn.h ├── shell.h ├── sin.h ├── sqr.h ├── statement.h ├── str.h ├── tan.h ├── term.h ├── time_.h ├── tokenizer.h ├── var.h └── var_list.h ├── man └── tcbasic.1.in ├── src ├── abs.c ├── addop.c ├── atn.c ├── buffer.c ├── command.c ├── cos.c ├── cot.c ├── driver.c ├── eval.c ├── exp.c ├── expr_item.c ├── expr_list.c ├── expression.c ├── factor.c ├── int_.c ├── line.c ├── log.c ├── mulop.c ├── number.c ├── pi.c ├── primary.c ├── prng.c ├── readaline.c ├── relop.c ├── rem.c ├── rnd.c ├── runtime.c ├── sgn.c ├── shell.c ├── sin.c ├── sqr.c ├── statement.c ├── str.c ├── tan.c ├── term.c ├── time_.c ├── tokenizer.c ├── var.c └── var_list.c └── tests ├── abs.bas ├── abs.ex ├── coinflip.bas ├── coinflip.ex ├── division.bas ├── division.ex ├── fib.bas ├── fib.ex ├── for.bas ├── for.ex ├── functions.bas ├── functions.ex ├── hello.bas ├── hello.ex ├── int_.bas ├── int_.ex ├── mod.bas ├── mod.ex ├── newton.bas ├── newton.ex ├── pemdas.bas ├── pemdas.ex ├── pi.bas ├── pi.ex ├── remainder.bas ├── remainder.ex ├── shell.bas ├── shell.ex ├── squares.bas └── squares.ex /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/workflows/cmake.yml: -------------------------------------------------------------------------------- 1 | name: CMake 2 | 3 | on: [push] 4 | 5 | env: 6 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) 7 | BUILD_TYPE: Release 8 | 9 | jobs: 10 | build: 11 | # The CMake configure and build commands are platform agnostic and should work equally 12 | # well on Windows or Mac. You can convert this to a matrix build if you need 13 | # cross-platform coverage. 14 | # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | 20 | - name: Create Build Environment 21 | # Some projects don't allow in-source building, so create a separate build directory 22 | # We'll use this as our working directory for all subsequent commands 23 | run: cmake -E make_directory ${{runner.workspace}}/build 24 | 25 | - name: Configure CMake 26 | # Use a bash shell so we can use the same syntax for environment variable 27 | # access regardless of the host operating system 28 | shell: bash 29 | working-directory: ${{runner.workspace}}/build 30 | # Note the current convention is to use the -S and -B options here to specify source 31 | # and build directories, but this is only available with CMake 3.13 and higher. 32 | # The CMake binaries on the Github Actions machines are (as of this writing) 3.12 33 | run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE 34 | 35 | - name: Build 36 | working-directory: ${{runner.workspace}}/build 37 | shell: bash 38 | # Execute the build. You can specify a specific target with "--target " 39 | run: cmake --build . --config $BUILD_TYPE 40 | 41 | - name: Test 42 | working-directory: ${{runner.workspace}}/build 43 | shell: bash 44 | # Execute tests defined by the CMake configuration. 45 | # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail 46 | run: ctest -C $BUILD_TYPE 47 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # ******** NOTE ******** 12 | 13 | name: "CodeQL" 14 | 15 | on: 16 | push: 17 | branches: [ master ] 18 | pull_request: 19 | # The branches below must be a subset of the branches above 20 | branches: [ master ] 21 | schedule: 22 | - cron: '31 6 * * 3' 23 | 24 | jobs: 25 | analyze: 26 | name: Analyze 27 | runs-on: ubuntu-latest 28 | 29 | strategy: 30 | fail-fast: false 31 | matrix: 32 | language: [ 'cpp' ] 33 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 34 | # Learn more: 35 | # https://docs.github.com/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 36 | 37 | steps: 38 | - name: Checkout repository 39 | uses: actions/checkout@v2 40 | 41 | # Initializes the CodeQL tools for scanning. 42 | - name: Initialize CodeQL 43 | uses: github/codeql-action/init@v1 44 | with: 45 | languages: ${{ matrix.language }} 46 | # If you wish to specify custom queries, you can do so here or in a config file. 47 | # By default, queries listed here will override any specified in a config file. 48 | # Prefix the list here with "+" to use these queries and those in the config file. 49 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 50 | 51 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 52 | # If this step fails, then you should remove it and run the build manually (see below) 53 | - name: Autobuild 54 | uses: github/codeql-action/autobuild@v1 55 | 56 | # ℹ️ Command-line programs to run using the OS shell. 57 | # 📚 https://git.io/JvXDl 58 | 59 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 60 | # and modify them (or add more) to build your code if your project 61 | # uses a compiled language 62 | 63 | #- run: | 64 | # make bootstrap 65 | # make release 66 | 67 | - name: Perform CodeQL Analysis 68 | uses: github/codeql-action/analyze@v1 69 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | aclocal.m4 3 | autom4te.cache/ 4 | compile 5 | config.h 6 | config.in 7 | config.in~ 8 | config.log 9 | config.status 10 | configure 11 | cov-int 12 | depcomp 13 | .deps/ 14 | install-sh 15 | Makefile 16 | Makefile.in 17 | missing 18 | parser.c 19 | parser.h 20 | parser.plist 21 | scanner.c 22 | scanner.h 23 | scanner.plist 24 | stamp-h1 25 | tcbasic 26 | tcbasic.1 27 | tcbasic*.tar.gz 28 | tcbasic.tgz 29 | test-driver 30 | test-suite.log 31 | *.out 32 | *.log 33 | *.trs 34 | ylwrap 35 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # tcbasic - a small BASIC Interpreter written in C. 2 | # Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | 17 | cmake_minimum_required(VERSION 3.10) 18 | project(tcbasic VERSION 2.3.0 LANGUAGES C) 19 | 20 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_DEFAULT_SOURCE") 21 | set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wall -Werror -Wextra -Wpedantic") 22 | 23 | configure_file ( 24 | "${PROJECT_SOURCE_DIR}/include/config.h.in" 25 | "${PROJECT_BINARY_DIR}/include/config.h" 26 | ) 27 | 28 | include_directories( 29 | "${PROJECT_SOURCE_DIR}/include" 30 | "${PROJECT_BINARY_DIR}/include" 31 | ) 32 | 33 | configure_file ( 34 | "${PROJECT_SOURCE_DIR}/man/tcbasic.1.in" 35 | "${PROJECT_BINARY_DIR}/man/tcbasic.1" 36 | ) 37 | 38 | file(GLOB SOURCES "src/*.c") 39 | add_executable(tcbasic ${SOURCES}) 40 | target_link_libraries(tcbasic m) 41 | install(TARGETS tcbasic DESTINATION bin) 42 | install(FILES ${PROJECT_BINARY_DIR}/man/tcbasic.1 DESTINATION man/man1) 43 | install(DIRECTORY ${PROJECT_SOURCE_DIR}/examples DESTINATION share/${PROJECT_NAME}) 44 | 45 | include(CTest) 46 | enable_testing() 47 | 48 | set (functional_tests abs coinflip division fib for functions hello int_ mod newton pemdas pi remainder shell squares) 49 | foreach(test ${functional_tests}) 50 | add_test(NAME ${test}_exec COMMAND sh -c "${PROJECT_BINARY_DIR}/${PROJECT_NAME} ${PROJECT_SOURCE_DIR}/tests/${test}.bas > ${PROJECT_BINARY_DIR}/tests_${test}.out") 51 | add_test(NAME ${test}_check COMMAND ${CMAKE_COMMAND} -E compare_files ${PROJECT_SOURCE_DIR}/tests/${test}.ex ${PROJECT_BINARY_DIR}/tests_${test}.out) 52 | endforeach() 53 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at linuxgeek@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing 2 | ============ 3 | 4 | 1. Fork it 5 | 2. Create your feature branch (`git checkout -b my-new-feature`) 6 | 3. Commit your changes (`git commit -am 'Add some feature'`) 7 | 4. Push to the branch (`git push origin my-new-feature`) 8 | 5. Create new Pull Request 9 | -------------------------------------------------------------------------------- /LANG.md: -------------------------------------------------------------------------------- 1 | # tcbasic Language Reference 2 | 3 | ## Operators 4 | 5 | ### Arithmetic Operators 6 | 7 | - `+` - addition 8 | - `-` - subtraction 9 | - `*` - multiplication 10 | - `/` - division 11 | - `\` - integer division 12 | - `%` - modulus 13 | - `^` - exponentiation 14 | 15 | ### Relational Operators 16 | 17 | - `<=` - less than or equal to 18 | - `<` - less than 19 | - `=` - equal to 20 | - `<>` - not equal to 21 | - `><` - not equal to 22 | - `>` - greater than 23 | - `>=` - greater than or equal to 24 | 25 | ## Statements 26 | 27 | ### REM remark 28 | 29 | Remark has no effect on the execution of the program and acts as a comment to the developer. The remark can contain any character. 30 | 31 | Example: 32 | 33 | 10 REM anything after "REM" is considered a comment and ignored by the interpreter. 34 | 35 | ### PRINT list 36 | 37 | Prints the contents of 'list' to the console where 'list' is a comma separated list of one or more quoted strings, expressions, and/or variables. 38 | 39 | Example: 40 | 41 | 10 PRINT 2,"+",2,"=",2+2 42 | 43 | ### IF expression relop expression THEN statement 44 | 45 | Evaluates both 'expression's and compares them using relational operator 'relop'. If the relation is true, then the statement will be executed. Otherwise, the statement is skipped. 46 | 47 | Example: 48 | 49 | 1000 PRINT "Enter a number:" 50 | 1010 INPUT A 51 | 1020 REM Absolute value of A 52 | 1030 IF A < 0 THEN LET A = -A 53 | 1040 PRINT "The absolute value of the number entered is: ",A 54 | 55 | ### GOTO expression 56 | 57 | Evaluates 'expression' and jumps to the corresponding line number. It may appear with with or without whitespace between `GO` and `TO`. For example, both `GOTO 70` and `GO TO 70` are equivalent. 58 | 59 | Example: 60 | 61 | 10 PRINT "How old are you?" 62 | 20 INPUT A 63 | 30 IF A >= 40 THEN GOTO 60 64 | 40 PRINT "You are too young!" 65 | 50 GOTO 70 66 | 60 PRINT "You are over the hill!" 67 | 70 END 68 | 69 | ### INPUT var_list 70 | 71 | Given a comma separated list of 1 or more variables, this command will prompt the user to enter a comma separated list of expressions. The value of each expression will be assigned to each corresponding variable. 72 | 73 | Example: 74 | 75 | 10 PRINT "Enter 2 numbers to multiply:" 76 | 20 INPUT A,B 77 | 30 PRINT "The product of ",A," and ",B," is ",A*B 78 | 79 | ### FOR var = expression TO expression (STEP expression) / NEXT I 80 | 81 | Evaluates the first 'expression' and assigns the result to the index variable 82 | 'var' when entering the loop. Before each iteration, the second expression is 83 | evaluated and compared to the index variable. If the limit is not exceeded, 84 | another iteration takes place. At the end of each iteration, the step 85 | 'expression' is evaluated and added to the index variable. If a step 'expression' 86 | is not provided, the step defaults to `1`. 87 | 88 | Example: 89 | 90 | 10 PRINT "Squares of integers from 1 to 10" 91 | 20 FOR I = 1 TO 10 92 | 30 PRINT I^2 93 | 40 NEXT I 94 | 50 END 95 | 96 | ### GOSUB expression 97 | 98 | Evaluates 'expression' and jumps to the corresponding line number after saving the current line number. It may appear with with or without whitespace between `GO` and `SUB`. For example, both `GOSUB 100` and `GO SUB 100` are equivalent. 99 | 100 | Example: 101 | 102 | 10 PRINT "Enter 2 numbers to multiply:" 103 | 20 INPUT A,B 104 | 30 GOSUB 100 105 | 40 PRINT "The product of ",A," and ",B," is ",C 106 | 50 END 107 | 108 | 100 REM Multiply Subroutine 109 | 110 LET C = A*B 110 | 120 RETURN 111 | 112 | ### RETURN 113 | 114 | Returns control to the line after the last 'GOSUB' call. 115 | 116 | Example: 117 | 118 | 10 PRINT "Enter 2 numbers to multiply:" 119 | 20 INPUT A,B 120 | 30 GOSUB 100 121 | 40 PRINT "The product of ",A," and ",B," is ",C 122 | 50 END 123 | 124 | 100 REM Multiply Subroutine 125 | 110 LET C = A*B 126 | 120 RETURN 127 | 128 | ### LET var = expression 129 | 130 | Assigns the value of expression to variable 'var' where 'var' is a single character variable name in the range from A to Z. 131 | 132 | Example: 133 | 134 | 10 LET A = 2 135 | 20 LET B = 2 136 | 30 LET C = A + B 137 | 40 PRINT A,"+",B,"=",C 138 | 139 | ### END 140 | 141 | Ends the execution of the program. 142 | 143 | Example: 144 | 145 | 10 PRINT "Hello, World" 146 | 20 END 147 | 30 REM Nothing is executed after the 'END' statement is executed. 148 | 40 PRINT "Nothing to see here" 149 | 150 | ### STOP 151 | 152 | Exits the interpreter. 153 | 154 | Example: 155 | 156 | STOP 157 | 158 | ### BEEP 159 | 160 | System beep. 161 | 162 | Example: 163 | 164 | 100 BEEP 165 | 166 | ### SHELL cmd 167 | 168 | Executes a shell command. 169 | 170 | Example: 171 | 172 | 100 PRINT "Current uptime:" 173 | 200 SHELL "uptime" 174 | 175 | ### RANDOMIZE 176 | 177 | Re-seeds the random number generator, causing RND to return a different sequence of random numbers. 178 | 179 | Example: 180 | 181 | 10 REM Flip a coin and print HEADS or TAILS 182 | 15 RANDOMIZE 183 | 20 LET C = RND 184 | 30 IF C < 0.5 THEN PRINT "HEADS" 185 | 40 IF C >= 0.5 THEN PRINT "TAILS" 186 | 187 | ### CLS 188 | 189 | Clears the screen. 190 | 191 | Example: 192 | 193 | 10 REM Clear screen and print "Hello" 194 | 20 CLS 195 | 30 PRINT "Hello" 196 | 197 | ## Commands 198 | 199 | ### CLEAR 200 | 201 | Clears the program from memory and sets all variables to 0. 202 | 203 | Example: 204 | 205 | CLEAR 206 | 207 | ### LIST 208 | 209 | Prints the current program. 210 | 211 | Example: 212 | 213 | LIST 214 | 215 | ### RENUM 216 | 217 | Renumber lines in memory. 218 | 219 | Example: 220 | 221 | 1 REM FOO 222 | 2 REM BAR 223 | 5 REM BAZ 224 | RENUM 225 | LIST 226 | 10 REM FOO 227 | 20 REM BAR 228 | 30 REM BAZ 229 | 230 | ### RUN 231 | 232 | Executes the current program. 233 | 234 | Example: 235 | 236 | RUN 237 | 238 | ### TROFF 239 | 240 | Turn off debug tracing. 241 | 242 | TROFF 243 | 244 | ### TRON 245 | 246 | Turn on debug tracing. When on, debug tracing prints "TR> " followed by the line that is about to be executed. Use `TROFF` to turn tracing off. 247 | 248 | 10 PRINT "HELLO" 249 | 20 PRINT "GOODBYE" 250 | TRON 251 | RUN 252 | TR> 10 PRINT "HELLO" 253 | HELLO 254 | TR> 20 PRINT "GOODBYE" 255 | GOODBYE 256 | 257 | ## Built-in Functions 258 | 259 | ### π 260 | 261 | Symbol evaluates to Pi (`3.14159265`) 262 | 263 | Example: 264 | 265 | 10 PRINT "Enter the radius of the circle" 266 | 20 INPUT r 267 | 30 LET c = 2 * π * r 268 | 40 PRINT "Circumference of circle with radius ",r," is ", c 269 | 270 | ### RND 271 | 272 | Returns a random number in the range [0,1). The same sequence of numbers is returned in each program run. Use the RANDOMIZE statement to generate different sequences in each program run. 273 | 274 | Example: 275 | 276 | 10 REM Flip a coin and print HEADS or TAILS 277 | 20 LET C = RND 278 | 30 IF C < 0.5 THEN PRINT "HEADS" 279 | 40 IF C >= 0.5 THEN PRINT "TAILS" 280 | 281 | ### TIME 282 | 283 | Returns the number of seconds since midnight. 284 | 285 | Example: 286 | 287 | 10 PRINT TIME 288 | 289 | ### SIN (expression) 290 | 291 | Returns the sine of the given expression (measured in radians). 292 | 293 | Example: 294 | 295 | 110 LET A = SIN((0*3.1415926)/2) 296 | 297 | ### COS (expression) 298 | 299 | Returns the cosine of the given expression (measured in radians). 300 | 301 | Example: 302 | 303 | 210 LET A = COS((0*3.1415926)/2) 304 | 305 | ### TAN (expression) 306 | 307 | Returns the tangent of the given expression (measured in radians). 308 | 309 | Example: 310 | 311 | 320 LET B = TAN(-3) 312 | 313 | ### COT (expression) 314 | 315 | Returns the cotangent of the given expression (measured in radians). 316 | 317 | Example: 318 | 319 | 420 LET B = COT(-0.01) 320 | 321 | ### ATN (expression) 322 | 323 | Returns the arctangent of the given expression (measured in radians). 324 | 325 | Example: 326 | 327 | 530 LET C = ATN(1.0) 328 | 329 | ### EXP (expression) 330 | 331 | Returns `e` to the power of the given expression. 332 | 333 | Example: 334 | 335 | 610 LET A = EXP(2.0) 336 | 337 | ### LOG (expression) 338 | 339 | Returns the natural logarithm of of the given expression. 340 | 341 | Example: 342 | 343 | 720 LET B = LOG(2) 344 | 345 | ### ABS (expression) 346 | 347 | Returns the absolute value of the given expression. 348 | 349 | Example: 350 | 351 | 840 LET D = ABS(-2.0) 352 | 353 | ### INT (expression) 354 | 355 | Returns the integer portion of the given expression. 356 | 357 | Example: 358 | 359 | 905 LET T = INT(RND * 100) + 1 360 | 361 | ### SGN (expression) 362 | 363 | Returns the sign of the given expression. `1` if `expression > 0`, `0` if `expression = 0`, `-1` if `expression < 0`. 364 | 365 | 40 LET S = SGN(3.14159) 366 | 367 | ### SQR (expression) 368 | 369 | Returns the square root of the given expression. 370 | 371 | Example: 372 | 373 | 920 LET B = SQR(2) 374 | 375 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tcbasic 2 | 3 | tcbasic is a small [BASIC](http://en.wikipedia.org/wiki/BASIC) Interpreter 4 | written in [C](http://en.wikipedia.org/wiki/C_%28programming_language%29). 5 | 6 | ## Current Status 7 | 8 | The "basics" are done and working. The interpreter implements the 9 | [Tiny BASIC](http://en.wikipedia.org/wiki/Tiny_BASIC) dialect of BASIC 10 | with added support for floating point numbers and many of the built-in mathematical 11 | functions in [Dartmouth BASIC](http://en.wikipedia.org/wiki/Dartmouth_BASIC). 12 | Development will continue with the goal of implementing successively more 13 | complete dialects of BASIC. 14 | 15 | ## Requirements 16 | 17 | * C compiler and standard build tools (make, sh, ...). 18 | * [cmake](https://cmake.org/) 19 | 20 | ## Building 21 | 22 | Standard cmake build (`make test` runs the test suite): 23 | 24 | $ cd bin 25 | $ cmake .. 26 | $ make 27 | $ make test 28 | # make install 29 | 30 | ## Using 31 | 32 | Start the interpreter in interactive mode: 33 | 34 | $ tcbasic 35 | 36 | Execute a program from a file in batch mode: 37 | 38 | $ tcbasic sample.bas 39 | 40 | ## Example Program 41 | 42 | 10 REM Square Root Calculator using Newton's Method 43 | 44 | 100 LET X = 1337 45 | 400 GOSUB 1000 46 | 500 PRINT "The square root of ",X," is approximately ",Y 47 | 600 END 48 | 49 | 1000 REM Calculate the square root of a given Number 50 | 1001 REM Expects input to be in X. Output will be in Y. 51 | 1002 REM Uses Z as a temporary variable. 52 | 1050 LET Y = 0.5 * X 53 | 1100 LET Z = Y 54 | 1200 LET Y = Y-(((Y^2)-X)/(2*Y)) 55 | 1300 IF Z <> Y THEN GOTO 1100 56 | 1400 RETURN 57 | 58 | ## Language Reference 59 | 60 | See `LANG.md` 61 | 62 | ## License 63 | 64 | See `COPYING` for the full license. Here's a summary: 65 | 66 | tcbasic - a small BASIC Interpreter written in C. 67 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 68 | 69 | This program is free software: you can redistribute it and/or modify 70 | it under the terms of the GNU General Public License as published by 71 | the Free Software Foundation, either version 3 of the License, or 72 | (at your option) any later version. 73 | 74 | This program is distributed in the hope that it will be useful, 75 | but WITHOUT ANY WARRANTY; without even the implied warranty of 76 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 77 | GNU General Public License for more details. 78 | 79 | You should have received a copy of the GNU General Public License 80 | along with this program. If not, see . 81 | 82 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Only the current version is supported. 6 | 7 | ## Reporting a Vulnerability 8 | 9 | Report vulnerabilities the same way you would any bug: https://github.com/tcort/tcbasic/issues 10 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | Enhancements: 2 | 3 | * PRINT separators (';' vs ','), print zone, etc 4 | 5 | Implement additional statements: 6 | 7 | * READ/DATA/RESTORE 8 | * ON .. GOTO 9 | * DEF 10 | * DIM 11 | 12 | Implement language fundamentals: 13 | 14 | * Strings 15 | * Arrays (test with quicksort) 16 | 17 | Implement language standards / defacto standards: 18 | 19 | * Dartmouth BASIC 20 | * ECMA-55 Minimal BASIC 21 | * ECMA-116 Level 1 and 2 22 | 23 | Internals: 24 | 25 | * Better representation of lines. 26 | 27 | Testing: 28 | 29 | * write more tests 30 | * add a preflight test to run cppcheck, valgrind, etc. 31 | 32 | Other changes: 33 | 34 | * Better error handling / reporting. 35 | 36 | -------------------------------------------------------------------------------- /bin/.gitignore: -------------------------------------------------------------------------------- 1 | CMakeCache.txt 2 | CMakeFiles 3 | cmake_install.cmake 4 | CTestTestfile.cmake 5 | DartConfiguration.tcl 6 | include 7 | Makefile 8 | tcbasic 9 | Testing 10 | *.out 11 | -------------------------------------------------------------------------------- /examples/guess.bas: -------------------------------------------------------------------------------- 1 | 10 RANDOMIZE 2 | 100 LET N = INT(RND * 100) + 1 3 | 1000 PRINT "I'm thinking of a number between 1 and 100. What is it?" 4 | 1100 INPUT G 5 | 1300 IF G > N THEN GOTO 7000 6 | 1400 IF G < N THEN GOTO 8000 7 | 1500 IF G = N THEN GOTO 9000 8 | 7000 PRINT G, " is too high!" 9 | 7100 GOTO 1000 10 | 8000 PRINT G, " is too low!" 11 | 8100 GOTO 1000 12 | 9000 PRINT G, " is correct!" 13 | 9100 END 14 | -------------------------------------------------------------------------------- /examples/sample.bas: -------------------------------------------------------------------------------- 1 | 1 REM This is a fibonacci number calculator! 2 | 10 PRINT "How many fibonacci numbers should I calculate?" 3 | 20 INPUT X 4 | 30 IF X <= 2 THEN GOTO 10 5 | 40 PRINT "Calculating the first ",X," fibonacci numbers: " 6 | 50 PRINT "fib[0] = 0" 7 | 60 PRINT "fib[1] = 1" 8 | 70 LET J = 1 9 | 10 | 100 LET J = J + 1 11 | 110 LET A = 0 12 | 120 LET B = 1 13 | 130 LET I = 1 14 | 140 GOSUB 1000 15 | 150 PRINT "fib[",J,"] = ",C 16 | 160 IF J < X-1 THEN GOTO 100 17 | 170 END 18 | 19 | 1000 LET C = B + A 20 | 1010 LET T = B 21 | 1020 LET B = C 22 | 1030 LET A = T 23 | 1040 LET I = I + 1 24 | 1050 IF I = J THEN RETURN 25 | 1060 GOTO 1000 26 | -------------------------------------------------------------------------------- /include/abs.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_ABS_H 20 | #define TCBASIC_ABS_H 21 | 22 | struct number; 23 | struct tokenizer; 24 | 25 | struct abs { 26 | struct expression *e; 27 | }; 28 | 29 | struct abs *new_abs(struct expression *e); 30 | struct abs *parse_abs(struct tokenizer *t); 31 | struct number *eval_abs(struct abs *a); 32 | void print_abs(struct abs *a); 33 | void free_abs(struct abs *a); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /include/addop.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_ADDOP_H 20 | #define TCBASIC_ADDOP_H 21 | 22 | struct tokenizer; 23 | 24 | struct addop { 25 | int type; 26 | }; 27 | 28 | struct addop *new_addop(int type); 29 | struct addop *parse_addop(struct tokenizer *t); 30 | int eval_addop(struct addop *op); 31 | void print_addop(struct addop *op); 32 | void free_addop(struct addop *op); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /include/atn.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_ATN_H 20 | #define TCBASIC_ATN_H 21 | 22 | struct number; 23 | struct tokenizer; 24 | 25 | struct atn { 26 | struct expression *e; 27 | }; 28 | 29 | struct atn *new_atn(struct expression *e); 30 | struct atn *parse_atn(struct tokenizer *t); 31 | struct number *eval_atn(struct atn *a); 32 | void print_atn(struct atn *a); 33 | void free_atn(struct atn *a); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /include/buffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_BUFFER_H 20 | #define TCBASIC_BUFFER_H 21 | 22 | typedef struct Buffer { 23 | char *buf; /* pointer returned by malloc */ 24 | size_t maxsize; /* size of space allocated by malloc */ 25 | size_t cursize; /* amount of space currently used */ 26 | size_t incr; /* increment to add when growing maxsize */ 27 | } Buffer; 28 | 29 | /* allocates a new Buffer structure */ 30 | Buffer *bf_alloc(size_t size, size_t incr); 31 | 32 | /* adds the character ch to the end of the given Buffer */ 33 | void bf_addch(Buffer *buf, char ch); 34 | 35 | /* re-initializes the given Buffer, such that the next call to 36 | bf_addch will put the character at the start of the buffer */ 37 | void bf_clear(Buffer *buf); 38 | 39 | /* tests that the given pointer is a valid Buffer */ 40 | void bf_valid(Buffer *buf); 41 | 42 | /* de-allocates the Buffer and any memory it may contain */ 43 | void bf_free(Buffer *buf); 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /include/command.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_COMMAND_H 20 | #define TCBASIC_COMMAND_H 21 | 22 | struct tokenizer; 23 | 24 | struct command { 25 | int type; 26 | }; 27 | 28 | struct command *new_command(int type); 29 | struct command *parse_command(struct tokenizer *t); 30 | void exec_command(struct command *cmd); 31 | void free_command(struct command *cmd); 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /include/config.h.in: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_CONFIG_H 20 | #define TCBASIC_CONFIG_H 21 | 22 | #define PROJECT_NAME "@PROJECT_NAME@" 23 | #define PROJECT_VERSION "@PROJECT_VERSION@" 24 | #define PROJECT_STRING "@PROJECT_NAME@ @PROJECT_VERSION@" 25 | 26 | #define PROJECT_BUGREPORT "https://github.com/tcort/tcbasic/issues" 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /include/cos.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_COS_H 20 | #define TCBASIC_COS_H 21 | 22 | struct number; 23 | struct tokenizer; 24 | 25 | struct cos { 26 | struct expression *e; 27 | }; 28 | 29 | struct cos *new_cos(struct expression *e); 30 | struct cos *parse_cos(struct tokenizer *t); 31 | struct number *eval_cos(struct cos *c); 32 | void print_cos(struct cos *c); 33 | void free_cos(struct cos *c); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /include/cot.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_COT_H 20 | #define TCBASIC_COT_H 21 | 22 | struct number; 23 | struct tokenizer; 24 | 25 | struct cot { 26 | struct expression *e; 27 | }; 28 | 29 | struct cot *new_cot(struct expression *e); 30 | struct cot *parse_cot(struct tokenizer *t); 31 | struct number *eval_cot(struct cot *c); 32 | void print_cot(struct cot *c); 33 | void free_cot(struct cot *c); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /include/eval.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_EVAL_H 20 | #define TCBASIC_EVAL_H 21 | 22 | void eval(char *s); 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /include/exp.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_EXP_H 20 | #define TCBASIC_EXP_H 21 | 22 | struct number; 23 | struct tokenizer; 24 | 25 | struct exp { 26 | struct expression *e; 27 | }; 28 | 29 | struct exp *new_exp(struct expression *e); 30 | struct exp *parse_exp(struct tokenizer *t); 31 | struct number *eval_exp(struct exp *l); 32 | void print_exp(struct exp *l); 33 | void free_exp(struct exp *l); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /include/expr_item.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_EXPR_ITEM_H 20 | #define TCBASIC_EXPR_ITEM_H 21 | 22 | struct expression; 23 | struct str; 24 | struct tokenizer; 25 | 26 | struct expr_item { 27 | struct expression *e; 28 | struct str *str; 29 | }; 30 | 31 | struct expr_item *new_expr_item(struct expression *e, struct str *str); 32 | struct expr_item *parse_expr_item(struct tokenizer *t); 33 | void eval_expr_item(struct expr_item *ei); 34 | void print_expr_item(struct expr_item *ei); 35 | void free_expr_item(struct expr_item *ei); 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /include/expr_list.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_EXPR_LIST_H 20 | #define TCBASIC_EXPR_LIST_H 21 | 22 | struct expr_item; 23 | struct tokenizer; 24 | 25 | struct expr_list { 26 | struct expr_item *expr_item; 27 | struct expr_list *list; 28 | }; 29 | 30 | struct expr_list *new_expr_list(struct expr_item *expr_item, struct expr_list *list); 31 | struct expr_list *parse_expr_list(struct tokenizer *t); 32 | void eval_expr_list(struct expr_list *el); 33 | void print_expr_list(struct expr_list *el); 34 | void free_expr_list(struct expr_list *el); 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /include/expression.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_EXPRESSION_H 20 | #define TCBASIC_EXPRESSION_H 21 | 22 | struct addop; 23 | struct number; 24 | struct term; 25 | struct tokenizer; 26 | 27 | struct expression { 28 | struct addop *term1_op; 29 | struct term *term1; 30 | struct addop *term2_op; 31 | struct term *term2; 32 | }; 33 | 34 | struct expression *new_expression(struct addop *term1_op, struct term *term1, struct addop *term2_op, struct term *term2); 35 | struct expression *parse_expression(struct tokenizer *t); 36 | struct number *eval_expression(struct expression *e); 37 | void print_expression(struct expression *e); 38 | void free_expression(struct expression *e); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /include/factor.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_FACTOR_H 20 | #define TCBASIC_FACTOR_H 21 | 22 | struct tokenizer; 23 | struct primary; 24 | struct number; 25 | 26 | struct factor { 27 | struct primary *p; 28 | struct factor *f; 29 | }; 30 | 31 | struct factor *new_factor(struct primary *p, struct factor *f); 32 | struct factor *parse_factor(struct tokenizer *t); 33 | struct number *eval_factor(struct factor *f); 34 | void print_factor(struct factor *f); 35 | void free_factor(struct factor *f); 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /include/int_.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_INT__H 20 | #define TCBASIC_INT__H 21 | 22 | struct number; 23 | struct tokenizer; 24 | 25 | struct int_ { 26 | struct expression *e; 27 | }; 28 | 29 | struct int_ *new_int(struct expression *e); 30 | struct int_ *parse_int(struct tokenizer *t); 31 | struct number *eval_int(struct int_ *i); 32 | void print_int(struct int_ *i); 33 | void free_int(struct int_ *i); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /include/line.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_LINE_H 20 | #define TCBASIC_LINE_H 21 | 22 | struct tokenizer; 23 | struct statement; 24 | struct number; 25 | 26 | struct line { 27 | struct statement *statement; 28 | int number; 29 | struct line *next; 30 | }; 31 | 32 | struct line *new_line(struct statement *statement, struct number *number); 33 | void parse_line(struct tokenizer *t); 34 | int eval_line(struct line *l); 35 | void print_line(struct line *l); 36 | void print_lines(struct line *l); 37 | void free_line(struct line *l); 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /include/log.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_LOG_H 20 | #define TCBASIC_LOG_H 21 | 22 | struct number; 23 | struct tokenizer; 24 | 25 | struct log { 26 | struct expression *e; 27 | }; 28 | 29 | struct log *new_log(struct expression *e); 30 | struct log *parse_log(struct tokenizer *t); 31 | struct number *eval_log(struct log *l); 32 | void print_log(struct log *l); 33 | void free_log(struct log *l); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /include/mulop.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_MULOP_H 20 | #define TCBASIC_MULOP_H 21 | 22 | struct mulop { 23 | int type; 24 | }; 25 | 26 | struct mulop *new_mulop(int type); 27 | struct mulop *parse_mulop(struct tokenizer *t); 28 | void print_mulop(struct mulop *op); 29 | void free_mulop(struct mulop *op); 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /include/number.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_NUMBER_H 20 | #define TCBASIC_NUMBER_H 21 | 22 | struct tokenizer; 23 | 24 | struct number { 25 | enum number_type { 26 | INT, 27 | FLOAT 28 | } type; 29 | union number_value { 30 | int ival; 31 | float fval; 32 | } value; 33 | }; 34 | 35 | #define INT_VALUE(n) (n->type == INT ? n->value.ival : (int)n->value.fval) 36 | #define FLOAT_VALUE(n) (n->type == FLOAT ? n->value.fval : (float) n->value.ival) 37 | 38 | struct number *new_number(char *s); 39 | struct number *new_number_from_int(int i); 40 | struct number *new_number_from_float(float f); 41 | struct number *parse_number(struct tokenizer *t); 42 | struct number *clone_number(struct number *n); 43 | struct number *add_number(struct number *x, struct number *y); 44 | struct number *subtract_number(struct number *x, struct number *y); 45 | struct number *multiply_number(struct number *x, struct number *y); 46 | struct number *divide_number(struct number *x, struct number *y); 47 | struct number *idivide_number(struct number *x, struct number *y); 48 | struct number *modulus_number(struct number *x, struct number *y); 49 | struct number *pow_number(struct number *x, struct number *y); 50 | void print_number(struct number *n); 51 | void free_number(struct number *n); 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /include/pi.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_PI_H 20 | #define TCBASIC_PI_H 21 | 22 | struct number; 23 | struct tokenizer; 24 | 25 | struct pi { 26 | char xxx; 27 | }; 28 | 29 | struct pi *new_pi(void); 30 | struct pi *parse_pi(struct tokenizer *t); 31 | struct number *eval_pi(void); 32 | void print_pi(struct pi *r); 33 | void free_pi(struct pi *r); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /include/primary.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_PRIMARY_H 20 | #define TCBASIC_PRIMARY_H 21 | 22 | struct expression; 23 | struct number; 24 | struct rnd; 25 | struct time; 26 | struct var; 27 | struct sin; 28 | struct cos; 29 | struct tan; 30 | struct cot; 31 | struct atn; 32 | struct exp; 33 | struct log; 34 | struct abs; 35 | struct sgn; 36 | struct sqr; 37 | struct int_; 38 | struct pi; 39 | 40 | struct primary { 41 | int type; 42 | union primary_union { 43 | struct expression *e; 44 | struct number *n; 45 | struct rnd *r; 46 | struct time *time; 47 | struct sin *sin; 48 | struct cos *cos; 49 | struct tan *tan; 50 | struct cot *cot; 51 | struct atn *atn; 52 | struct exp *exp; 53 | struct log *log; 54 | struct abs *abs; 55 | struct sgn *sgn; 56 | struct sqr *sqr; 57 | struct int_ *int_; 58 | struct var *v; 59 | struct pi *pi; 60 | } u; 61 | }; 62 | 63 | struct primary *new_primary(int type, void *value); 64 | struct primary *parse_primary(struct tokenizer *t); 65 | struct number *eval_primary(struct primary *f); 66 | void print_primary(struct primary *f); 67 | void free_primary(struct primary *f); 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /include/prng.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_PRNG_H 20 | #define TCBASIC_PRNG_H 21 | 22 | void tcb_randomize(void); 23 | void tcb_srand(unsigned long seed); 24 | float tcb_rand(void); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /include/readaline.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_READALINE_H 20 | #define TCBASIC_READALINE_H 21 | 22 | #include 23 | 24 | #include "buffer.h" 25 | 26 | /* prints the prompt on the terminal only if standard input is a terminal */ 27 | Buffer *readaline(FILE *fd, const char *prompt, Buffer *buf); 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /include/relop.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_RELOP_H 20 | #define TCBASIC_RELOP_H 21 | 22 | struct relop { 23 | int type; 24 | }; 25 | 26 | struct relop *new_relop(int type); 27 | struct relop *parse_relop(struct tokenizer *t); 28 | void print_relop(struct relop *op); 29 | void free_relop(struct relop *op); 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /include/rem.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_REM_H 20 | #define TCBASIC_REM_H 21 | 22 | struct tokenizer; 23 | 24 | struct rem { 25 | char *value; 26 | }; 27 | 28 | struct rem *new_rem(char *value); 29 | struct rem *parse_rem(struct tokenizer *t); 30 | void print_rem(struct rem *r); 31 | void free_rem(struct rem *r); 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /include/rnd.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_RND_H 20 | #define TCBASIC_RND_H 21 | 22 | struct number; 23 | struct tokenizer; 24 | 25 | struct rnd { 26 | char xxx; 27 | }; 28 | 29 | struct rnd *new_rnd(void); 30 | struct rnd *parse_rnd(struct tokenizer *t); 31 | struct number *eval_rnd(void); 32 | void print_rnd(struct rnd *r); 33 | void free_rnd(struct rnd *r); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /include/runtime.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_RUNTIME_H 20 | #define TCBASIC_RUNTIME_H 21 | 22 | struct number; 23 | struct line; 24 | 25 | struct for_state { 26 | struct number *limit; 27 | struct number *step; 28 | int target; 29 | }; 30 | 31 | struct line *runtime_get_first_line(void); 32 | struct line *runtime_get_line(int number); 33 | void runtime_set_line(struct line *item); 34 | void runtime_rm_line(int number); 35 | int runtime_get_line_after_nearest_next(int for_line_number, char var); 36 | 37 | void runtime_set_for_state(char v, struct number *limit, struct number *step, int target); 38 | struct for_state *runtime_get_for_state(char v); 39 | 40 | void runtime_reset(void); 41 | int runtime_continue(void); 42 | void runtime_stop(void); 43 | 44 | void runtime_trace_on(void); 45 | void runtime_trace_off(void); 46 | int runtime_is_tracing(void); 47 | 48 | void runtime_callstack_push(int number); 49 | int runtime_callstack_pop(void); 50 | 51 | void runtime_set_var(char var, struct number *value); 52 | struct number *runtime_get_var(char var); 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /include/sgn.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_SGN_H 20 | #define TCBASIC_SGN_H 21 | 22 | struct number; 23 | struct tokenizer; 24 | 25 | struct sgn { 26 | struct expression *e; 27 | }; 28 | 29 | struct sgn *new_sgn(struct expression *e); 30 | struct sgn *parse_sgn(struct tokenizer *t); 31 | struct number *eval_sgn(struct sgn *a); 32 | void print_sgn(struct sgn *a); 33 | void free_sgn(struct sgn *a); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /include/shell.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_SHELL_H 20 | #define TCBASIC_SHELL_H 21 | 22 | int doshell(char *cmd); 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /include/sin.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_SIN_H 20 | #define TCBASIC_SIN_H 21 | 22 | struct number; 23 | struct tokenizer; 24 | 25 | struct sin { 26 | struct expression *e; 27 | }; 28 | 29 | struct sin *new_sin(struct expression *e); 30 | struct sin *parse_sin(struct tokenizer *t); 31 | struct number *eval_sin(struct sin *a); 32 | void print_sin(struct sin *a); 33 | void free_sin(struct sin *a); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /include/sqr.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_SQR_H 20 | #define TCBASIC_SQR_H 21 | 22 | struct number; 23 | struct tokenizer; 24 | 25 | struct sqr { 26 | struct expression *e; 27 | }; 28 | 29 | struct sqr *new_sqr(struct expression *e); 30 | struct sqr *parse_sqr(struct tokenizer *t); 31 | struct number *eval_sqr(struct sqr *a); 32 | void print_sqr(struct sqr *a); 33 | void free_sqr(struct sqr *a); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /include/statement.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_STATEMENT_H 20 | #define TCBASIC_STATEMENT_H 21 | 22 | struct expr_list; 23 | struct expression; 24 | struct statement; 25 | struct relop; 26 | struct rem; 27 | 28 | struct statement { 29 | int type; 30 | 31 | union statements { 32 | struct print_statement { 33 | struct expr_list *expr_list; 34 | } print_stmt; 35 | struct if_statement { 36 | struct expression *left; 37 | struct relop *relop; 38 | struct expression *right; 39 | struct statement *statement; 40 | } if_stmt; 41 | struct shell_statement { 42 | struct str *str; 43 | } shell_stmt; 44 | struct goto_statement { 45 | struct expression *expression; 46 | } goto_stmt; 47 | struct input_statement { 48 | struct var_list *var_list; 49 | } input_stmt; 50 | struct let_statement { 51 | struct var *var; 52 | struct expression *expression; 53 | } let_stmt; 54 | struct gosub_statement { 55 | struct expression *expression; 56 | } gosub_stmt; 57 | struct for_statement { 58 | struct var *var; 59 | struct expression *initial; 60 | struct expression *limit; 61 | struct expression *step; 62 | } for_stmt; 63 | struct next_statement { 64 | struct var *var; 65 | } next_stmt; 66 | struct rem_statement { 67 | struct rem *rem; 68 | } rem_stmt; 69 | } u; 70 | }; 71 | 72 | struct statement *new_statement(int type, void *arg1, void *arg2, void *arg3, void *arg4); 73 | struct statement *parse_statement(struct tokenizer *t); 74 | void print_statement(struct statement *s); 75 | int eval_statement(struct statement *s, int number, int next_number); 76 | void free_statement(struct statement *s); 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /include/str.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_STR_H 20 | #define TCBASIC_STR_H 21 | 22 | struct tokenizer; 23 | 24 | struct str { 25 | char *value; 26 | }; 27 | 28 | struct str *new_str(char *value); 29 | struct str *parse_str(struct tokenizer *t); 30 | char *eval_str(struct str *s); 31 | void print_str(struct str *s); 32 | void free_str(struct str *s); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /include/tan.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_TAN_H 20 | #define TCBASIC_TAN_H 21 | 22 | struct number; 23 | struct tokenizer; 24 | 25 | struct tan { 26 | struct expression *e; 27 | }; 28 | 29 | struct tan *new_tan(struct expression *e); 30 | struct tan *parse_tan(struct tokenizer *t); 31 | struct number *eval_tan(struct tan *a); 32 | void print_tan(struct tan *a); 33 | void free_tan(struct tan *a); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /include/term.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_TERM_H 20 | #define TCBASIC_TERM_H 21 | 22 | struct factor; 23 | struct mulop; 24 | 25 | struct term { 26 | struct factor *left; 27 | struct mulop *op; 28 | struct factor *right; 29 | }; 30 | 31 | struct term *new_term(struct factor *left, struct mulop *op, struct factor *right); 32 | struct term *parse_term(struct tokenizer *t); 33 | struct number *eval_term(struct term *op); 34 | void print_term(struct term *op); 35 | void free_term(struct term *op); 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /include/time_.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_TIME_H 20 | #define TCBASIC_TIME_H 21 | 22 | struct number; 23 | struct tokenizer; 24 | 25 | struct time { 26 | char xxx; 27 | }; 28 | 29 | struct time *new_time(void); 30 | struct time *parse_time(struct tokenizer *t); 31 | struct number *eval_time(void); 32 | void print_time(struct time *t); 33 | void free_time(struct time *t); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /include/tokenizer.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_TOKENIZER_H 20 | #define TCBASIC_TOKENIZER_H 21 | 22 | enum token_types { 23 | PRINT, IF, THEN, GOTO, INPUT, LET, GOSUB, RETURN, END, REM, RANDOMIZE, 24 | CLEAR, LIST, RENUM, RUN, STOP, TROFF, TRON, CLS, SHELL, BEEP, 25 | RND, TIME, FOR, TO, STEP, NEXT, 26 | SIN, COS, TAN, COT, ATN, EXP, LOG, ABS, SGN, SQR, INT_, 27 | LTEQ, LTGT, LT, GTEQ, GTLT, GT, EQ, 28 | PLUS, MINUS, TIMES, DIVIDE, IDIVIDE, MOD, 29 | CIRCUMFLEX, COMMA, OPAREN, CPAREN, 30 | STR, VAR, NUMBER, PI, 31 | SPACE, INVALID, EOS 32 | }; 33 | 34 | enum lhs { 35 | EXPRESSION 36 | }; 37 | 38 | struct token { 39 | enum token_types type; 40 | char *text; 41 | }; 42 | 43 | struct tokenizer { 44 | char **s; 45 | struct token token; 46 | }; 47 | 48 | void token_get(struct tokenizer *t); 49 | void token_unget(struct tokenizer *t); 50 | 51 | void tokenizer_init(void); 52 | void tokenizer_exit(void); 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /include/var.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_VAR_H 20 | #define TCBASIC_VAR_H 21 | 22 | struct number; 23 | struct tokenizer; 24 | 25 | struct var { 26 | char value; 27 | }; 28 | 29 | struct var *new_var(char value); 30 | struct var *parse_var(struct tokenizer *t); 31 | struct number *eval_var(struct var *v); 32 | void print_var(struct var *v); 33 | void free_var(struct var *v); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /include/var_list.h: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #ifndef TCBASIC_VAR_LIST_H 20 | #define TCBASIC_VAR_LIST_H 21 | 22 | struct var; 23 | 24 | struct var_list { 25 | struct var *var; 26 | struct var_list *list; 27 | }; 28 | 29 | struct var_list *new_var_list(struct var *var, struct var_list *list); 30 | struct var_list *parse_var_list(struct tokenizer *t); 31 | void eval_var_list(struct var_list *vl, char *line); 32 | void print_var_list(struct var_list *vl); 33 | void free_var_list(struct var_list *vl); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /man/tcbasic.1.in: -------------------------------------------------------------------------------- 1 | .\" tcbasic - a small BASIC Interpreter written in C. 2 | .\" Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 3 | .\" 4 | .\" This program is free software: you can redistribute it and/or modify 5 | .\" it under the terms of the GNU General Public License as published by 6 | .\" the Free Software Foundation, either version 3 of the License, or 7 | .\" (at your option) any later version. 8 | .\" 9 | .\" This program is distributed in the hope that it will be useful, 10 | .\" but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | .\" GNU General Public License for more details. 13 | .\" 14 | .\" You should have received a copy of the GNU General Public License 15 | .\" along with this program. If not, see . 16 | .TH TCBASIC "1" "June 2018" "@PROJECT_NAME@ @PROJECT_VERSION@" "User Commands" 17 | .SH NAME 18 | tcbasic \- a small BASIC Interpreter written in C 19 | .SH SYNOPSIS 20 | .B tcbasic 21 | [\fIfilename\fR] 22 | .SH DESCRIPTION 23 | tcbasic implements a small subset of BASIC in portable C. If the user specifies 24 | a filename on the command line or pipes data to tcbasic, the results will be 25 | written to standard out. If no file is specified, an interactive mode is 26 | started where a user can interact with the BASIC system directly. 27 | .SH OPTIONS 28 | .TP 29 | \fB\-h\fR, \-? \fB\-\-help\fR 30 | Print a helpful message and exit 31 | .TP 32 | \fB\-v\fR \fB\-\-version\fR 33 | Print version information and exit 34 | .SH STATEMENTS 35 | .TP 36 | \fBREM remark\fR 37 | Remark has no effect on the execution of the program 38 | and acts as a comment to the developer. The remark can contain 39 | any character. 40 | .TP 41 | \fBPRINT list\fR 42 | Prints the contents of 'list' to the console where 'list' is a 43 | comma separated list of one or more quoted strings, expressions, 44 | and/or variables. 45 | .TP 46 | \fBIF expression relop expression THEN statement\fR 47 | Evaluates both 'expression's and compares them using relational 48 | operator 'relop'. If the relation is true, then the statement 49 | will be executed. Otherwise, the statement is skipped. 50 | .TP 51 | \fBGOTO expression\fR 52 | Evaluates 'expression' and jumps to the corresponding line number. 53 | .TP 54 | \fBINPUT var_list\fR 55 | Given a comma separated list of 1 or more variables, this command 56 | will prompt the user to enter a comma separated list of expressions. 57 | The value of each expression will be assigned to each corresponding 58 | variable. 59 | .TP 60 | \fBGOSUB expression\fR 61 | Evaluates 'expression' and jumps to the corresponding line number 62 | after saving the current line number. 63 | .TP 64 | \fBRETURN\fR 65 | Returns control to the line after the last 'GOSUB' call. 66 | .TP 67 | \fBLET var = expression\fR 68 | Assigns the value of expression to variable 'var' where 'var' is 69 | a single character variable name in the range from A to Z. 70 | .TP 71 | \fBEND\fR 72 | Ends the execution of the program. 73 | .TP 74 | \fBSTOP\fR 75 | Exits the interpreter. 76 | .TP 77 | \fBBEEP\fR 78 | System beep. 79 | .TP 80 | \fBSHELL cmd\fR 81 | Executes a shell command. 82 | .TP 83 | \fBRANDOMIZE\fR 84 | Re-seeds the random number generator, causing RND to return a different 85 | sequence of random numbers. 86 | \fBCLS\fR 87 | Clears the screen. 88 | .SH FUNCTIONS 89 | .TP 90 | \fBRND\fR 91 | Returns a random number in the range [0,1). The same sequence of numbers is 92 | returned in each program run. Use the RANDOMIZE statement to generate 93 | different sequences in each program run. 94 | .TP 95 | \fBTIME\fR 96 | Returns the number of seconds since midnight. 97 | .TP 98 | \fBSIN (expression)\fR 99 | Returns the sine of the given expression (measured in radians). 100 | .TP 101 | \fBCOS (expression)\fR 102 | Returns the cosine of the given expression (measured in radians). 103 | .TP 104 | \fBTAN (expression)\fR 105 | Returns the tangent of the given expression (measured in radians). 106 | .TP 107 | \fBCOT (expression)\fR 108 | Returns the cotangent of the given expression (measured in radians). 109 | .TP 110 | \fBATN (expression)\fR 111 | Returns the arctangent of the given expression (measured in radians). 112 | .TP 113 | \fBEXP (expression)\fR 114 | Returns e to the power of the given expression. 115 | .TP 116 | \fBLOG (expression)\fR 117 | Returns the natural logarithm of of the given expression. 118 | .TP 119 | \fBABS (expression)\fR 120 | Returns the absolute value of the given expression. 121 | .TP 122 | \fBINT (expression)\fR 123 | Returns the integer portion of the given expression. 124 | .TP 125 | \fBSGN (expression)\fR 126 | Returns the sign of the given expression. 1, 0, or -1 for positive, zero, or negative. 127 | .TP 128 | \fBSQR (expression)\fR 129 | Returns the square root of the given expression. 130 | .SH COMMANDS 131 | .TP 132 | \fBCLEAR\fR 133 | Clears the program from memory and sets all variables to 0. 134 | .TP 135 | \fBLIST\fR 136 | Prints the current program. 137 | .TP 138 | \fBRENUM\fR 139 | Renumber lines in memory. 140 | .TP 141 | \fBRUN\fR 142 | Executes the current program. 143 | .TP 144 | \fBTROFF\fR 145 | Turns off debug tracing. 146 | .TP 147 | \fBTRON\fR 148 | Turns on debug tracing. 149 | .SH AUTHORS 150 | See https://github.com/tcort/tcbasic/graphs/contributors 151 | .SH "REPORTING BUGS" 152 | See https://github.com/tcort/tcbasic/issues 153 | .SH COPYRIGHT 154 | Copyright \(co 2015, 2016, 2017, 2018, 2020 Thomas Cort 155 | .br 156 | This is free software; see the source for copying conditions. There is NO 157 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 158 | -------------------------------------------------------------------------------- /src/abs.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "tokenizer.h" 28 | 29 | #include "abs.h" 30 | #include "expression.h" 31 | #include "number.h" 32 | 33 | struct abs *new_abs(struct expression *e) { 34 | 35 | struct abs *a; 36 | 37 | a = (struct abs *) malloc(sizeof(struct abs)); 38 | if (a == NULL) { 39 | perror("malloc"); 40 | exit(EXIT_FAILURE); 41 | } 42 | memset(a, '\0', sizeof(struct abs)); 43 | 44 | a->e = e; 45 | 46 | return a; 47 | } 48 | 49 | struct abs *parse_abs(struct tokenizer *t) { 50 | 51 | struct expression *e; 52 | 53 | token_get(t); 54 | if (t->token.type != ABS) { 55 | token_unget(t); 56 | return NULL; 57 | } 58 | 59 | token_get(t); 60 | if (t->token.type != OPAREN) { 61 | token_unget(t); 62 | return NULL; 63 | } 64 | 65 | e = parse_expression(t); 66 | if (e == NULL) { 67 | return NULL; 68 | } 69 | 70 | token_get(t); 71 | if (t->token.type != CPAREN) { 72 | token_unget(t); 73 | free_expression(e); 74 | return NULL; 75 | } 76 | 77 | return new_abs(e); 78 | } 79 | 80 | struct number *eval_abs(struct abs *a) { 81 | struct number *n; 82 | 83 | n = eval_expression(a->e); 84 | if (n->type == INT) { 85 | n->value.ival = abs(n->value.ival); 86 | } else { /* float */ 87 | n->value.fval = fabsf(n->value.fval); 88 | } 89 | 90 | return n; 91 | } 92 | 93 | void print_abs(struct abs *a) { 94 | if (a == NULL) { 95 | return; 96 | } 97 | 98 | printf("ABS ("); 99 | print_expression(a->e); 100 | printf(")"); 101 | } 102 | 103 | void free_abs(struct abs *a) { 104 | 105 | if (a != NULL) { 106 | if (a->e != NULL) { 107 | free_expression(a->e); 108 | a->e = NULL; 109 | } 110 | free(a); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/addop.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "addop.h" 27 | #include "tokenizer.h" 28 | 29 | struct addop *new_addop(int type) { 30 | 31 | struct addop *op; 32 | 33 | op = (struct addop *) malloc(sizeof(struct addop)); 34 | if (op == NULL) { 35 | perror("malloc"); 36 | exit(EXIT_FAILURE); 37 | } 38 | memset(op, '\0', sizeof(struct addop)); 39 | 40 | op->type = type; 41 | 42 | return op; 43 | } 44 | 45 | struct addop *parse_addop(struct tokenizer *t) { 46 | 47 | token_get(t); 48 | switch (t->token.type) { 49 | case PLUS: 50 | return new_addop(PLUS); 51 | case MINUS: 52 | return new_addop(MINUS); 53 | default: 54 | token_unget(t); 55 | return NULL; 56 | } 57 | } 58 | 59 | int eval_addop(struct addop *op) { 60 | 61 | if (op == NULL) { 62 | return 1; 63 | } 64 | 65 | return (op->type == PLUS) ? 1 : -1; 66 | } 67 | 68 | void print_addop(struct addop *op) { 69 | 70 | if (op == NULL) { 71 | return; 72 | } 73 | 74 | switch (op->type) { 75 | case PLUS: 76 | printf("+"); 77 | break; 78 | case MINUS: 79 | printf("-"); 80 | break; 81 | default: 82 | printf("?"); 83 | break; 84 | } 85 | } 86 | 87 | void free_addop(struct addop *op) { 88 | if (op != NULL) { 89 | free(op); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/atn.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "tokenizer.h" 28 | 29 | #include "atn.h" 30 | #include "expression.h" 31 | #include "number.h" 32 | 33 | struct atn *new_atn(struct expression *e) { 34 | 35 | struct atn *a; 36 | 37 | a = (struct atn *) malloc(sizeof(struct atn)); 38 | if (a == NULL) { 39 | perror("malloc"); 40 | exit(EXIT_FAILURE); 41 | } 42 | memset(a, '\0', sizeof(struct atn)); 43 | 44 | a->e = e; 45 | 46 | return a; 47 | } 48 | 49 | struct atn *parse_atn(struct tokenizer *t) { 50 | 51 | struct expression *e; 52 | 53 | token_get(t); 54 | if (t->token.type != ATN) { 55 | token_unget(t); 56 | return NULL; 57 | } 58 | 59 | token_get(t); 60 | if (t->token.type != OPAREN) { 61 | token_unget(t); 62 | return NULL; 63 | } 64 | 65 | e = parse_expression(t); 66 | if (e == NULL) { 67 | return NULL; 68 | } 69 | 70 | token_get(t); 71 | if (t->token.type != CPAREN) { 72 | token_unget(t); 73 | free_expression(e); 74 | return NULL; 75 | } 76 | 77 | return new_atn(e); 78 | } 79 | 80 | struct number *eval_atn(struct atn *a) { 81 | struct number *n; 82 | 83 | n = eval_expression(a->e); 84 | if (n->type == INT) { 85 | float f; 86 | f = atanf((1.0f) * n->value.ival); 87 | n->type = FLOAT; 88 | n->value.fval = f; 89 | } else { /* float */ 90 | n->value.fval = atanf(n->value.fval); 91 | } 92 | 93 | return n; 94 | } 95 | 96 | void print_atn(struct atn *a) { 97 | if (a == NULL) { 98 | return; 99 | } 100 | 101 | printf("ATN ("); 102 | print_expression(a->e); 103 | printf(")"); 104 | } 105 | 106 | void free_atn(struct atn *a) { 107 | 108 | if (a != NULL) { 109 | if (a->e != NULL) { 110 | free_expression(a->e); 111 | a->e = NULL; 112 | } 113 | free(a); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/buffer.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "buffer.h" 27 | 28 | /* 29 | * allocates a new Buffer structure 30 | * 31 | * size is the total size of the space allocated by malloc/realloc. 32 | * incr is the amount to add to size when the buffer needs to grow. 33 | */ 34 | Buffer *bf_alloc(size_t size, size_t incr) { 35 | 36 | Buffer *buffer; 37 | 38 | /* sanity check */ 39 | if (size < 1 || incr < 1) { 40 | fprintf(stderr, "bf_alloc: Invalid Arguments"); 41 | exit(EXIT_FAILURE); 42 | } 43 | 44 | /* allocate a new Buffer structure */ 45 | buffer = (Buffer *) malloc(sizeof(Buffer)); 46 | if (buffer == NULL) { 47 | perror("bf_alloc"); 48 | exit(EXIT_FAILURE); 49 | } 50 | 51 | /* give the internal buffer the given initial "size" using 52 | malloc() */ 53 | buffer->buf = (char *) malloc(size); 54 | if (buffer->buf == NULL) { 55 | perror("bf_alloc"); 56 | free(buffer); 57 | exit(EXIT_FAILURE); 58 | } 59 | 60 | /* copy the given "size" into maxsize */ 61 | buffer->maxsize = size; 62 | 63 | /* saves the value of "incr" in the buffer structure for 64 | later use by bf_addch() */ 65 | buffer->incr = incr; 66 | 67 | buffer->cursize = 0; 68 | 69 | /* return a pointer to the buffer structure on success */ 70 | return buffer; 71 | } 72 | 73 | /* adds the character ch to the end of the given Buffer */ 74 | void bf_addch(Buffer *buf, char ch) { 75 | 76 | bf_valid(buf); /* check for valid Buffer */ 77 | 78 | /* if the buffer is full */ 79 | if (buf->cursize == buf->maxsize) { 80 | 81 | size_t newmaxsize = buf->maxsize + buf->incr; 82 | 83 | /* check if increasing maxsize by incr would cause an overflow */ 84 | if (newmaxsize < buf->maxsize) { 85 | errno = EOVERFLOW; 86 | perror("bf_addch"); 87 | exit(EXIT_FAILURE); 88 | } 89 | 90 | /* add incr bytes to maxsize and use realloc() to make 91 | the buffer larger before adding the character */ 92 | buf->buf = (char *) realloc(buf->buf, newmaxsize); 93 | if (buf->buf == NULL) { 94 | perror("realloc"); 95 | exit(EXIT_FAILURE); 96 | } 97 | 98 | buf->maxsize = newmaxsize; 99 | } 100 | 101 | buf->buf[buf->cursize] = ch; 102 | 103 | /* increments cursize by one to count the character added */ 104 | buf->cursize++; 105 | } 106 | 107 | /* re-initializes the given Buffer, such that the next call to 108 | bf_addch will put the character at the start of the buffer */ 109 | void bf_clear(Buffer *buf) { 110 | 111 | bf_valid(buf); /* check for valid Buffer */ 112 | 113 | /* does not alter maxsize, buf, or incr */ 114 | buf->cursize = 0; 115 | /* does not need to overwrite the existing contents */ 116 | } 117 | 118 | /* 119 | * tests that the given pointer is a valid Buffer 120 | * 121 | * buf is a pointer to the Buffer to be tested 122 | */ 123 | void bf_valid(Buffer *buf) { 124 | 125 | /* are all Buffer values consistent with each other? */ 126 | if (buf == NULL || buf->buf == NULL || buf->cursize > buf->maxsize || 127 | buf->maxsize < 1 || buf->incr < 1) { 128 | /* invalid buffer */ 129 | exit(EXIT_FAILURE); 130 | } 131 | } 132 | 133 | /* 134 | * de-allocates the Buffer and any memory it may contain 135 | * 136 | * buf is a pointer to a Buffer that needs to be free()'d 137 | */ 138 | void bf_free(Buffer *buf) { 139 | 140 | if (buf != NULL) { 141 | 142 | if (buf->buf != NULL) { 143 | free(buf->buf); 144 | } 145 | 146 | free(buf); 147 | } 148 | } 149 | 150 | -------------------------------------------------------------------------------- /src/command.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "runtime.h" 27 | 28 | #include "command.h" 29 | #include "line.h" 30 | #include "tokenizer.h" 31 | 32 | struct command *new_command(int type) { 33 | 34 | struct command *cmd; 35 | 36 | cmd = (struct command *) malloc(sizeof(struct command)); 37 | if (cmd == NULL) { 38 | perror("malloc"); 39 | exit(EXIT_FAILURE); 40 | } 41 | memset(cmd, '\0', sizeof(struct command)); 42 | 43 | cmd->type = type; 44 | 45 | return cmd; 46 | } 47 | 48 | struct command *parse_command(struct tokenizer *t) { 49 | 50 | token_get(t); 51 | switch (t->token.type) { 52 | case RENUM: 53 | return new_command(RENUM); 54 | case RUN: 55 | return new_command(RUN); 56 | case TROFF: 57 | return new_command(TROFF); 58 | case TRON: 59 | return new_command(TRON); 60 | case LIST: 61 | return new_command(LIST); 62 | case CLEAR: 63 | return new_command(CLEAR); 64 | default: 65 | token_unget(t); 66 | return NULL; 67 | } 68 | } 69 | 70 | void exec_command(struct command *cmd) { 71 | 72 | struct line *cur; 73 | int n; 74 | 75 | if (cmd == NULL) { 76 | return; 77 | } 78 | 79 | switch (cmd->type) { 80 | case RENUM: 81 | for (cur = runtime_get_first_line(), n = 10; cur != NULL; cur = cur->next, n += 10) { 82 | cur->number = n; 83 | } 84 | break; 85 | case CLEAR: 86 | runtime_reset(); 87 | break; 88 | case LIST: 89 | print_lines(runtime_get_first_line()); 90 | break; 91 | case RUN: 92 | cur = runtime_get_first_line(); 93 | while (cur != NULL) { 94 | int r; 95 | r = eval_line(cur); 96 | if (r == -1) { 97 | cur = cur->next; 98 | } else if (r == -2) { 99 | break; 100 | } else { 101 | cur = runtime_get_line(r); 102 | } 103 | } 104 | break; 105 | case TROFF: 106 | runtime_trace_off(); 107 | break; 108 | case TRON: 109 | runtime_trace_on(); 110 | break; 111 | } 112 | } 113 | 114 | void free_command(struct command *cmd) { 115 | if (cmd != NULL) { 116 | free(cmd); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/cos.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "tokenizer.h" 28 | 29 | #include "cos.h" 30 | #include "expression.h" 31 | #include "number.h" 32 | 33 | struct cos *new_cos(struct expression *e) { 34 | 35 | struct cos *s; 36 | 37 | s = (struct cos *) malloc(sizeof(struct cos)); 38 | if (s == NULL) { 39 | perror("malloc"); 40 | exit(EXIT_FAILURE); 41 | } 42 | memset(s, '\0', sizeof(struct cos)); 43 | 44 | s->e = e; 45 | 46 | return s; 47 | } 48 | 49 | struct cos *parse_cos(struct tokenizer *t) { 50 | 51 | struct expression *e; 52 | 53 | token_get(t); 54 | if (t->token.type != COS) { 55 | token_unget(t); 56 | return NULL; 57 | } 58 | 59 | token_get(t); 60 | if (t->token.type != OPAREN) { 61 | token_unget(t); 62 | return NULL; 63 | } 64 | 65 | e = parse_expression(t); 66 | if (e == NULL) { 67 | return NULL; 68 | } 69 | 70 | token_get(t); 71 | if (t->token.type != CPAREN) { 72 | token_unget(t); 73 | free_expression(e); 74 | return NULL; 75 | } 76 | 77 | return new_cos(e); 78 | } 79 | 80 | struct number *eval_cos(struct cos *c) { 81 | struct number *n; 82 | 83 | n = eval_expression(c->e); 84 | if (n->type == INT) { 85 | float f; 86 | f = cosf((1.0f) * n->value.ival); 87 | n->type = FLOAT; 88 | n->value.fval = f; 89 | } else { /* float */ 90 | n->value.fval = cosf(n->value.fval); 91 | } 92 | 93 | return n; 94 | } 95 | 96 | void print_cos(struct cos *c) { 97 | if (c == NULL) { 98 | return; 99 | } 100 | 101 | printf("COS ("); 102 | print_expression(c->e); 103 | printf(")"); 104 | } 105 | 106 | void free_cos(struct cos *c) { 107 | 108 | if (c != NULL) { 109 | if (c->e != NULL) { 110 | free_expression(c->e); 111 | c->e = NULL; 112 | } 113 | free(c); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/cot.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "tokenizer.h" 28 | 29 | #include "cot.h" 30 | #include "expression.h" 31 | #include "number.h" 32 | 33 | struct cot *new_cot(struct expression *e) { 34 | 35 | struct cot *c; 36 | 37 | c = (struct cot *) malloc(sizeof(struct cot)); 38 | if (c == NULL) { 39 | perror("malloc"); 40 | exit(EXIT_FAILURE); 41 | } 42 | memset(c, '\0', sizeof(struct cot)); 43 | 44 | c->e = e; 45 | 46 | return c; 47 | } 48 | 49 | struct cot *parse_cot(struct tokenizer *t) { 50 | 51 | struct expression *e; 52 | 53 | token_get(t); 54 | if (t->token.type != COT) { 55 | token_unget(t); 56 | return NULL; 57 | } 58 | 59 | token_get(t); 60 | if (t->token.type != OPAREN) { 61 | token_unget(t); 62 | return NULL; 63 | } 64 | 65 | e = parse_expression(t); 66 | if (e == NULL) { 67 | return NULL; 68 | } 69 | 70 | token_get(t); 71 | if (t->token.type != CPAREN) { 72 | token_unget(t); 73 | free_expression(e); 74 | return NULL; 75 | } 76 | 77 | return new_cot(e); 78 | } 79 | 80 | struct number *eval_cot(struct cot *c) { 81 | struct number *n; 82 | 83 | n = eval_expression(c->e); 84 | if (n->type == INT) { 85 | float f; 86 | f = 1.0f / tanf((1.0f) * n->value.ival); 87 | n->type = FLOAT; 88 | n->value.fval = f; 89 | } else { /* float */ 90 | n->value.fval = 1.0f / tanf(n->value.fval); 91 | } 92 | 93 | return n; 94 | } 95 | 96 | void print_cot(struct cot *c) { 97 | if (c == NULL) { 98 | return; 99 | } 100 | 101 | printf("COT ("); 102 | print_expression(c->e); 103 | printf(")"); 104 | } 105 | 106 | void free_cot(struct cot *c) { 107 | 108 | if (c != NULL) { 109 | if (c->e != NULL) { 110 | free_expression(c->e); 111 | c->e = NULL; 112 | } 113 | free(c); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/driver.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "buffer.h" 27 | #include "eval.h" 28 | #include "readaline.h" 29 | #include "runtime.h" 30 | #include "tokenizer.h" 31 | 32 | static void print_help(char *progname) { 33 | 34 | fprintf(stdout, "%s - a small BASIC Interpreter written in C\n", PROJECT_NAME); 35 | fprintf(stdout, "\n"); 36 | fprintf(stdout, "Usage: %s [filename]\n", progname); 37 | fprintf(stdout, "\n"); 38 | fprintf(stdout, "Options:\n"); 39 | fprintf(stdout, " -h, -? --help Print a helpful message and exit\n"); 40 | fprintf(stdout, " -v --version Print version information and exit\n"); 41 | fprintf(stdout, "\n"); 42 | fprintf(stdout, "Report bugs to %s\n", PROJECT_BUGREPORT); 43 | 44 | exit(0); 45 | } 46 | 47 | static void print_version(void) { 48 | 49 | fprintf(stdout, "%s\n", PROJECT_STRING); 50 | fprintf(stdout, "\n"); 51 | fprintf(stdout, "Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort \n"); 52 | fprintf(stdout, "This is free software; see the source for copying conditions. There is NO\n"); 53 | fprintf(stdout, "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"); 54 | fprintf(stdout, "\n"); 55 | fprintf(stdout, "Written by Thomas Cort \n"); 56 | 57 | exit(0); 58 | } 59 | 60 | int main(int argc, char *argv[]) { 61 | 62 | int optc; 63 | Buffer *buf; 64 | FILE *fp; 65 | const char* const short_options = "h?v"; 66 | 67 | #if HAVE_GETOPT_LONG 68 | static const struct option long_options[] = { 69 | {"help", no_argument, NULL, 'h'}, 70 | {"version", no_argument, NULL, 'v'}, 71 | {NULL, 0, NULL, 0} 72 | }; 73 | #endif 74 | 75 | runtime_reset(); 76 | 77 | #if HAVE_GETOPT_LONG 78 | while ((optc = getopt_long(argc, argv, short_options, long_options, NULL)) != -1) { 79 | #else 80 | while ((optc = getopt(argc, argv, short_options)) != -1) { 81 | #endif 82 | switch (optc) { 83 | case 'v': 84 | print_version(); 85 | break; 86 | case 'h': 87 | case '?': 88 | print_help(argv[0]); 89 | break; 90 | } 91 | } 92 | 93 | if (optind != argc && optind + 1 != argc) { 94 | print_help(argv[0]); 95 | } 96 | 97 | if (optind + 1 == argc) { 98 | fp = fopen(argv[optind], "r"); 99 | if (fp == NULL) { 100 | perror("fopen"); 101 | return EXIT_FAILURE; 102 | } 103 | } else { 104 | fp = stdin; 105 | } 106 | 107 | tokenizer_init(); 108 | 109 | buf = bf_alloc(32, 16); 110 | do { 111 | readaline(fp, "> ", buf); 112 | eval(buf->buf); 113 | bf_clear(buf); 114 | } while (runtime_continue() && !feof(fp)); 115 | bf_free(buf); 116 | 117 | if (argc == 2) { 118 | eval("RUN"); 119 | } 120 | 121 | if (fp != stdin) { 122 | fclose(fp); 123 | } 124 | runtime_reset(); 125 | 126 | tokenizer_exit(); 127 | 128 | return EXIT_SUCCESS; 129 | } 130 | -------------------------------------------------------------------------------- /src/eval.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include "eval.h" 26 | #include "tokenizer.h" 27 | 28 | #include "line.h" 29 | 30 | void eval(char *s) { 31 | struct tokenizer t; 32 | 33 | if (s == NULL || s[0] == '\0') { 34 | return; 35 | } 36 | 37 | memset(&t, '\0', sizeof(struct tokenizer)); 38 | t.s = &s; 39 | 40 | parse_line(&t); 41 | } 42 | 43 | -------------------------------------------------------------------------------- /src/exp.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "tokenizer.h" 28 | 29 | #include "exp.h" 30 | #include "expression.h" 31 | #include "number.h" 32 | 33 | struct exp *new_exp(struct expression *e) { 34 | 35 | struct exp *ex; 36 | 37 | ex = (struct exp *) malloc(sizeof(struct exp)); 38 | if (ex == NULL) { 39 | perror("malloc"); 40 | exit(EXIT_FAILURE); 41 | } 42 | memset(ex, '\0', sizeof(struct exp)); 43 | 44 | ex->e = e; 45 | 46 | return ex; 47 | } 48 | 49 | struct exp *parse_exp(struct tokenizer *t) { 50 | 51 | struct expression *e; 52 | 53 | token_get(t); 54 | if (t->token.type != EXP) { 55 | token_unget(t); 56 | return NULL; 57 | } 58 | 59 | token_get(t); 60 | if (t->token.type != OPAREN) { 61 | token_unget(t); 62 | return NULL; 63 | } 64 | 65 | e = parse_expression(t); 66 | if (e == NULL) { 67 | return NULL; 68 | } 69 | 70 | token_get(t); 71 | if (t->token.type != CPAREN) { 72 | token_unget(t); 73 | free_expression(e); 74 | return NULL; 75 | } 76 | 77 | return new_exp(e); 78 | } 79 | 80 | struct number *eval_exp(struct exp *ex) { 81 | struct number *n; 82 | 83 | n = eval_expression(ex->e); 84 | if (n->type == INT) { 85 | float f; 86 | f = expf((1.0f) * n->value.ival); 87 | n->type = FLOAT; 88 | n->value.fval = f; 89 | } else { /* float */ 90 | n->value.fval = expf(n->value.fval); 91 | } 92 | 93 | return n; 94 | } 95 | 96 | void print_exp(struct exp *ex) { 97 | if (ex == NULL) { 98 | return; 99 | } 100 | 101 | printf("EXP ("); 102 | print_expression(ex->e); 103 | printf(")"); 104 | } 105 | 106 | void free_exp(struct exp *ex) { 107 | 108 | if (ex != NULL) { 109 | if (ex->e != NULL) { 110 | free_expression(ex->e); 111 | ex->e = NULL; 112 | } 113 | free(ex); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/expr_item.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "expr_item.h" 27 | #include "expression.h" 28 | #include "number.h" 29 | #include "str.h" 30 | 31 | struct expr_item *new_expr_item(struct expression *e, struct str *str) { 32 | 33 | struct expr_item *ei; 34 | 35 | ei = (struct expr_item *) malloc(sizeof(struct expr_item)); 36 | if (ei == NULL) { 37 | perror("malloc"); 38 | exit(EXIT_FAILURE); 39 | } 40 | memset(ei, '\0', sizeof(struct expr_item)); 41 | 42 | ei->e = e; 43 | ei->str = str; 44 | 45 | return ei; 46 | } 47 | 48 | struct expr_item *parse_expr_item(struct tokenizer *t) { 49 | 50 | struct expression *expr; 51 | struct str *s; 52 | 53 | expr = parse_expression(t); 54 | if (expr != NULL) { 55 | return new_expr_item(expr, NULL); 56 | } 57 | 58 | s = parse_str(t); 59 | if (s != NULL) { 60 | return new_expr_item(NULL, s); 61 | } 62 | 63 | return NULL; 64 | } 65 | 66 | void eval_expr_item(struct expr_item *ei) { 67 | 68 | if (ei == NULL) { 69 | return; 70 | } 71 | 72 | if (ei->str != NULL) { 73 | printf("%s", eval_str(ei->str)); 74 | } else { 75 | struct number *n = eval_expression(ei->e); 76 | print_number(n); 77 | free_number(n); 78 | } 79 | } 80 | 81 | void print_expr_item(struct expr_item *ei) { 82 | 83 | if (ei == NULL) { 84 | return; 85 | } 86 | 87 | print_expression(ei->e); 88 | print_str(ei->str); 89 | } 90 | 91 | void free_expr_item(struct expr_item *ei) { 92 | if (ei != NULL) { 93 | free_str(ei->str); 94 | free_expression(ei->e); 95 | free(ei); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/expr_list.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "expr_list.h" 27 | #include "expr_item.h" 28 | 29 | #include "tokenizer.h" 30 | 31 | struct expr_list *new_expr_list(struct expr_item *expr_item, struct expr_list *list) { 32 | 33 | struct expr_list *el; 34 | 35 | el = (struct expr_list *) malloc(sizeof(struct expr_list)); 36 | if (el == NULL) { 37 | perror("malloc"); 38 | exit(EXIT_FAILURE); 39 | } 40 | memset(el, '\0', sizeof(struct expr_list)); 41 | 42 | el->expr_item = expr_item; 43 | el->list = list; 44 | 45 | return el; 46 | } 47 | 48 | struct expr_list *parse_expr_list(struct tokenizer *t) { 49 | 50 | struct expr_item *i; 51 | 52 | i = parse_expr_item(t); 53 | if (i == NULL) { 54 | return NULL; 55 | } 56 | 57 | token_get(t); 58 | if (t->token.type == COMMA) { 59 | return new_expr_list(i, parse_expr_list(t)); 60 | } else { 61 | token_unget(t); 62 | return new_expr_list(i, NULL); 63 | } 64 | } 65 | 66 | void eval_expr_list(struct expr_list *el) { 67 | 68 | if (el == NULL) { 69 | return; 70 | } 71 | 72 | eval_expr_item(el->expr_item); 73 | eval_expr_list(el->list); 74 | } 75 | 76 | void print_expr_list(struct expr_list *el) { 77 | 78 | if (el == NULL) { 79 | return; 80 | } 81 | 82 | print_expr_item(el->expr_item); 83 | if (el->list != NULL) { 84 | printf(", "); 85 | print_expr_list(el->list); 86 | } 87 | } 88 | 89 | void free_expr_list(struct expr_list *el) { 90 | if (el != NULL) { 91 | free_expr_item(el->expr_item); 92 | free_expr_list(el->list); 93 | free(el); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/expression.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "addop.h" 27 | #include "expression.h" 28 | #include "number.h" 29 | #include "term.h" 30 | 31 | struct expression *new_expression(struct addop *term1_op, struct term *term1, struct addop *term2_op, struct term *term2) { 32 | 33 | struct expression *e; 34 | 35 | e = (struct expression *) malloc(sizeof(struct expression)); 36 | if (e == NULL) { 37 | perror("malloc"); 38 | exit(EXIT_FAILURE); 39 | } 40 | memset(e, '\0', sizeof(struct expression)); 41 | 42 | e->term1_op = term1_op; 43 | e->term1 = term1; 44 | e->term2_op = term2_op; 45 | e->term2 = term2; 46 | 47 | return e; 48 | } 49 | 50 | struct expression *parse_expression(struct tokenizer *t) { 51 | 52 | struct addop *t1_op; 53 | struct term *t1; 54 | struct addop *t2_op; 55 | struct term *t2; 56 | 57 | t1_op = parse_addop(t); 58 | if (t1_op == NULL) { 59 | t1 = parse_term(t); 60 | if (t1 == NULL) { /* not an expression */ 61 | return NULL; 62 | } 63 | t2_op = parse_addop(t); 64 | if (t2_op == NULL) { /* X */ 65 | return new_expression(NULL, t1, NULL, NULL); 66 | } 67 | t2 = parse_term(t); 68 | if (t2 == NULL) { 69 | free_term(t1); 70 | free_addop(t2_op); 71 | return NULL; 72 | } 73 | return new_expression(NULL, t1, t2_op, t2); /* X+Y */ 74 | } 75 | 76 | t1 = parse_term(t); 77 | if (t1 == NULL) { /* + but no term */ 78 | free_addop(t1_op); 79 | return NULL; 80 | } 81 | 82 | t2_op = parse_addop(t); 83 | if (t2_op == NULL) { /* +X */ 84 | return new_expression(t1_op, t1, NULL, NULL); 85 | } 86 | 87 | t2 = parse_term(t); /* +X+ no term */ 88 | if (t2 == NULL) { 89 | free_addop(t1_op); 90 | free_term(t1); 91 | free_addop(t2_op); 92 | return NULL; 93 | } 94 | return new_expression(t1_op, t1, t2_op, t2); 95 | } 96 | 97 | struct number *eval_expression(struct expression *e) { 98 | 99 | 100 | struct number *o1; 101 | struct number *t1; 102 | struct number *o2; 103 | struct number *t2; 104 | struct number *l; 105 | struct number *r; 106 | struct number *result; 107 | 108 | if (e == NULL) { 109 | return 0; 110 | } 111 | 112 | if (e->term1_op != NULL) { 113 | o1 = new_number_from_int(eval_addop(e->term1_op)); 114 | } else { 115 | o1 = new_number_from_int(1); 116 | } 117 | 118 | if (e->term1 != NULL) { 119 | t1 = eval_term(e->term1); 120 | } else { 121 | t1 = new_number_from_int(0); 122 | } 123 | 124 | if (e->term2_op != NULL) { 125 | o2 = new_number_from_int(eval_addop(e->term2_op)); 126 | } else { 127 | o2 = new_number_from_int(1); 128 | } 129 | 130 | if (e->term2 != NULL) { 131 | t2 = eval_term(e->term2); 132 | } else { 133 | t2 = new_number_from_int(0); 134 | } 135 | 136 | l = multiply_number(o1, t1); 137 | r = multiply_number(o2, t2); 138 | 139 | result = add_number(l, r); 140 | 141 | free_number(l); 142 | free_number(r); 143 | free_number(o1); 144 | free_number(t1); 145 | free_number(o2); 146 | free_number(t2); 147 | 148 | return result; 149 | } 150 | 151 | void print_expression(struct expression *e) { 152 | 153 | if (e == NULL) { 154 | return; 155 | } 156 | 157 | print_addop(e->term1_op); 158 | print_term(e->term1); 159 | print_addop(e->term2_op); 160 | print_term(e->term2); 161 | } 162 | 163 | void free_expression(struct expression *e) { 164 | if (e != NULL) { 165 | free_addop(e->term1_op); 166 | free_term(e->term1); 167 | free_addop(e->term2_op); 168 | free_term(e->term2); 169 | free(e); 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /src/factor.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "tokenizer.h" 27 | 28 | #include "factor.h" 29 | #include "number.h" 30 | #include "primary.h" 31 | 32 | struct factor *new_factor(struct primary *p, struct factor *f) { 33 | 34 | struct factor *r; 35 | 36 | r = (struct factor *) malloc(sizeof(struct factor)); 37 | if (r == NULL) { 38 | perror("malloc"); 39 | exit(EXIT_FAILURE); 40 | } 41 | memset(r, '\0', sizeof(struct factor)); 42 | 43 | r->p = p; 44 | r->f = f; 45 | 46 | return r; 47 | } 48 | 49 | struct factor *parse_factor(struct tokenizer *t) { 50 | 51 | struct primary *p; 52 | struct factor *f; 53 | 54 | p = parse_primary(t); 55 | if (p == NULL) { 56 | return NULL; 57 | } 58 | 59 | token_get(t); 60 | if (t->token.type == CIRCUMFLEX) { 61 | f = parse_factor(t); 62 | if (f == NULL) { 63 | free_primary(p); 64 | return NULL; 65 | } 66 | } else { 67 | f = NULL; 68 | token_unget(t); 69 | } 70 | 71 | return new_factor(p, f); 72 | } 73 | 74 | struct number * eval_factor(struct factor *f) { 75 | 76 | struct number *n1 = NULL; 77 | struct number *n2 = NULL; 78 | struct number *r = NULL; 79 | 80 | if (f == NULL) { 81 | return new_number_from_int(1); 82 | } 83 | 84 | n1 = eval_primary(f->p); 85 | if (f->f == NULL) { 86 | r = clone_number(n1); 87 | } else { 88 | n2 = eval_factor(f->f); 89 | r = pow_number(n1, n2); 90 | } 91 | 92 | free_number(n1); 93 | free_number(n2); 94 | 95 | return r; 96 | } 97 | 98 | void print_factor(struct factor *f) { 99 | 100 | if (f == NULL) { 101 | return; 102 | } 103 | 104 | print_primary(f->p); 105 | if (f->f != NULL) { 106 | printf("^"); 107 | print_factor(f->f); 108 | } 109 | } 110 | 111 | void free_factor(struct factor *f) { 112 | if (f != NULL) { 113 | if (f->p != NULL) { 114 | free_primary(f->p); 115 | f->p = NULL; 116 | } 117 | if (f->f != NULL) { 118 | free_factor(f->f); 119 | f->f = NULL; 120 | } 121 | free(f); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/int_.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "tokenizer.h" 28 | 29 | #include "int_.h" 30 | #include "expression.h" 31 | #include "number.h" 32 | 33 | struct int_ *new_int(struct expression *e) { 34 | 35 | struct int_ *i; 36 | 37 | i = (struct int_ *) malloc(sizeof(struct int_)); 38 | if (i == NULL) { 39 | perror("malloc"); 40 | exit(EXIT_FAILURE); 41 | } 42 | memset(i, '\0', sizeof(struct int_)); 43 | 44 | i->e = e; 45 | 46 | return i; 47 | } 48 | 49 | struct int_ *parse_int(struct tokenizer *t) { 50 | 51 | struct expression *e; 52 | 53 | token_get(t); 54 | if (t->token.type != INT_) { 55 | token_unget(t); 56 | return NULL; 57 | } 58 | 59 | token_get(t); 60 | if (t->token.type != OPAREN) { 61 | token_unget(t); 62 | return NULL; 63 | } 64 | 65 | e = parse_expression(t); 66 | if (e == NULL) { 67 | return NULL; 68 | } 69 | 70 | token_get(t); 71 | if (t->token.type != CPAREN) { 72 | token_unget(t); 73 | free_expression(e); 74 | return NULL; 75 | } 76 | 77 | return new_int(e); 78 | } 79 | 80 | struct number *eval_int(struct int_ *i) { 81 | struct number *n; 82 | 83 | n = eval_expression(i->e); 84 | if (n->type == FLOAT) { 85 | n->type = INT; 86 | n->value.ival = (int) n->value.fval; 87 | } 88 | 89 | return n; 90 | } 91 | 92 | void print_int(struct int_ *i) { 93 | if (i == NULL) { 94 | return; 95 | } 96 | 97 | printf("INT ("); 98 | print_expression(i->e); 99 | printf(")"); 100 | } 101 | 102 | void free_int(struct int_ *i) { 103 | 104 | if (i != NULL) { 105 | if (i->e != NULL) { 106 | free_expression(i->e); 107 | i->e = NULL; 108 | } 109 | free(i); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/line.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "runtime.h" 27 | #include "tokenizer.h" 28 | 29 | #include "command.h" 30 | #include "line.h" 31 | #include "number.h" 32 | #include "statement.h" 33 | 34 | struct line *new_line(struct statement *statement, struct number *number) { 35 | 36 | struct line *l; 37 | 38 | l = (struct line *) malloc(sizeof(struct line)); 39 | if (l == NULL) { 40 | perror("malloc"); 41 | exit(EXIT_FAILURE); 42 | } 43 | memset(l, '\0', sizeof(struct line)); 44 | 45 | l->statement = statement; 46 | l->number = INT_VALUE(number); 47 | 48 | free_number(number); 49 | 50 | return l; 51 | } 52 | 53 | void parse_line(struct tokenizer *t) { 54 | 55 | struct command *cmd; 56 | struct statement *stmt; 57 | struct number *num; 58 | 59 | cmd = parse_command(t); 60 | if (cmd != NULL) { 61 | exec_command(cmd); 62 | free_command(cmd); 63 | cmd = NULL; 64 | token_get(t); 65 | return; 66 | } 67 | 68 | stmt = parse_statement(t); 69 | if (stmt != NULL) { 70 | eval_statement(stmt, -1, -1); 71 | free_statement(stmt); 72 | stmt = NULL; 73 | token_get(t); 74 | return; 75 | } 76 | 77 | num = parse_number(t); 78 | if (num != NULL) { 79 | stmt = parse_statement(t); 80 | if (stmt != NULL) { 81 | runtime_set_line(new_line(stmt, num)); 82 | token_get(t); 83 | return; 84 | } else { 85 | runtime_rm_line(INT_VALUE(num)); 86 | free_number(num); 87 | num = NULL; 88 | token_get(t); 89 | return; 90 | } 91 | } 92 | 93 | fprintf(stderr, "ERROR: INVALID STATEMENT\n"); 94 | } 95 | 96 | int eval_line(struct line *l) { 97 | 98 | if (l == NULL) { 99 | return -1; 100 | } 101 | 102 | if (runtime_is_tracing()) { 103 | printf("TR> "); 104 | print_line(l); 105 | } 106 | 107 | return eval_statement(l->statement, l->number, (l->next != NULL) ? l->next->number : -1); 108 | } 109 | 110 | void print_line(struct line *l) { 111 | 112 | if (l == NULL) { 113 | return; 114 | } 115 | 116 | printf("%d ", l->number); 117 | print_statement(l->statement); 118 | printf("\n"); 119 | 120 | } 121 | 122 | void print_lines(struct line *l) { 123 | 124 | struct line *cur; 125 | 126 | if (l == NULL) { 127 | return; 128 | } 129 | 130 | for (cur = l; cur != NULL; cur = cur->next) { 131 | print_line(cur); 132 | } 133 | 134 | } 135 | 136 | void free_line(struct line *l) { 137 | if (l != NULL) { 138 | free_statement(l->statement); 139 | free_line(l->next); 140 | free(l); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/log.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "tokenizer.h" 28 | 29 | #include "log.h" 30 | #include "expression.h" 31 | #include "number.h" 32 | 33 | struct log *new_log(struct expression *e) { 34 | 35 | struct log *l; 36 | 37 | l = (struct log *) malloc(sizeof(struct log)); 38 | if (l == NULL) { 39 | perror("malloc"); 40 | exit(EXIT_FAILURE); 41 | } 42 | memset(l, '\0', sizeof(struct log)); 43 | 44 | l->e = e; 45 | 46 | return l; 47 | } 48 | 49 | struct log *parse_log(struct tokenizer *t) { 50 | 51 | struct expression *e; 52 | 53 | token_get(t); 54 | if (t->token.type != LOG) { 55 | token_unget(t); 56 | return NULL; 57 | } 58 | 59 | token_get(t); 60 | if (t->token.type != OPAREN) { 61 | token_unget(t); 62 | return NULL; 63 | } 64 | 65 | e = parse_expression(t); 66 | if (e == NULL) { 67 | return NULL; 68 | } 69 | 70 | token_get(t); 71 | if (t->token.type != CPAREN) { 72 | token_unget(t); 73 | free_expression(e); 74 | return NULL; 75 | } 76 | 77 | return new_log(e); 78 | } 79 | 80 | struct number *eval_log(struct log *l) { 81 | struct number *n; 82 | 83 | n = eval_expression(l->e); 84 | if (n->type == INT) { 85 | float f; 86 | f = logf((1.0f) * n->value.ival); 87 | n->type = FLOAT; 88 | n->value.fval = f; 89 | } else { /* float */ 90 | n->value.fval = logf(n->value.fval); 91 | } 92 | 93 | return n; 94 | } 95 | 96 | void print_log(struct log *l) { 97 | if (l == NULL) { 98 | return; 99 | } 100 | 101 | printf("LOG ("); 102 | print_expression(l->e); 103 | printf(")"); 104 | } 105 | 106 | void free_log(struct log *l) { 107 | 108 | if (l != NULL) { 109 | if (l->e != NULL) { 110 | free_expression(l->e); 111 | l->e = NULL; 112 | } 113 | free(l); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/mulop.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "tokenizer.h" 27 | 28 | #include "mulop.h" 29 | 30 | struct mulop *new_mulop(int type) { 31 | 32 | struct mulop *op; 33 | 34 | op = (struct mulop *) malloc(sizeof(struct mulop)); 35 | if (op == NULL) { 36 | perror("malloc"); 37 | exit(EXIT_FAILURE); 38 | } 39 | memset(op, '\0', sizeof(struct mulop)); 40 | 41 | op->type = type; 42 | 43 | return op; 44 | } 45 | 46 | struct mulop *parse_mulop(struct tokenizer *t) { 47 | 48 | token_get(t); 49 | switch (t->token.type) { 50 | case TIMES: 51 | return new_mulop(TIMES); 52 | case DIVIDE: 53 | return new_mulop(DIVIDE); 54 | case IDIVIDE: 55 | return new_mulop(IDIVIDE); 56 | case MOD: 57 | return new_mulop(MOD); 58 | default: 59 | token_unget(t); 60 | return NULL; 61 | } 62 | } 63 | 64 | void print_mulop(struct mulop *op) { 65 | 66 | if (op == NULL) { 67 | return; 68 | } 69 | 70 | switch (op->type) { 71 | case TIMES: 72 | printf("*"); 73 | break; 74 | case DIVIDE: 75 | printf("/"); 76 | break; 77 | case IDIVIDE: 78 | printf("\\"); 79 | break; 80 | case MOD: 81 | printf("MOD"); 82 | break; 83 | default: 84 | printf("?"); 85 | break; 86 | } 87 | } 88 | 89 | void free_mulop(struct mulop *op) { 90 | if (op != NULL) { 91 | free(op); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/number.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "number.h" 29 | 30 | #include "tokenizer.h" 31 | 32 | struct number *new_number(char *s) { 33 | 34 | int is_int = 0; 35 | regex_t ireg; 36 | regmatch_t matches[1]; 37 | struct number *n; 38 | 39 | n = (struct number *) malloc(sizeof(struct number)); 40 | if (n == NULL) { 41 | perror("malloc"); 42 | exit(EXIT_FAILURE); 43 | } 44 | memset(n, '\0', sizeof(struct number)); 45 | 46 | regcomp(&ireg, "^[0-9]+$", REG_EXTENDED); 47 | is_int = !regexec(&ireg, s, 1, matches, 0); 48 | regfree(&ireg); 49 | 50 | if (is_int) { 51 | n->type = INT; 52 | n->value.ival = atoi(s); 53 | } else { 54 | n->type = FLOAT; 55 | n->value.fval = (float) atof(s); 56 | } 57 | 58 | return n; 59 | } 60 | 61 | struct number *new_number_from_int(int i) { 62 | 63 | struct number r; 64 | 65 | r.type = INT; 66 | r.value.ival = i; 67 | 68 | return clone_number(&r); 69 | } 70 | 71 | struct number *new_number_from_float(float f) { 72 | 73 | struct number r; 74 | 75 | r.type = FLOAT; 76 | r.value.fval = f; 77 | 78 | return clone_number(&r); 79 | } 80 | 81 | struct number *parse_number(struct tokenizer *t) { 82 | 83 | token_get(t); 84 | if (t->token.type == NUMBER) { 85 | return new_number(t->token.text); 86 | } else { 87 | token_unget(t); 88 | return NULL; 89 | } 90 | } 91 | 92 | struct number *clone_number(struct number *n) { 93 | struct number *clone; 94 | 95 | if (n == NULL) { 96 | return NULL; 97 | } 98 | 99 | clone = (struct number *) malloc(sizeof(struct number)); 100 | if (clone == NULL) { 101 | perror("malloc"); 102 | exit(EXIT_FAILURE); 103 | } 104 | 105 | memcpy(clone, n, sizeof(struct number)); 106 | return clone; 107 | } 108 | 109 | struct number *add_number(struct number *x, struct number *y) { 110 | struct number r; 111 | 112 | if (x == NULL || y == NULL) { 113 | return NULL; 114 | } 115 | 116 | 117 | if (x->type == INT) { 118 | if (y->type == INT) { 119 | r.type = INT; 120 | r.value.ival = x->value.ival + y->value.ival; 121 | } else { 122 | r.type = FLOAT; 123 | r.value.fval = x->value.ival + y->value.fval; 124 | } 125 | } else { 126 | if (y->type == INT) { 127 | r.type = FLOAT; 128 | r.value.fval = x->value.fval + y->value.ival; 129 | } else { 130 | r.type = FLOAT; 131 | r.value.fval = x->value.fval + y->value.fval; 132 | } 133 | } 134 | 135 | return clone_number(&r); 136 | } 137 | 138 | struct number *subtract_number(struct number *x, struct number *y) { 139 | 140 | struct number *neg; 141 | struct number *yneg; 142 | struct number *r; 143 | 144 | if (x == NULL || y == NULL) { 145 | return NULL; 146 | } 147 | 148 | neg = new_number_from_int(-1); 149 | if (neg == NULL) { 150 | return NULL; 151 | } 152 | 153 | yneg = multiply_number(neg, y); 154 | if (yneg == NULL) { 155 | free_number(neg); 156 | return NULL; 157 | } 158 | 159 | free_number(neg); 160 | 161 | r = add_number(x, yneg); 162 | if (r == NULL) { 163 | free_number(yneg); 164 | return NULL; 165 | } 166 | 167 | free_number(yneg); 168 | return r; 169 | 170 | } 171 | 172 | struct number *multiply_number(struct number *x, struct number *y) { 173 | struct number r; 174 | 175 | if (x == NULL || y == NULL) { 176 | return NULL; 177 | } 178 | 179 | 180 | if (x->type == INT) { 181 | if (y->type == INT) { 182 | r.type = INT; 183 | r.value.ival = x->value.ival * y->value.ival; 184 | } else { 185 | r.type = FLOAT; 186 | r.value.fval = x->value.ival * y->value.fval; 187 | } 188 | } else { 189 | if (y->type == INT) { 190 | r.type = FLOAT; 191 | r.value.fval = x->value.fval * y->value.ival; 192 | } else { 193 | r.type = FLOAT; 194 | r.value.fval = x->value.fval * y->value.fval; 195 | } 196 | } 197 | 198 | return clone_number(&r); 199 | } 200 | 201 | struct number *idivide_number(struct number *x, struct number *y) { 202 | struct number r; 203 | 204 | if (x == NULL || y == NULL) { 205 | return NULL; 206 | } 207 | 208 | r.type = INT; 209 | r.value.ival = INT_VALUE(x) / INT_VALUE(y); 210 | 211 | return clone_number(&r); 212 | } 213 | 214 | struct number *divide_number(struct number *x, struct number *y) { 215 | struct number r; 216 | 217 | if (x == NULL || y == NULL) { 218 | return NULL; 219 | } 220 | 221 | 222 | if (x->type == INT) { 223 | if (y->type == INT) { 224 | r.type = INT; 225 | r.value.ival = x->value.ival / y->value.ival; 226 | } else { 227 | r.type = FLOAT; 228 | r.value.fval = x->value.ival / y->value.fval; 229 | } 230 | } else { 231 | if (y->type == INT) { 232 | r.type = FLOAT; 233 | r.value.fval = x->value.fval / y->value.ival; 234 | } else { 235 | r.type = FLOAT; 236 | r.value.fval = x->value.fval / y->value.fval; 237 | } 238 | } 239 | 240 | return clone_number(&r); 241 | } 242 | 243 | struct number *modulus_number(struct number *x, struct number *y) { 244 | struct number r; 245 | 246 | if (x == NULL || y == NULL) { 247 | return NULL; 248 | } 249 | 250 | 251 | if (x->type == INT) { 252 | if (y->type == INT) { 253 | r.type = INT; 254 | r.value.ival = x->value.ival % y->value.ival; 255 | } else { 256 | r.type = FLOAT; 257 | r.value.fval = fmod(x->value.ival, y->value.fval); 258 | } 259 | } else { 260 | if (y->type == INT) { 261 | r.type = FLOAT; 262 | r.value.fval = fmod(x->value.fval, y->value.ival); 263 | } else { 264 | r.type = FLOAT; 265 | r.value.fval = fmod(x->value.fval, y->value.fval); 266 | } 267 | } 268 | 269 | return clone_number(&r); 270 | } 271 | 272 | struct number *pow_number(struct number *x, struct number *y) { 273 | struct number r; 274 | 275 | if (x == NULL || y == NULL) { 276 | return NULL; 277 | } 278 | 279 | 280 | if (x->type == INT) { 281 | if (y->type == INT) { 282 | r.type = INT; 283 | r.value.ival = (int) pow(x->value.ival, y->value.ival); 284 | } else { 285 | r.type = FLOAT; 286 | r.value.fval = pow(x->value.ival, y->value.fval); 287 | } 288 | } else { 289 | if (y->type == INT) { 290 | r.type = FLOAT; 291 | r.value.fval = pow(x->value.fval, y->value.ival); 292 | } else { 293 | r.type = FLOAT; 294 | r.value.fval = pow(x->value.fval, y->value.fval); 295 | } 296 | } 297 | 298 | return clone_number(&r); 299 | } 300 | 301 | void print_number(struct number *n) { 302 | if (n == NULL) { 303 | return; 304 | } 305 | 306 | if (n->type == INT) { 307 | printf("%d", n->value.ival); 308 | } else { 309 | printf("%f", n->value.fval); 310 | } 311 | } 312 | 313 | void free_number(struct number *n) { 314 | if (n != NULL) { 315 | free(n); 316 | } 317 | } 318 | 319 | -------------------------------------------------------------------------------- /src/pi.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "prng.h" 27 | #include "tokenizer.h" 28 | 29 | #include "number.h" 30 | #include "pi.h" 31 | 32 | struct pi *new_pi(void) { 33 | 34 | struct pi *r; 35 | 36 | r = (struct pi *) malloc(sizeof(struct pi)); 37 | if (r == NULL) { 38 | perror("malloc"); 39 | exit(EXIT_FAILURE); 40 | } 41 | memset(r, '\0', sizeof(struct pi)); 42 | 43 | return r; 44 | } 45 | 46 | struct pi *parse_pi(struct tokenizer *t) { 47 | 48 | token_get(t); 49 | if (t->token.type != PI) { 50 | token_unget(t); 51 | return NULL; 52 | } 53 | 54 | return new_pi(); 55 | } 56 | 57 | struct number *eval_pi(void) { 58 | return new_number_from_float(3.14159265); 59 | } 60 | 61 | void print_pi(struct pi *r) { 62 | if (r == NULL) { 63 | return; 64 | } 65 | 66 | printf("π"); 67 | } 68 | 69 | void free_pi(struct pi *r) { 70 | if (r != NULL) { 71 | free(r); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/primary.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "tokenizer.h" 27 | 28 | #include "expression.h" 29 | #include "primary.h" 30 | #include "number.h" 31 | #include "rnd.h" 32 | #include "time_.h" 33 | #include "sin.h" 34 | #include "cos.h" 35 | #include "tan.h" 36 | #include "cot.h" 37 | #include "atn.h" 38 | #include "exp.h" 39 | #include "log.h" 40 | #include "abs.h" 41 | #include "int_.h" 42 | #include "sgn.h" 43 | #include "sqr.h" 44 | #include "var.h" 45 | #include "pi.h" 46 | 47 | struct primary *new_primary(int type, void *value) { 48 | 49 | struct primary *f; 50 | 51 | f = (struct primary *) malloc(sizeof(struct primary)); 52 | if (f == NULL) { 53 | perror("malloc"); 54 | exit(EXIT_FAILURE); 55 | } 56 | memset(f, '\0', sizeof(struct primary)); 57 | 58 | f->type = type; 59 | switch (f->type) { 60 | case EXPRESSION: 61 | f->u.e = (struct expression *) value; 62 | break; 63 | case NUMBER: 64 | f->u.n = (struct number *) value; 65 | break; 66 | case RND: 67 | f->u.r = (struct rnd *) value; 68 | break; 69 | case TIME: 70 | f->u.time = (struct time *) value; 71 | break; 72 | case SIN: 73 | f->u.sin = (struct sin *) value; 74 | break; 75 | case COS: 76 | f->u.cos = (struct cos *) value; 77 | break; 78 | case TAN: 79 | f->u.tan = (struct tan *) value; 80 | break; 81 | case COT: 82 | f->u.cot = (struct cot *) value; 83 | break; 84 | case ATN: 85 | f->u.atn = (struct atn *) value; 86 | break; 87 | case EXP: 88 | f->u.exp = (struct exp *) value; 89 | break; 90 | case LOG: 91 | f->u.log = (struct log *) value; 92 | break; 93 | case ABS: 94 | f->u.abs = (struct abs *) value; 95 | break; 96 | case SGN: 97 | f->u.sgn = (struct sgn *) value; 98 | break; 99 | case SQR: 100 | f->u.sqr = (struct sqr *) value; 101 | break; 102 | case INT_: 103 | f->u.int_ = (struct int_ *) value; 104 | break; 105 | case VAR: 106 | f->u.v = (struct var *) value; 107 | break; 108 | case PI: 109 | f->u.pi = (struct pi *) value; 110 | break; 111 | } 112 | 113 | return f; 114 | } 115 | 116 | struct primary *parse_primary(struct tokenizer *t) { 117 | 118 | struct var *v; 119 | struct number *num; 120 | struct rnd *r; 121 | struct time *time; 122 | struct sin *sin; 123 | struct cos *cos; 124 | struct tan *tan; 125 | struct cot *cot; 126 | struct atn *atn; 127 | struct exp *exp; 128 | struct log *log; 129 | struct abs *abs; 130 | struct sgn *sgn; 131 | struct sqr *sqr; 132 | struct int_ *int_; 133 | struct pi *pi; 134 | 135 | v = parse_var(t); 136 | if (v != NULL) { 137 | return new_primary(VAR, v); 138 | } 139 | 140 | num = parse_number(t); 141 | if (num != NULL) { 142 | return new_primary(NUMBER, num); 143 | } 144 | 145 | token_get(t); 146 | if (t->token.type == OPAREN) { 147 | struct expression *expr; 148 | expr = parse_expression(t); 149 | if (expr == NULL) { 150 | return NULL; 151 | } 152 | token_get(t); 153 | if (t->token.type == CPAREN) { 154 | return new_primary(EXPRESSION, expr); 155 | } 156 | token_unget(t); 157 | free_expression(expr); 158 | return NULL; 159 | } 160 | token_unget(t); 161 | 162 | pi = parse_pi(t); 163 | if (pi != NULL) { 164 | return new_primary(PI, pi); 165 | } 166 | 167 | r = parse_rnd(t); 168 | if (r != NULL) { 169 | return new_primary(RND, r); 170 | } 171 | 172 | time = parse_time(t); 173 | if (time != NULL) { 174 | return new_primary(TIME, time); 175 | } 176 | 177 | sin = parse_sin(t); 178 | if (sin != NULL) { 179 | return new_primary(SIN, sin); 180 | } 181 | 182 | cos = parse_cos(t); 183 | if (cos != NULL) { 184 | return new_primary(COS, cos); 185 | } 186 | 187 | tan = parse_tan(t); 188 | if (tan != NULL) { 189 | return new_primary(TAN, tan); 190 | } 191 | 192 | cot = parse_cot(t); 193 | if (cot != NULL) { 194 | return new_primary(COT, cot); 195 | } 196 | 197 | atn = parse_atn(t); 198 | if (atn != NULL) { 199 | return new_primary(ATN, atn); 200 | } 201 | 202 | exp = parse_exp(t); 203 | if (exp != NULL) { 204 | return new_primary(EXP, exp); 205 | } 206 | 207 | log = parse_log(t); 208 | if (log != NULL) { 209 | return new_primary(LOG, log); 210 | } 211 | 212 | abs = parse_abs(t); 213 | if (abs != NULL) { 214 | return new_primary(ABS, abs); 215 | } 216 | 217 | sgn = parse_sgn(t); 218 | if (sgn != NULL) { 219 | return new_primary(SGN, sgn); 220 | } 221 | 222 | sqr = parse_sqr(t); 223 | if (sqr != NULL) { 224 | return new_primary(SQR, sqr); 225 | } 226 | 227 | int_ = parse_int(t); 228 | if (int_ != NULL) { 229 | return new_primary(INT_, int_); 230 | } 231 | 232 | return NULL; 233 | } 234 | 235 | struct number * eval_primary(struct primary *f) { 236 | 237 | struct number *n = NULL; 238 | 239 | if (f == NULL) { 240 | return new_number_from_int(1); 241 | } 242 | 243 | switch (f->type) { 244 | case EXPRESSION: 245 | n = eval_expression(f->u.e); 246 | break; 247 | case NUMBER: 248 | n = clone_number(f->u.n); 249 | break; 250 | case RND: 251 | n = eval_rnd(); 252 | break; 253 | case TIME: 254 | n = eval_time(); 255 | break; 256 | case SIN: 257 | n = eval_sin(f->u.sin); 258 | break; 259 | case COS: 260 | n = eval_cos(f->u.cos); 261 | break; 262 | case TAN: 263 | n = eval_tan(f->u.tan); 264 | break; 265 | case COT: 266 | n = eval_cot(f->u.cot); 267 | break; 268 | case ATN: 269 | n = eval_atn(f->u.atn); 270 | break; 271 | case EXP: 272 | n = eval_exp(f->u.exp); 273 | break; 274 | case LOG: 275 | n = eval_log(f->u.log); 276 | break; 277 | case ABS: 278 | n = eval_abs(f->u.abs); 279 | break; 280 | case SGN: 281 | n = eval_sgn(f->u.sgn); 282 | break; 283 | case SQR: 284 | n = eval_sqr(f->u.sqr); 285 | break; 286 | case INT_: 287 | n = eval_int(f->u.int_); 288 | break; 289 | case VAR: 290 | n = eval_var(f->u.v); 291 | break; 292 | case PI: 293 | n = eval_pi(); 294 | break; 295 | } 296 | 297 | return n; 298 | } 299 | 300 | void print_primary(struct primary *f) { 301 | 302 | if (f == NULL) { 303 | return; 304 | } 305 | 306 | switch (f->type) { 307 | case EXPRESSION: 308 | printf("("); 309 | print_expression(f->u.e); 310 | printf(")"); 311 | break; 312 | case NUMBER: 313 | print_number(f->u.n); 314 | break; 315 | case RND: 316 | print_rnd(f->u.r); 317 | break; 318 | case TIME: 319 | print_time(f->u.time); 320 | break; 321 | case SIN: 322 | print_sin(f->u.sin); 323 | break; 324 | case COS: 325 | print_cos(f->u.cos); 326 | break; 327 | case TAN: 328 | print_tan(f->u.tan); 329 | break; 330 | case COT: 331 | print_cot(f->u.cot); 332 | break; 333 | case ATN: 334 | print_atn(f->u.atn); 335 | break; 336 | case EXP: 337 | print_exp(f->u.exp); 338 | break; 339 | case LOG: 340 | print_log(f->u.log); 341 | break; 342 | case ABS: 343 | print_abs(f->u.abs); 344 | break; 345 | case SGN: 346 | print_sgn(f->u.sgn); 347 | break; 348 | case SQR: 349 | print_sqr(f->u.sqr); 350 | break; 351 | case INT_: 352 | print_int(f->u.int_); 353 | break; 354 | case VAR: 355 | print_var(f->u.v); 356 | break; 357 | case PI: 358 | print_pi(f->u.pi); 359 | break; 360 | } 361 | } 362 | 363 | void free_primary(struct primary *f) { 364 | if (f != NULL) { 365 | switch (f->type) { 366 | case EXPRESSION: 367 | free_expression(f->u.e); 368 | f->u.e = NULL; 369 | break; 370 | case NUMBER: 371 | free_number(f->u.n); 372 | f->u.n = NULL; 373 | break; 374 | case RND: 375 | free_rnd(f->u.r); 376 | f->u.r = NULL; 377 | break; 378 | case TIME: 379 | free_time(f->u.time); 380 | f->u.time = NULL; 381 | break; 382 | case SIN: 383 | free_sin(f->u.sin); 384 | f->u.sin = NULL; 385 | break; 386 | case COS: 387 | free_cos(f->u.cos); 388 | f->u.cos = NULL; 389 | break; 390 | case TAN: 391 | free_tan(f->u.tan); 392 | f->u.tan = NULL; 393 | break; 394 | case COT: 395 | free_cot(f->u.cot); 396 | f->u.cot = NULL; 397 | break; 398 | case ATN: 399 | free_atn(f->u.atn); 400 | f->u.atn = NULL; 401 | break; 402 | case EXP: 403 | free_exp(f->u.exp); 404 | f->u.exp = NULL; 405 | break; 406 | case LOG: 407 | free_log(f->u.log); 408 | f->u.log = NULL; 409 | break; 410 | case ABS: 411 | free_abs(f->u.abs); 412 | f->u.abs = NULL; 413 | break; 414 | case SGN: 415 | free_sgn(f->u.sgn); 416 | f->u.sgn = NULL; 417 | break; 418 | case SQR: 419 | free_sqr(f->u.sqr); 420 | f->u.sqr = NULL; 421 | break; 422 | case INT_: 423 | free_int(f->u.int_); 424 | f->u.int_ = NULL; 425 | break; 426 | case VAR: 427 | free_var(f->u.v); 428 | f->u.v = NULL; 429 | break; 430 | case PI: 431 | free_pi(f->u.pi); 432 | f->u.pi = NULL; 433 | break; 434 | } 435 | free(f); 436 | } 437 | } 438 | -------------------------------------------------------------------------------- /src/prng.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include "prng.h" 26 | 27 | static unsigned long tcb_seed = 1; 28 | 29 | #define A 16807 30 | #define M 2147483647 31 | 32 | void tcb_randomize(void) { 33 | 34 | #if HAVE_CLOCK_GETTIME == 1 || HAVE_GETTIMEOFDAY == 1 35 | int rc; 36 | #endif 37 | 38 | #if HAVE_CLOCK_GETTIME == 1 39 | struct timespec ts; 40 | #endif 41 | 42 | #if HAVE_GETTIMEOFDAY == 1 43 | struct timeval tv; 44 | #endif 45 | 46 | tcb_srand((unsigned long) time(NULL)); 47 | 48 | #if HAVE_GETTIMEOFDAY == 1 49 | rc = gettimeofday(&tv, NULL); 50 | if (rc == 0) { 51 | tcb_srand(tv.tv_usec); 52 | } 53 | #endif 54 | 55 | #if HAVE_CLOCK_GETTIME == 1 56 | rc = clock_gettime(CLOCK_REALTIME, &ts); 57 | if (rc == 0) { 58 | tcb_srand(ts.tv_nsec); 59 | } 60 | #endif 61 | 62 | #if HAVE_ARC4RANDOM == 1 63 | tcb_srand(arc4random()); 64 | #endif 65 | } 66 | 67 | void tcb_srand(unsigned long seed) { 68 | tcb_seed = (seed == 0) ? 1 : seed; 69 | } 70 | 71 | float tcb_rand(void) { 72 | tcb_seed = (A * tcb_seed) % M; 73 | return tcb_seed / (float) M; 74 | } 75 | -------------------------------------------------------------------------------- /src/readaline.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "buffer.h" 29 | #include "readaline.h" 30 | 31 | /* 32 | * prints the prompt on the terminal only if standard input 33 | * is a terminal. Additionally, it reads stdin into buf until EOF or NL 34 | * 35 | * f from where to read input 36 | * prompt is the string to print to a terminal 37 | * buf is the buffer put characters 38 | * returns a pointer to the buffer 39 | * no error return value; any errors cause the program to exit 40 | */ 41 | Buffer *readaline(FILE *f, const char *prompt, Buffer *lbuf) { 42 | 43 | int fd, rc; 44 | 45 | bf_valid(lbuf); /* check for valid Buffer */ 46 | 47 | /* get the file descriptor number if standard input */ 48 | fd = fileno(f); 49 | if (fd == -1) { 50 | perror("fileno"); 51 | exit(1); 52 | } 53 | 54 | /* print the prompt on the terminal only if standard input 55 | is a terminal */ 56 | rc = isatty(fd); 57 | if (rc == 1 && prompt != NULL) { 58 | 59 | fprintf(stderr, "%s", prompt); 60 | fflush(stderr); 61 | } 62 | 63 | do { 64 | char ch; 65 | ch = (char) fgetc(f); 66 | if (ch == -1 || ch == '\n' || feof(f)) { 67 | 68 | /* work until error, EOF or a newline */ 69 | break; 70 | } 71 | 72 | /* put characters in the buffer */ 73 | bf_addch(lbuf, ch); 74 | 75 | } while (1); 76 | 77 | /* terminate the buffer with a NULL character when done */ 78 | bf_addch(lbuf, '\0'); 79 | 80 | return lbuf; 81 | } 82 | 83 | -------------------------------------------------------------------------------- /src/relop.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "tokenizer.h" 27 | 28 | #include "relop.h" 29 | 30 | struct relop *new_relop(int type) { 31 | 32 | struct relop *op; 33 | 34 | op = (struct relop *) malloc(sizeof(struct relop)); 35 | if (op == NULL) { 36 | perror("malloc"); 37 | exit(EXIT_FAILURE); 38 | } 39 | memset(op, '\0', sizeof(struct relop)); 40 | 41 | op->type = type; 42 | 43 | return op; 44 | } 45 | 46 | struct relop *parse_relop(struct tokenizer *t) { 47 | 48 | token_get(t); 49 | switch (t->token.type) { 50 | case LTEQ: 51 | return new_relop(LTEQ); 52 | case LTGT: 53 | return new_relop(LTGT); 54 | case LT: 55 | return new_relop(LT); 56 | case GTEQ: 57 | return new_relop(GTEQ); 58 | case GTLT: 59 | return new_relop(GTLT); 60 | case GT: 61 | return new_relop(GT); 62 | case EQ: 63 | return new_relop(EQ); 64 | default: 65 | token_unget(t); 66 | return NULL; 67 | } 68 | } 69 | 70 | void print_relop(struct relop *op) { 71 | 72 | if (op == NULL) { 73 | return; 74 | } 75 | 76 | switch (op->type) { 77 | case LTEQ: 78 | printf("<="); 79 | break; 80 | case LTGT: 81 | printf("<>"); 82 | break; 83 | case LT: 84 | printf("<"); 85 | break; 86 | case GTEQ: 87 | printf(">="); 88 | break; 89 | case GTLT: 90 | printf("><"); 91 | break; 92 | case GT: 93 | printf(">"); 94 | break; 95 | case EQ: 96 | printf("="); 97 | break; 98 | default: 99 | printf("?"); 100 | break; 101 | } 102 | } 103 | 104 | void free_relop(struct relop *op) { 105 | if (op != NULL) { 106 | free(op); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/rem.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "rem.h" 27 | 28 | #include "tokenizer.h" 29 | 30 | struct rem *new_rem(char *value) { 31 | 32 | struct rem *r; 33 | 34 | r = (struct rem *) malloc(sizeof(struct rem)); 35 | if (r == NULL) { 36 | perror("malloc"); 37 | exit(EXIT_FAILURE); 38 | } 39 | memset(r, '\0', sizeof(struct rem)); 40 | 41 | r->value = value; 42 | 43 | return r; 44 | } 45 | 46 | struct rem *parse_rem(struct tokenizer *t) { 47 | token_get(t); 48 | if (t->token.type == REM) { 49 | char *s = strdup(t->token.text); 50 | return new_rem(s); 51 | } else { 52 | token_unget(t); 53 | return NULL; 54 | } 55 | } 56 | 57 | void print_rem(struct rem *r) { 58 | if (r == NULL) { 59 | return; 60 | } 61 | 62 | printf("%s", r->value); 63 | } 64 | 65 | void free_rem(struct rem *r) { 66 | if (r != NULL) { 67 | if (r->value != NULL) { 68 | free(r->value); 69 | } 70 | free(r); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/rnd.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "prng.h" 27 | #include "tokenizer.h" 28 | 29 | #include "number.h" 30 | #include "rnd.h" 31 | 32 | struct rnd *new_rnd() { 33 | 34 | struct rnd *r; 35 | 36 | r = (struct rnd *) malloc(sizeof(struct rnd)); 37 | if (r == NULL) { 38 | perror("malloc"); 39 | exit(EXIT_FAILURE); 40 | } 41 | memset(r, '\0', sizeof(struct rnd)); 42 | 43 | return r; 44 | } 45 | 46 | struct rnd *parse_rnd(struct tokenizer *t) { 47 | 48 | token_get(t); 49 | if (t->token.type != RND) { 50 | token_unget(t); 51 | return NULL; 52 | } 53 | 54 | return new_rnd(); 55 | } 56 | 57 | struct number *eval_rnd(void) { 58 | return new_number_from_float(tcb_rand()); 59 | } 60 | 61 | void print_rnd(struct rnd *r) { 62 | if (r == NULL) { 63 | return; 64 | } 65 | 66 | printf("RND"); 67 | } 68 | 69 | void free_rnd(struct rnd *r) { 70 | if (r != NULL) { 71 | free(r); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/runtime.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "line.h" 28 | #include "number.h" 29 | #include "statement.h" 30 | #include "tokenizer.h" 31 | #include "var.h" 32 | 33 | #include "runtime.h" 34 | 35 | struct line *lines = NULL; 36 | 37 | struct line *runtime_get_first_line(void) { 38 | return lines; 39 | } 40 | 41 | struct line *runtime_get_line(int number) { 42 | struct line *cur; 43 | 44 | if (number <= 0) { 45 | return NULL; 46 | } 47 | 48 | for (cur = lines; cur != NULL; cur = cur->next) { 49 | if (number == cur->number) { 50 | return cur; 51 | } 52 | } 53 | 54 | return NULL; 55 | } 56 | 57 | int runtime_get_line_after_nearest_next(int for_line_number, char var) { 58 | 59 | struct line *cur; 60 | 61 | for (cur = runtime_get_line(for_line_number); cur != NULL; cur = cur->next) { 62 | if (cur->statement->type == NEXT && cur->statement->u.next_stmt.var->value == var) { 63 | return cur->next == NULL ? -1 : cur->next->number; 64 | } 65 | 66 | } 67 | 68 | return -1; 69 | 70 | } 71 | 72 | void runtime_rm_line(int number) { 73 | struct line *list = lines; 74 | struct line *head = list; 75 | struct line *cur = list; 76 | struct line *prev; 77 | 78 | if (number <= 0) { 79 | return; 80 | } 81 | 82 | if (head == NULL) { /* empty list */ 83 | /* nothing to do */; 84 | } else if (head->number == number) { /* first element in list */ 85 | head = head->next; 86 | cur->next = NULL; 87 | free_line(cur); 88 | } else { 89 | for (prev = cur, cur = cur->next; cur != NULL; prev = cur, cur = cur->next) { 90 | if (cur->number == number) { 91 | prev->next = cur->next; 92 | cur->next = NULL; 93 | free_line(cur); 94 | cur = prev; 95 | } 96 | } 97 | } 98 | 99 | lines = head; 100 | } 101 | 102 | void runtime_set_line(struct line *item) { 103 | struct line *list = lines; 104 | struct line *head = list; 105 | struct line *cur = list; 106 | 107 | if (item == NULL || item->number <= 0) { 108 | return; 109 | } 110 | 111 | if (head == NULL) { /* empty list, make item 1st element */ 112 | head = item; 113 | } else if (list->number > item->number) { /* item comes before list, make item 1st element */ 114 | item->next = head; 115 | head = item; 116 | } else if (list->number == item->number) { /* item replaces 1st element */ 117 | item->next = cur->next; 118 | head = item; 119 | cur->next = NULL; 120 | free_line(cur); 121 | } else { /* item comes after 1st element */ 122 | struct line *prev; 123 | 124 | for (prev = cur, cur = cur->next; cur != NULL; prev = cur, cur = cur->next) { 125 | if (cur->number == item->number) { /* item replaces current element */ 126 | prev->next = item; 127 | item->next = cur->next; 128 | cur->next = NULL; 129 | free_line(cur); 130 | break; 131 | } else if (prev->number < item->number && item->number < cur->number) { /* item goes between prev and cur */ 132 | prev->next = item; 133 | item->next = cur; 134 | break; 135 | } 136 | } 137 | if (cur == NULL) { /* insert at end of list */ 138 | prev->next = item; 139 | } 140 | } 141 | 142 | lines = head; 143 | } 144 | 145 | 146 | /* *** *** *** */ 147 | 148 | #define NVARS 26 149 | struct number *vars[NVARS] = { 150 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 151 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 152 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 153 | NULL, NULL 154 | }; 155 | 156 | void runtime_set_var(char var, struct number *value) { 157 | int i = (var - 'A') % NVARS; 158 | if (vars[i] != NULL) { 159 | free_number(vars[i]); 160 | } 161 | vars[(var - 'A') % NVARS] = clone_number(value); 162 | } 163 | 164 | struct number *runtime_get_var(char var) { 165 | return vars[(var - 'A') % NVARS]; 166 | } 167 | 168 | /* *** *** *** */ 169 | 170 | #define NFORSTATES 26 171 | struct for_state for_states[NFORSTATES] = { 172 | { NULL, NULL, 0 }, { NULL, NULL, 0 }, { NULL, NULL, 0 }, { NULL, NULL, 0 }, 173 | { NULL, NULL, 0 }, { NULL, NULL, 0 }, { NULL, NULL, 0 }, { NULL, NULL, 0 }, 174 | { NULL, NULL, 0 }, { NULL, NULL, 0 }, { NULL, NULL, 0 }, { NULL, NULL, 0 }, 175 | { NULL, NULL, 0 }, { NULL, NULL, 0 }, { NULL, NULL, 0 }, { NULL, NULL, 0 }, 176 | { NULL, NULL, 0 }, { NULL, NULL, 0 }, { NULL, NULL, 0 }, { NULL, NULL, 0 }, 177 | { NULL, NULL, 0 }, { NULL, NULL, 0 }, { NULL, NULL, 0 }, { NULL, NULL, 0 }, 178 | { NULL, NULL, 0 }, { NULL, NULL, 0 } 179 | }; 180 | 181 | void runtime_set_for_state(char var, struct number *limit, struct number *step, int target) { 182 | int i = (var - 'A') % NFORSTATES; 183 | 184 | free_number(for_states[i].limit); 185 | for_states[i].limit = NULL; 186 | free_number(for_states[i].step); 187 | for_states[i].step = NULL; 188 | 189 | for_states[i].limit = clone_number(limit); 190 | for_states[i].step = clone_number(step); 191 | for_states[i].target = target; 192 | } 193 | 194 | struct for_state *runtime_get_for_state(char var) { 195 | return &for_states[(var - 'A') % NFORSTATES]; 196 | } 197 | 198 | /* *** *** *** */ 199 | 200 | int done = 0; 201 | 202 | void runtime_stop(void) { 203 | done = 1; 204 | } 205 | 206 | int runtime_continue(void) { 207 | return !done; 208 | } 209 | 210 | /* *** *** *** */ 211 | 212 | static int trace = 0; 213 | 214 | void runtime_trace_on(void) { 215 | trace = 1; 216 | } 217 | 218 | void runtime_trace_off(void) { 219 | trace = 0; 220 | } 221 | 222 | int runtime_is_tracing(void) { 223 | return trace; 224 | } 225 | 226 | /* *** *** *** */ 227 | 228 | struct stack *call_stack = NULL; 229 | 230 | struct stack { 231 | int val; 232 | struct stack *next; 233 | }; 234 | 235 | void runtime_callstack_push(int val) { 236 | struct stack *s; 237 | s = (struct stack *) malloc(sizeof(struct stack)); 238 | if (s == NULL) { 239 | perror("malloc"); 240 | exit(EXIT_FAILURE); 241 | } 242 | memset(s, '\0', sizeof(struct stack)); 243 | 244 | s->val = val; 245 | s->next = call_stack; 246 | 247 | call_stack = s; 248 | } 249 | 250 | int runtime_callstack_pop() { 251 | 252 | struct stack *old; 253 | int val; 254 | 255 | if (call_stack == NULL) { 256 | return -3; 257 | } 258 | 259 | val = call_stack->val; 260 | old = call_stack; 261 | call_stack = call_stack->next; 262 | free(old); 263 | 264 | return val; 265 | } 266 | 267 | /* *** *** *** */ 268 | 269 | void runtime_reset(void) { 270 | int i; 271 | for (i = 0; i < NVARS; i++) { 272 | free_number(vars[i]); 273 | vars[i] = NULL; 274 | } 275 | 276 | for (i = 0; i < NFORSTATES; i++) { 277 | free_number(for_states[i].limit); 278 | for_states[i].limit = NULL; 279 | free_number(for_states[i].step); 280 | for_states[i].step = NULL; 281 | for_states[i].target = 0; 282 | } 283 | 284 | if (lines != NULL) { 285 | free_line(lines); 286 | lines = NULL; 287 | } 288 | while (runtime_callstack_pop() != -3) { 289 | /* do nothing */; 290 | } 291 | } 292 | 293 | /* *** *** *** */ 294 | 295 | 296 | -------------------------------------------------------------------------------- /src/sgn.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "tokenizer.h" 28 | 29 | #include "sgn.h" 30 | #include "expression.h" 31 | #include "number.h" 32 | 33 | struct sgn *new_sgn(struct expression *e) { 34 | 35 | struct sgn *a; 36 | 37 | a = (struct sgn *) malloc(sizeof(struct sgn)); 38 | if (a == NULL) { 39 | perror("malloc"); 40 | exit(EXIT_FAILURE); 41 | } 42 | memset(a, '\0', sizeof(struct sgn)); 43 | 44 | a->e = e; 45 | 46 | return a; 47 | } 48 | 49 | struct sgn *parse_sgn(struct tokenizer *t) { 50 | 51 | struct expression *e; 52 | 53 | token_get(t); 54 | if (t->token.type != SGN) { 55 | token_unget(t); 56 | return NULL; 57 | } 58 | 59 | token_get(t); 60 | if (t->token.type != OPAREN) { 61 | token_unget(t); 62 | return NULL; 63 | } 64 | 65 | e = parse_expression(t); 66 | if (e == NULL) { 67 | return NULL; 68 | } 69 | 70 | token_get(t); 71 | if (t->token.type != CPAREN) { 72 | token_unget(t); 73 | free_expression(e); 74 | return NULL; 75 | } 76 | 77 | return new_sgn(e); 78 | } 79 | 80 | struct number *eval_sgn(struct sgn *a) { 81 | int r; 82 | struct number *n; 83 | 84 | r = 0; 85 | n = eval_expression(a->e); 86 | if (n->type == INT) { 87 | if (n->value.ival > 0) { 88 | r = 1; 89 | } else if (n->value.ival < 0) { 90 | r = -1; 91 | } 92 | } else { /* float */ 93 | if (n->value.fval > 0.0) { 94 | r = 1; 95 | } else if (n->value.fval < 0.0) { 96 | r = -1; 97 | } 98 | } 99 | 100 | n->value.ival = r; 101 | n->type = INT; /* cast to int */ 102 | 103 | return n; 104 | } 105 | 106 | void print_sgn(struct sgn *a) { 107 | if (a == NULL) { 108 | return; 109 | } 110 | 111 | printf("SGN ("); 112 | print_expression(a->e); 113 | printf(")"); 114 | } 115 | 116 | void free_sgn(struct sgn *a) { 117 | 118 | if (a != NULL) { 119 | if (a->e != NULL) { 120 | free_expression(a->e); 121 | a->e = NULL; 122 | } 123 | free(a); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/shell.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "shell.h" 28 | 29 | int doshell(char *cmd) { 30 | 31 | int wstatus; 32 | pid_t pid; 33 | 34 | pid = fork(); 35 | if (pid < 0) { 36 | return -1; 37 | } else if (pid == 0) { 38 | execl("/bin/sh", "sh", "-c", cmd, NULL); 39 | exit(EXIT_FAILURE); 40 | } 41 | 42 | waitpid(pid, &wstatus, 0); 43 | 44 | return WEXITSTATUS(wstatus); 45 | } 46 | 47 | -------------------------------------------------------------------------------- /src/sin.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "tokenizer.h" 28 | 29 | #include "sin.h" 30 | #include "expression.h" 31 | #include "number.h" 32 | 33 | struct sin *new_sin(struct expression *e) { 34 | 35 | struct sin *s; 36 | 37 | s = (struct sin *) malloc(sizeof(struct sin)); 38 | if (s == NULL) { 39 | perror("malloc"); 40 | exit(EXIT_FAILURE); 41 | } 42 | memset(s, '\0', sizeof(struct sin)); 43 | 44 | s->e = e; 45 | 46 | return s; 47 | } 48 | 49 | struct sin *parse_sin(struct tokenizer *t) { 50 | 51 | struct expression *e; 52 | 53 | token_get(t); 54 | if (t->token.type != SIN) { 55 | token_unget(t); 56 | return NULL; 57 | } 58 | 59 | token_get(t); 60 | if (t->token.type != OPAREN) { 61 | token_unget(t); 62 | return NULL; 63 | } 64 | 65 | e = parse_expression(t); 66 | if (e == NULL) { 67 | return NULL; 68 | } 69 | 70 | token_get(t); 71 | if (t->token.type != CPAREN) { 72 | token_unget(t); 73 | free_expression(e); 74 | return NULL; 75 | } 76 | 77 | return new_sin(e); 78 | } 79 | 80 | struct number *eval_sin(struct sin *s) { 81 | struct number *n; 82 | 83 | n = eval_expression(s->e); 84 | if (n->type == INT) { 85 | float f; 86 | f = sinf((1.0f) * n->value.ival); 87 | n->type = FLOAT; 88 | n->value.fval = f; 89 | } else { /* float */ 90 | n->value.fval = sinf(n->value.fval); 91 | } 92 | 93 | return n; 94 | } 95 | 96 | void print_sin(struct sin *s) { 97 | if (s == NULL) { 98 | return; 99 | } 100 | 101 | printf("SIN ("); 102 | print_expression(s->e); 103 | printf(")"); 104 | } 105 | 106 | void free_sin(struct sin *s) { 107 | 108 | if (s != NULL) { 109 | if (s->e != NULL) { 110 | free_expression(s->e); 111 | s->e = NULL; 112 | } 113 | free(s); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/sqr.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "tokenizer.h" 28 | 29 | #include "sqr.h" 30 | #include "expression.h" 31 | #include "number.h" 32 | 33 | struct sqr *new_sqr(struct expression *e) { 34 | 35 | struct sqr *s; 36 | 37 | s = (struct sqr *) malloc(sizeof(struct sqr)); 38 | if (s == NULL) { 39 | perror("malloc"); 40 | exit(EXIT_FAILURE); 41 | } 42 | memset(s, '\0', sizeof(struct sqr)); 43 | 44 | s->e = e; 45 | 46 | return s; 47 | } 48 | 49 | struct sqr *parse_sqr(struct tokenizer *t) { 50 | 51 | struct expression *e; 52 | 53 | token_get(t); 54 | if (t->token.type != SQR) { 55 | token_unget(t); 56 | return NULL; 57 | } 58 | 59 | token_get(t); 60 | if (t->token.type != OPAREN) { 61 | token_unget(t); 62 | return NULL; 63 | } 64 | 65 | e = parse_expression(t); 66 | if (e == NULL) { 67 | return NULL; 68 | } 69 | 70 | token_get(t); 71 | if (t->token.type != CPAREN) { 72 | token_unget(t); 73 | free_expression(e); 74 | return NULL; 75 | } 76 | 77 | return new_sqr(e); 78 | } 79 | 80 | struct number *eval_sqr(struct sqr *s) { 81 | struct number *n; 82 | 83 | n = eval_expression(s->e); 84 | if (n->type == INT) { 85 | float f; 86 | f = sqrtf((1.0f) * n->value.ival); 87 | n->type = FLOAT; 88 | n->value.fval = f; 89 | } else { /* float */ 90 | n->value.fval = sqrtf(n->value.fval); 91 | } 92 | 93 | return n; 94 | } 95 | 96 | void print_sqr(struct sqr *s) { 97 | if (s == NULL) { 98 | return; 99 | } 100 | 101 | printf("SQR ("); 102 | print_expression(s->e); 103 | printf(")"); 104 | } 105 | 106 | void free_sqr(struct sqr *s) { 107 | 108 | if (s != NULL) { 109 | if (s->e != NULL) { 110 | free_expression(s->e); 111 | s->e = NULL; 112 | } 113 | free(s); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/str.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "str.h" 27 | 28 | #include "tokenizer.h" 29 | 30 | struct str *new_str(char *value) { 31 | 32 | struct str *s; 33 | 34 | s = (struct str *) malloc(sizeof(struct str)); 35 | if (s == NULL) { 36 | perror("malloc"); 37 | exit(EXIT_FAILURE); 38 | } 39 | memset(s, '\0', sizeof(struct str)); 40 | 41 | s->value = value; 42 | 43 | return s; 44 | } 45 | 46 | struct str *parse_str(struct tokenizer *t) { 47 | token_get(t); 48 | if (t->token.type == STR) { 49 | size_t len = strlen(t->token.text+1); 50 | char *s = strdup(t->token.text+1); 51 | s[len - 1] = '\0'; /* chomp ending double quote */ 52 | return new_str(s); 53 | } else { 54 | token_unget(t); 55 | return NULL; 56 | } 57 | } 58 | 59 | char *eval_str(struct str *s) { 60 | if (s == NULL) { 61 | return NULL; 62 | } 63 | 64 | return s->value; 65 | } 66 | 67 | void print_str(struct str *s) { 68 | if (s == NULL) { 69 | return; 70 | } 71 | 72 | printf("\"%s\"", s->value); 73 | } 74 | 75 | void free_str(struct str *s) { 76 | if (s != NULL) { 77 | if (s->value != NULL) { 78 | free(s->value); 79 | } 80 | free(s); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/tan.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "tokenizer.h" 28 | 29 | #include "tan.h" 30 | #include "expression.h" 31 | #include "number.h" 32 | 33 | struct tan *new_tan(struct expression *e) { 34 | 35 | struct tan *t; 36 | 37 | t = (struct tan *) malloc(sizeof(struct tan)); 38 | if (t == NULL) { 39 | perror("malloc"); 40 | exit(EXIT_FAILURE); 41 | } 42 | memset(t, '\0', sizeof(struct tan)); 43 | 44 | t->e = e; 45 | 46 | return t; 47 | } 48 | 49 | struct tan *parse_tan(struct tokenizer *t) { 50 | 51 | struct expression *e; 52 | 53 | token_get(t); 54 | if (t->token.type != TAN) { 55 | token_unget(t); 56 | return NULL; 57 | } 58 | 59 | token_get(t); 60 | if (t->token.type != OPAREN) { 61 | token_unget(t); 62 | return NULL; 63 | } 64 | 65 | e = parse_expression(t); 66 | if (e == NULL) { 67 | return NULL; 68 | } 69 | 70 | token_get(t); 71 | if (t->token.type != CPAREN) { 72 | token_unget(t); 73 | free_expression(e); 74 | return NULL; 75 | } 76 | 77 | return new_tan(e); 78 | } 79 | 80 | struct number *eval_tan(struct tan *t) { 81 | struct number *n; 82 | 83 | n = eval_expression(t->e); 84 | if (n->type == INT) { 85 | float f; 86 | f = tanf((1.0f) * n->value.ival); 87 | n->type = FLOAT; 88 | n->value.fval = f; 89 | } else { /* float */ 90 | n->value.fval = tanf(n->value.fval); 91 | } 92 | 93 | return n; 94 | } 95 | 96 | void print_tan(struct tan *t) { 97 | if (t == NULL) { 98 | return; 99 | } 100 | 101 | printf("TAN ("); 102 | print_expression(t->e); 103 | printf(")"); 104 | } 105 | 106 | void free_tan(struct tan *t) { 107 | 108 | if (t != NULL) { 109 | if (t->e != NULL) { 110 | free_expression(t->e); 111 | t->e = NULL; 112 | } 113 | free(t); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/term.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "tokenizer.h" 27 | 28 | #include "factor.h" 29 | #include "mulop.h" 30 | #include "number.h" 31 | #include "term.h" 32 | 33 | struct term *new_term(struct factor *left, struct mulop *op, struct factor *right) { 34 | 35 | struct term *t; 36 | 37 | t = (struct term *) malloc(sizeof(struct term)); 38 | if (t == NULL) { 39 | perror("malloc"); 40 | exit(EXIT_FAILURE); 41 | } 42 | memset(t, '\0', sizeof(struct term)); 43 | 44 | t->left = left; 45 | t->op = op; 46 | t->right = right; 47 | 48 | return t; 49 | } 50 | 51 | struct term *parse_term(struct tokenizer *t) { 52 | struct factor *f1; 53 | struct mulop *op; 54 | struct factor *f2; 55 | 56 | f1 = parse_factor(t); 57 | if (f1 == NULL) { 58 | return NULL; 59 | } 60 | 61 | op = parse_mulop(t); 62 | if (op == NULL) { 63 | return new_term(f1, NULL, NULL); 64 | } 65 | 66 | f2 = parse_factor(t); 67 | if (f2 == NULL) { 68 | free_factor(f1); 69 | free_mulop(op); 70 | return NULL; 71 | } 72 | 73 | return new_term(f1, op, f2); 74 | } 75 | 76 | struct number * eval_term(struct term *t) { 77 | 78 | struct number *l; 79 | struct number *r; 80 | struct number *result; 81 | 82 | if (t == NULL) { 83 | return new_number_from_int(0); 84 | } 85 | 86 | l = eval_factor(t->left); 87 | r = eval_factor(t->right); 88 | 89 | if (t->op != NULL && t->op->type == DIVIDE) { 90 | result = divide_number(l, r); 91 | } else if (t->op != NULL && t->op->type == IDIVIDE) { 92 | result = idivide_number(l, r); 93 | } else if (t->op != NULL && t->op->type == MOD) { 94 | result = modulus_number(l, r); 95 | } else { 96 | result = multiply_number(l, r); 97 | } 98 | 99 | free_number(l); 100 | free_number(r); 101 | 102 | return result; 103 | } 104 | 105 | void print_term(struct term *t) { 106 | 107 | if (t == NULL) { 108 | return; 109 | } 110 | 111 | print_factor(t->left); 112 | if (t->op != NULL) { 113 | printf(" "); 114 | print_mulop(t->op); 115 | printf(" "); 116 | print_factor(t->right); 117 | } 118 | } 119 | 120 | void free_term(struct term *t) { 121 | if (t != NULL) { 122 | free_factor(t->left); 123 | free_mulop(t->op); 124 | free_factor(t->right); 125 | free(t); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/time_.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "tokenizer.h" 28 | 29 | #include "number.h" 30 | #include "time_.h" 31 | 32 | struct time *new_time(void) { 33 | 34 | struct time *t; 35 | 36 | t = (struct time *) malloc(sizeof(struct time)); 37 | if (t == NULL) { 38 | perror("malloc"); 39 | exit(EXIT_FAILURE); 40 | } 41 | memset(t, '\0', sizeof(struct time)); 42 | 43 | return t; 44 | } 45 | 46 | struct time *parse_time(struct tokenizer *t) { 47 | 48 | token_get(t); 49 | if (t->token.type != TIME) { 50 | token_unget(t); 51 | return NULL; 52 | } 53 | 54 | return new_time(); 55 | } 56 | 57 | struct number *eval_time(void) { 58 | 59 | /* 60 | * computes seconds since midnight 61 | * this should work correctly even on days where the time changes to/from daylight savings time 62 | */ 63 | 64 | struct tm t; 65 | time_t now; 66 | time_t midnight; 67 | 68 | time(&now); /* get current time */ 69 | t = *localtime_r(&now, &t); 70 | 71 | t.tm_hour = 0; /* rewind to midnight */ 72 | t.tm_min = 0; 73 | t.tm_sec = 0; 74 | 75 | midnight = mktime(&t); /* get unix timestamp for midnight today */ 76 | 77 | return new_number_from_int(now - midnight); 78 | } 79 | 80 | void print_time(struct time *t) { 81 | if (t == NULL) { 82 | return; 83 | } 84 | 85 | printf("TIME"); 86 | } 87 | 88 | void free_time(struct time *t) { 89 | if (t != NULL) { 90 | free(t); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/tokenizer.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "tokenizer.h" 27 | 28 | struct token_info { 29 | const char *regex_text; 30 | enum token_types type; 31 | }; 32 | 33 | struct token_info token_defs[] = { 34 | { "^PRINT", PRINT }, 35 | { "^IF", IF }, 36 | { "^THEN", THEN }, 37 | { "^GO[ \t\f\r\n]*TO", GOTO }, 38 | { "^INPUT", INPUT }, 39 | { "^LET", LET }, 40 | { "^GO[ \t\f\r\n]*SUB", GOSUB }, 41 | { "^RETURN", RETURN }, 42 | { "^SHELL", SHELL }, 43 | { "^BEEP", BEEP }, 44 | { "^END", END }, 45 | { "^REM.*$", REM }, 46 | { "^RANDOMIZE", RANDOMIZE }, 47 | { "^CLS", CLS }, 48 | { "^CLEAR", CLEAR }, 49 | { "^LIST", LIST }, 50 | { "^RENUM", RENUM }, 51 | { "^RUN", RUN }, 52 | { "^STOP", STOP }, 53 | { "^TROFF", TROFF }, 54 | { "^TRON", TRON }, 55 | { "^RND", RND }, 56 | { "^TIME", TIME }, 57 | { "^SIN", SIN }, 58 | { "^COS", COS }, 59 | { "^TAN", TAN }, 60 | { "^COT", COT }, 61 | { "^ATN", ATN }, 62 | { "^EXP", EXP }, 63 | { "^LOG", LOG }, 64 | { "^ABS", ABS }, 65 | { "^SGN", SGN }, 66 | { "^SQR", SQR }, 67 | { "^INT", INT_ }, 68 | { "^FOR", FOR }, 69 | { "^TO", TO }, 70 | { "^STEP", STEP }, 71 | { "^NEXT", NEXT }, 72 | { "^<=", LTEQ }, 73 | { "^<>", LTGT }, 74 | { "^<", LT }, 75 | { "^>=", GTEQ }, 76 | { "^><", GTLT }, 77 | { "^>", GT }, 78 | { "^=", EQ }, 79 | { "^\\+", PLUS }, 80 | { "^\\-", MINUS }, 81 | { "^\\*", TIMES }, 82 | { "^\\/", DIVIDE }, 83 | { "^\\\\", IDIVIDE }, 84 | { "^MOD", MOD }, 85 | { "^,", COMMA }, 86 | { "^\\^", CIRCUMFLEX }, 87 | { "^\\(", OPAREN }, 88 | { "^\\)", CPAREN }, 89 | { "^\"[^\"]*\"", STR }, 90 | { "^[A-Z]", VAR }, 91 | { "^π", PI }, 92 | { "^(([0-9]+|([0-9]*\\.[0-9]*))([eE][-+]?[0-9]+)?)", NUMBER }, 93 | { "^[ \t\f\r\n]+", SPACE } 94 | }; 95 | #define NTOKEN_TYPES (sizeof(token_defs)/sizeof(token_defs[0])) 96 | 97 | regex_t regexes[NTOKEN_TYPES]; 98 | 99 | static struct token nextToken(char **s) { 100 | size_t i; 101 | size_t len; 102 | struct token t; 103 | int rc; 104 | regmatch_t matches[1]; 105 | 106 | t.type = INVALID; 107 | t.text = NULL; 108 | 109 | do { 110 | if (s == NULL || *s == NULL) { 111 | t.type = INVALID; 112 | return t; 113 | } else if (*s[0] == '\0' || strlen(*s) == 0) { 114 | t.type = EOS; 115 | return t; 116 | } 117 | if (t.text != NULL) { /* free space token */ 118 | free(t.text); 119 | t.text = NULL; 120 | } 121 | for (i = 0; i < NTOKEN_TYPES; i++) { 122 | rc = regexec(®exes[i], *s, 1, matches, 0); 123 | if (rc == 0) { 124 | len = (size_t) (matches[0].rm_eo - matches[0].rm_so); 125 | t.type = token_defs[i].type; 126 | t.text = (char *) malloc(len + 1); 127 | if (t.text == NULL) { 128 | perror("malloc"); 129 | exit(EXIT_FAILURE); 130 | } 131 | strncpy(t.text, *s, len); 132 | t.text[len] = '\0'; 133 | *s += len; 134 | break; 135 | } 136 | } 137 | } while (t.type == SPACE); 138 | return t; 139 | } 140 | 141 | void token_get(struct tokenizer *t) { 142 | if (t == NULL) { 143 | return; 144 | } else if (t->token.text != NULL) { 145 | free(t->token.text); 146 | t->token.text = NULL; 147 | } 148 | t->token = nextToken(t->s); 149 | } 150 | 151 | void token_unget(struct tokenizer *t) { 152 | char *s; 153 | if (t->token.text == NULL) { 154 | return; 155 | } 156 | s = *(t->s); 157 | s -= strlen(t->token.text); 158 | *(t->s) = s; 159 | t->token.type = INVALID; 160 | free(t->token.text); 161 | t->token.text = NULL; 162 | } 163 | 164 | 165 | void tokenizer_init() { 166 | size_t i; 167 | for (i = 0; i < NTOKEN_TYPES; i++) { 168 | regcomp(®exes[i], token_defs[i].regex_text, REG_EXTENDED|REG_ICASE); 169 | } 170 | } 171 | 172 | void tokenizer_exit() { 173 | size_t i; 174 | for (i = 0; i < NTOKEN_TYPES; i++) { 175 | regfree(®exes[i]); 176 | } 177 | } 178 | 179 | -------------------------------------------------------------------------------- /src/var.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "runtime.h" 27 | #include "tokenizer.h" 28 | 29 | #include "number.h" 30 | #include "var.h" 31 | 32 | struct var *new_var(char value) { 33 | 34 | struct var *v; 35 | 36 | v = (struct var *) malloc(sizeof(struct var)); 37 | if (v == NULL) { 38 | perror("malloc"); 39 | exit(EXIT_FAILURE); 40 | } 41 | memset(v, '\0', sizeof(struct var)); 42 | 43 | v->value = value; 44 | 45 | return v; 46 | } 47 | 48 | struct var *parse_var(struct tokenizer *t) { 49 | 50 | token_get(t); 51 | switch (t->token.type) { 52 | case VAR: 53 | return new_var(t->token.text[0]); 54 | default: 55 | token_unget(t); 56 | return NULL; 57 | } 58 | } 59 | 60 | struct number *eval_var(struct var *v) { 61 | if (v == NULL) { 62 | return 0; 63 | } 64 | 65 | return clone_number(runtime_get_var(v->value)); 66 | } 67 | 68 | void print_var(struct var *v) { 69 | if (v == NULL) { 70 | return; 71 | } 72 | 73 | printf("%c", v->value); 74 | } 75 | 76 | void free_var(struct var *v) { 77 | if (v != NULL) { 78 | free(v); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/var_list.c: -------------------------------------------------------------------------------- 1 | /* 2 | tcbasic - a small BASIC Interpreter written in C. 3 | Copyright (C) 2015, 2016, 2017, 2018, 2020 Thomas Cort 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program. If not, see . 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "eval.h" 27 | #include "tokenizer.h" 28 | 29 | #include "var_list.h" 30 | #include "var.h" 31 | 32 | struct var_list *new_var_list(struct var *var, struct var_list *list) { 33 | 34 | struct var_list *vl; 35 | 36 | vl = (struct var_list *) malloc(sizeof(struct var_list)); 37 | if (vl == NULL) { 38 | perror("malloc"); 39 | exit(EXIT_FAILURE); 40 | } 41 | memset(vl, '\0', sizeof(struct var_list)); 42 | 43 | vl->var = var; 44 | vl->list = list; 45 | 46 | return vl; 47 | } 48 | 49 | struct var_list *parse_var_list(struct tokenizer *t) { 50 | 51 | struct var *v; 52 | 53 | v = parse_var(t); 54 | if (v == NULL) { 55 | return NULL; 56 | } 57 | 58 | token_get(t); 59 | if (t->token.type == COMMA) { 60 | return new_var_list(v, parse_var_list(t)); 61 | } else { 62 | token_unget(t); 63 | return new_var_list(v, NULL); 64 | } 65 | } 66 | 67 | void eval_var_list(struct var_list *vl, char *line) { 68 | char *let; 69 | struct var_list *cur; 70 | size_t len; 71 | 72 | if (vl == NULL || line == NULL) { 73 | return; 74 | } 75 | 76 | len = strlen("LET X = ") + strlen(line) + 8; 77 | let = (char *) malloc(len*sizeof(char)); 78 | if (let == NULL) { 79 | perror("malloc"); 80 | exit(EXIT_FAILURE); 81 | } 82 | 83 | for (cur = vl; cur != NULL; cur = cur->list) { 84 | char *s; 85 | struct var *v; 86 | v = cur->var; 87 | s = strsep(&line, ","); 88 | snprintf(let, len, "LET %c = %s", v->value, (s != NULL) ? s : "0"); 89 | eval(let); 90 | } 91 | 92 | free(let); 93 | let = NULL; 94 | } 95 | 96 | void print_var_list(struct var_list *vl) { 97 | 98 | if (vl == NULL) { 99 | return; 100 | } 101 | 102 | print_var(vl->var); 103 | if (vl->list != NULL) { 104 | printf(", "); 105 | print_var_list(vl->list); 106 | } 107 | } 108 | 109 | void free_var_list(struct var_list *vl) { 110 | if (vl != NULL) { 111 | free_var(vl->var); 112 | free_var_list(vl->list); 113 | free(vl); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /tests/abs.bas: -------------------------------------------------------------------------------- 1 | 10 LET A = 23 2 | 20 GOSUB 1000 3 | 30 PRINT A 4 | 40 LET A = -23 5 | 50 GOSUB 1000 6 | 60 PRINT A 7 | 70 END 8 | 1000 IF A < 0 THEN LET A = -A 9 | 1010 RETURN 10 | -------------------------------------------------------------------------------- /tests/abs.ex: -------------------------------------------------------------------------------- 1 | 23 2 | 23 3 | -------------------------------------------------------------------------------- /tests/coinflip.bas: -------------------------------------------------------------------------------- 1 | 10 LET C = RND 2 | 20 IF C < 0.5 THEN PRINT "HEADS" 3 | 30 IF C >= 0.5 THEN PRINT "TAILS" 4 | -------------------------------------------------------------------------------- /tests/coinflip.ex: -------------------------------------------------------------------------------- 1 | HEADS 2 | -------------------------------------------------------------------------------- /tests/division.bas: -------------------------------------------------------------------------------- 1 | 10 LET X = 12.34 2 | 20 LET Y = 4.00 3 | 30 PRINT X/Y 4 | 40 PRINT X\Y 5 | -------------------------------------------------------------------------------- /tests/division.ex: -------------------------------------------------------------------------------- 1 | 3.085000 2 | 3 3 | -------------------------------------------------------------------------------- /tests/fib.bas: -------------------------------------------------------------------------------- 1 | 10 LET A = 1 2 | 20 LET B = 1 3 | 40 LET I = 2 4 | 50 GOSUB 1000 5 | 60 PRINT C 6 | 100 LET A = 1 7 | 110 LET B = 1 8 | 120 FOR I = 1 TO 10 9 | 130 LET C = A + B 10 | 140 LET T = B 11 | 150 LET B = C 12 | 160 LET A = T 13 | 200 NEXT I 14 | 250 PRINT C 15 | 300 END 16 | 1000 LET C = B + A 17 | 1010 LET T = B 18 | 1020 LET B = C 19 | 1030 LET A = T 20 | 1040 LET I = I + 1 21 | 1050 IF I = 12 THEN RETURN 22 | 1060 GOTO 1000 23 | -------------------------------------------------------------------------------- /tests/fib.ex: -------------------------------------------------------------------------------- 1 | 144 2 | 144 3 | -------------------------------------------------------------------------------- /tests/for.bas: -------------------------------------------------------------------------------- 1 | 10 LET A = 0 2 | 20 FOR I = 1 TO 100 3 | 30 LET A = A + I 4 | 40 NEXT I 5 | 50 PRINT A 6 | 60 LET N = 100 7 | 70 LET B = (N * (N + 1)) / 2 8 | 80 PRINT B 9 | 100 FOR I = 0 TO (5+5) STEP 1+1 10 | 150 PRINT I 11 | 200 NEXT I 12 | 500 FOR I = 10 TO 1 STEP -1 13 | 555 PRINT I 14 | 600 NEXT I 15 | 900 END 16 | -------------------------------------------------------------------------------- /tests/for.ex: -------------------------------------------------------------------------------- 1 | 5050 2 | 5050 3 | 0 4 | 2 5 | 4 6 | 6 7 | 8 8 | 10 9 | 10 10 | 9 11 | 8 12 | 7 13 | 6 14 | 5 15 | 4 16 | 3 17 | 2 18 | 1 19 | -------------------------------------------------------------------------------- /tests/functions.bas: -------------------------------------------------------------------------------- 1 | 10 REM Test each function: SIN, COS, TAN, COT, ATN, EXP, LOG, ABS, SQR, 2 | 3 | 100 REM SIN 4 | 110 LET A = SIN((0*3.1415926)/2) 5 | 120 LET B = SIN((1*3.1415926)/2) 6 | 130 LET C = SIN((2*3.1415926)/2) 7 | 140 LET D = SIN((3*3.1415926)/2) 8 | 190 GOSUB 1000 9 | 10 | 200 REM COS 11 | 210 LET A = COS((0*3.1415926)/2) 12 | 220 LET B = COS((1*3.1415926)/2) 13 | 230 LET C = COS((2*3.1415926)/2) 14 | 240 LET D = COS((3*3.1415926)/2) 15 | 290 GOSUB 1000 16 | 17 | 300 REM TAN 18 | 310 LET A = TAN(3) 19 | 320 LET B = TAN(-3) 20 | 330 LET C = TAN(1.0) 21 | 340 LET D = TAN(-1.0) 22 | 390 GOSUB 1000 23 | 24 | 400 REM COT 25 | 410 LET A = COT(0.01) 26 | 420 LET B = COT(-0.01) 27 | 430 LET C = COT(1) 28 | 440 LET D = COT(-1) 29 | 490 GOSUB 1000 30 | 31 | 500 REM ATN 32 | 510 LET A = ATN(123) 33 | 520 LET B = ATN(-123) 34 | 530 LET C = ATN(1.0) 35 | 540 LET D = ATN(-1.0) 36 | 590 GOSUB 1000 37 | 38 | 600 REM EXP 39 | 610 LET A = EXP(2.0) 40 | 620 LET B = EXP(0) 41 | 630 LET C = EXP(-1) 42 | 640 LET D = EXP(1) 43 | 690 GOSUB 1000 44 | 45 | 700 REM LOG 46 | 710 LET A = LOG(1) 47 | 720 LET B = LOG(2) 48 | 730 LET C = LOG(3.0) 49 | 740 LET D = LOG(4) 50 | 790 GOSUB 1000 51 | 52 | 800 REM ABS 53 | 810 LET A = ABS(4) 54 | 820 LET B = ABS(-2) 55 | 830 LET C = ABS(4.0) 56 | 840 LET D = ABS(-2.0) 57 | 890 GOSUB 1000 58 | 59 | 900 REM SQR 60 | 910 LET A = SQR(4) 61 | 920 LET B = SQR(2) 62 | 930 LET C = SQR(4.0) 63 | 940 LET D = SQR(2.0) 64 | 990 GOSUB 1000 65 | 66 | 999 GOTO 9999 67 | 68 | 1000 REM PRINT A,B,C,D 69 | 1001 PRINT A,",",B,",",C,",",D 70 | 1002 RETURN 71 | 72 | 9999 END 73 | -------------------------------------------------------------------------------- /tests/functions.ex: -------------------------------------------------------------------------------- 1 | 0.000000,1.000000,0.000000,-1.000000 2 | 1.000000,0.000000,-1.000000,0.000000 3 | -0.142547,0.142547,1.557408,-1.557408 4 | 99.996666,-99.996666,0.642093,-0.642093 5 | 1.562666,-1.562666,0.785398,-0.785398 6 | 7.389056,1.000000,0.367879,2.718282 7 | 0.000000,0.693147,1.098612,1.386294 8 | 4,2,4.000000,2.000000 9 | 2.000000,1.414214,2.000000,1.414214 10 | -------------------------------------------------------------------------------- /tests/hello.bas: -------------------------------------------------------------------------------- 1 | 10 PRINT "Hello" 2 | 20 END 3 | -------------------------------------------------------------------------------- /tests/hello.ex: -------------------------------------------------------------------------------- 1 | Hello 2 | -------------------------------------------------------------------------------- /tests/int_.bas: -------------------------------------------------------------------------------- 1 | PRINT INT(-2.0) 2 | PRINT INT(-1.999) 3 | PRINT INT(-1.1) 4 | PRINT INT(-1) 5 | PRINT INT(-0.9254) 6 | PRINT INT(0.999999) 7 | PRINT INT(9.999999) 8 | PRINT INT(10 + 0.0) 9 | PRINT INT(10.00001) 10 | PRINT INT(10.2) 11 | PRINT INT(10.99999) 12 | PRINT INT(11) 13 | -------------------------------------------------------------------------------- /tests/int_.ex: -------------------------------------------------------------------------------- 1 | -2 2 | -1 3 | -1 4 | -1 5 | 0 6 | 0 7 | 9 8 | 10 9 | 10 10 | 10 11 | 10 12 | 11 13 | -------------------------------------------------------------------------------- /tests/mod.bas: -------------------------------------------------------------------------------- 1 | 10 PRINT "96 MOD 10 = ",96 MOD 10 2 | 20 PRINT "9.6 MOD 5 = ",9.6 MOD 5 3 | 30 PRINT "10 MOD 4.8 = ",10 MOD 4.8 4 | 40 PRINT "2.2 MOD 1.1 = ",2.2 MOD 1.1 5 | -------------------------------------------------------------------------------- /tests/mod.ex: -------------------------------------------------------------------------------- 1 | 96 MOD 10 = 6 2 | 9.6 MOD 5 = 4.600000 3 | 10 MOD 4.8 = 0.400000 4 | 2.2 MOD 1.1 = 0.000000 5 | -------------------------------------------------------------------------------- /tests/newton.bas: -------------------------------------------------------------------------------- 1 | 10 REM Square Root Calculator using Newton's Method 2 | 3 | 100 LET X = 1337 4 | 400 GOSUB 1000 5 | 500 PRINT "The square root of ",X," is approximately ",Y 6 | 600 END 7 | 8 | 1000 REM Calculate the square root of a given Number 9 | 1001 REM Expects input to be in X. Output will be in Y. 10 | 1002 REM Uses Z as a temporary variable. 11 | 1050 LET Y = 0.5 * X 12 | 1100 LET Z = Y 13 | 1200 LET Y = Y-(((Y^2)-X)/(2*Y)) 14 | 1300 IF Z <> Y THEN GOTO 1100 15 | 1400 RETURN 16 | -------------------------------------------------------------------------------- /tests/newton.ex: -------------------------------------------------------------------------------- 1 | The square root of 1337 is approximately 36.565010 2 | -------------------------------------------------------------------------------- /tests/pemdas.bas: -------------------------------------------------------------------------------- 1 | LET A = 2*3+5*7 2 | PRINT A 3 | LET A = 2*(3+5)*7 4 | PRINT A 5 | LET A = 1^2^3 6 | PRINT A 7 | LET A = 2^3^2 8 | PRINT A 9 | LET A = 2^3^1 10 | PRINT A 11 | -------------------------------------------------------------------------------- /tests/pemdas.ex: -------------------------------------------------------------------------------- 1 | 41 2 | 16 3 | 1 4 | 512 5 | 8 6 | -------------------------------------------------------------------------------- /tests/pi.bas: -------------------------------------------------------------------------------- 1 | 10 PRINT π 2 | -------------------------------------------------------------------------------- /tests/pi.ex: -------------------------------------------------------------------------------- 1 | 3.141593 2 | -------------------------------------------------------------------------------- /tests/remainder.bas: -------------------------------------------------------------------------------- 1 | 10 LET A = 123456 2 | 20 LET N = 1337 3 | 30 LET C = (A - (N * (A/N))) 4 | 40 PRINT C 5 | -------------------------------------------------------------------------------- /tests/remainder.ex: -------------------------------------------------------------------------------- 1 | 452 2 | -------------------------------------------------------------------------------- /tests/shell.bas: -------------------------------------------------------------------------------- 1 | 100 SHELL "echo hello" 2 | -------------------------------------------------------------------------------- /tests/shell.ex: -------------------------------------------------------------------------------- 1 | hello 2 | -------------------------------------------------------------------------------- /tests/squares.bas: -------------------------------------------------------------------------------- 1 | 10 REM PRINTS SQUARES FROM 1^2 TO 10^2 2 | 20 FOR X = 1 TO 10 STEP 1 3 | 30 PRINT X ^ 2 4 | 40 NEXT X 5 | 50 END 6 | -------------------------------------------------------------------------------- /tests/squares.ex: -------------------------------------------------------------------------------- 1 | 1 2 | 4 3 | 9 4 | 16 5 | 25 6 | 36 7 | 49 8 | 64 9 | 81 10 | 100 11 | --------------------------------------------------------------------------------