diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..9b1fd4a --- /dev/null +++ b/.clang-format @@ -0,0 +1,7 @@ +BasedOnStyle: Google +ColumnLimit: 400 +--- +Language: Cpp +DerivePointerAlignment: false +--- +Language: Proto \ No newline at end of file diff --git a/.github/workflows/trunk-check.yaml b/.github/workflows/trunk-check.yaml new file mode 100644 index 0000000..e35b91c --- /dev/null +++ b/.github/workflows/trunk-check.yaml @@ -0,0 +1,22 @@ +name: Pull Request +on: [pull_request] +concurrency: + group: ${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: read-all + +jobs: + trunk_check: + name: Trunk Check Runner + runs-on: ubuntu-latest + permissions: + checks: write # For trunk to post annotations + contents: read # For repo checkout + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Trunk Check + uses: trunk-io/trunk-action@v1 diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 27aaef5..410e959 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -1,44 +1,60 @@ +# +# .github/workflows/ubuntu.yml +# Wopslang Github CI (Action) +# +# 2023, Wops Team +# + name: CI - Ubuntu OS on: push: - branches: [ main, lab ] + branches: [main, lab] pull_request: - branches: [ main, lab ] + branches: [main, lab] + +permissions: read-all jobs: Build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: make - run: mkdir sample/lib; make CI-TEST-Wopslang; + - uses: actions/checkout@v2 + - name: make + run: mkdir sample/lib; make CI-TEST-Wopslang; Fizzbuzz: needs: Build runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: make - run: mkdir sample/lib; make CI-TEST-Wopslang; mv Wopslang sample/; - - name: run - run: cd sample; ./Wopslang fizzbuzz.wops debug > out; + - uses: actions/checkout@v2 + - name: make + run: mkdir sample/lib; make CI-TEST-Wopslang; mv Wopslang sample/; + - name: run + run: cd sample; ./Wopslang fizzbuzz.wops debug > out; Hailstone_Sequence: needs: Build runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: make - run: mkdir sample/lib; make CI-TEST-Wopslang; mv Wopslang sample/; - - name: run - run: cd sample; tree; ./Wopslang hailstone_sequence.wops debug > out; + - uses: actions/checkout@v2 + - name: make + run: mkdir sample/lib; make CI-TEST-Wopslang; mv Wopslang sample/; + - name: run + run: cd sample; tree; ./Wopslang hailstone_sequence.wops debug > out; Hello_Wopslang: needs: Build runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: make - run: mkdir sample/lib; make CI-TEST-Wopslang; mv Wopslang sample/; - - name: run - run: cd sample; tree; ./Wopslang hello_wopslang.wops debug > out; - - + - uses: actions/checkout@v2 + - name: make + run: mkdir sample/lib; make CI-TEST-Wopslang; mv Wopslang sample/; + - name: run + run: cd sample; tree; ./Wopslang hello_wopslang.wops debug > out; + Multiline: + needs: Build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: make + run: mkdir sample/lib; make CI-TEST-Wopslang; mv Wopslang sample/; + - name: run + run: cd sample; echo "1" > input; tree; ./Wopslang multiline.wops debug < input > out; diff --git a/.trunk/.gitignore b/.trunk/.gitignore new file mode 100644 index 0000000..1e24652 --- /dev/null +++ b/.trunk/.gitignore @@ -0,0 +1,8 @@ +*out +*logs +*actions +*notifications +*tools +plugins +user_trunk.yaml +user.yaml diff --git a/.trunk/configs/.markdownlint.yaml b/.trunk/configs/.markdownlint.yaml new file mode 100644 index 0000000..fb94039 --- /dev/null +++ b/.trunk/configs/.markdownlint.yaml @@ -0,0 +1,10 @@ +# Autoformatter friendly markdownlint config (all formatting rules disabled) +default: true +blank_lines: false +bullet: false +html: false +indentation: false +line_length: false +spaces: false +url: false +whitespace: false diff --git a/.trunk/configs/.shellcheckrc b/.trunk/configs/.shellcheckrc new file mode 100644 index 0000000..8c7b1ad --- /dev/null +++ b/.trunk/configs/.shellcheckrc @@ -0,0 +1,7 @@ +enable=all +source-path=SCRIPTDIR +disable=SC2154 + +# If you're having issues with shellcheck following source, disable the errors via: +# disable=SC1090 +# disable=SC1091 diff --git a/.trunk/configs/.yamllint.yaml b/.trunk/configs/.yamllint.yaml new file mode 100644 index 0000000..4d44466 --- /dev/null +++ b/.trunk/configs/.yamllint.yaml @@ -0,0 +1,10 @@ +rules: + quoted-strings: + required: only-when-needed + extra-allowed: ["{|}"] + empty-values: + forbid-in-block-mappings: true + forbid-in-flow-mappings: true + key-duplicates: {} + octal-values: + forbid-implicit-octal: true diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml new file mode 100644 index 0000000..716a6d9 --- /dev/null +++ b/.trunk/trunk.yaml @@ -0,0 +1,28 @@ +# This file controls the behavior of Trunk: https://docs.trunk.io/cli +# To learn more about the format of this file, see https://docs.trunk.io/reference/trunk-yaml +version: 0.1 +cli: + version: 1.17.1 +plugins: + sources: + - id: trunk + ref: v1.2.6 + uri: https://github.com/trunk-io/plugins +runtimes: + enabled: + - go@1.21.0 + - node@18.12.1 + - python@3.10.8 +lint: + enabled: + - clang-format@16.0.3 + - actionlint@1.6.26 + - checkov@2.5.9 + - git-diff-check + - markdownlint@0.37.0 + - prettier@3.0.3 + - shellcheck@0.9.0 + - shfmt@3.6.0 + - trivy@0.46.0 + - trufflehog@3.60.0 + - yamllint@1.32.0 diff --git a/CHANGELOG b/CHANGELOG index 434f1ec..f7c7372 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,32 @@ - add more function - support Array(based on `std::vector`) +=== v0.1: 691dffb === +THIS VERSION IS THE FINAL VERSION OF v0.1.x + +- feature + - more flexible grammar (inline statements, multiline expressions) + - unified error message + +- improvement + - parser now parses code word by word (big improvement) + - deprecated old error handler + +=== v0.1.6: 9b2d6a9 === +THIS IS INTERNAL UPDATE: THERE IS NO NEW FEATURE + +improvement + - deprecated Array class + - developed Object class for v0.2 + - big improvement on error handler + +v0.1 checklist +- Better parser (inline code & multiline statement) + +v0.2 checklist +- Object (Array, Func) (user-definable Object will be in v0.2.1) +- Third party library & changing library code into `.wops` + === v0.1.5: 239dd25 === - feature diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 322e766..ad5e081 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,14 @@ + + # :page_with_curl: Contribute Guideline -## :wave: Welcome, new Wopers +## :wave: Welcome, new Wopers First off, thank you for considering contributing to Wopslang. Wopslang could be existed because of many devoted Wopers like you. @@ -22,13 +30,13 @@ If you already have a solution for it, please make a PR. If you already have a solution for it, PR suits you. Code style should satisfy these checklist. -- [ ] [Google C++ Coding Style Guide #General Naming Rules](https://google.github.io/styleguide/cppguide.html#General_Naming_Rules) -- [ ] K&R Indentation style -- [ ] Use Boilerplate Code : +- [ ] [Google C++ Coding Style Guide #General Naming Rules](https://google.github.io/styleguide/cppguide.html#General_Naming_Rules) +- [ ] K&R Indentation Style +- [ ] Use Boilerplate Code : ```c++ /* - * + * * * * , Wops Team @@ -43,6 +51,16 @@ Code style should satisfy these checklist. #endif ``` +All commit messages should satisfy these checklist. + +- [ ] Description Starts with Lowercase Character +- [ ] No Emoji +- [ ] Use Boilerplate Code : + +```text +: +``` + Also, your PR can be rejected by these reasons: - Too much change @@ -52,30 +70,21 @@ Also, your PR can be rejected by these reasons: Finally, your PR branch's name should be in one of these forms: - `patch-[username]-[number]` -- *`dev-[username]-[number]`: only for inside Wopers* +- _`dev-[username]-[number]`: only for inside Wopers_ - `docs-[username]-[number]` ### :speech_balloon: Being the Wopslang Manager -Wopslang managers mediate the overheated community, review the issues and pull requests, and lead the development of Wopslang. Of course, this job requires not only deep knowledge of Wopslang, but also conversation skill. Also, Wopslang managers should be in Wops team; Wopslang managers should be inside Wopers. +Wopslang managers mediate the overheated community, review the issues and pull requests, and lead the development of Wopslang. Of course, this job requires not only deep knowledge of Wopslang, but also conversation skill. Also, Wopslang managers should be in Wops team; Wopslang managers should be inside Wopers. -If you want to contribute as the Wopslang manager, join the [Wops Community Slack](https://join.slack.com/t/wopslangcommunity/shared_invite/zt-nkcy12cy-n8YlAPnOT~ErPODF6k3jOw) and send DM to Wopslang managers. We'll prepare the interview for you. +We're not recruiting the Wopslang manager for now. #### Wopslang manager list -|Github Username|Slack Username| -|---|---| -|@RedoC-github|@RedoC-github| -|@rdxxer|@codenstory| -|@pokmui|@pokmui| - -## :white_check_mark: TODO - -**Contributes about things in TODO list will have higher priority than normal one.** - -- Nothing - - - +| Github Username | Slack Username | +| --------------- | -------------- | +| @RedoC-github | @RedoC-github | +| @rdxxer | @codenstory | +| @pokmui | @pokmui | -2022, Wops Team +2023, Wops Team diff --git a/Makefile b/Makefile index 1c1aa21..6254f3a 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,10 @@ -# Makefile +# +# Makefile +# Wopslang Makefile +# +# 2023, Wops Team +# +# ifeq ($(OS), Windows_NT) OPTION=include/dlfcn.c src/import_/eexec_.cpp -std=c++11 diff --git a/NOTICE b/NOTICE index 52d947e..3e55f42 100644 --- a/NOTICE +++ b/NOTICE @@ -1,5 +1,5 @@ Wops Programming Language -Copyright (c) 2021 Wops Team +Copyright (c) 2023 Wops Team https://github.com/Wopslang/Wops This product is licensed under the terms of the Apache Software License 2.0. See the LICENSE file for the full license text. diff --git a/README.md b/README.md index 76fc598..d1c48ee 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,6 @@ -> :mega: **IMPORTANT ANNOUNCEMENT** -> Every Wops teammate is a student, preparing for some exams, entrance tests, and more. Now, most developers are living hard as students, not developers. And it is causing delays in updates. However, this project is still onboard, and we always welcome your contributions! Please stay tuned on Wopslang and be with our team. # :hammer_and_wrench: Working Pseudocode, Wopslang [![CI - Ubuntu OS](https://github.com/Wopslang/Wops/actions/workflows/ubuntu.yml/badge.svg)](https://github.com/Wopslang/Wops/actions/workflows/ubuntu.yml) -[![Badge](https://img.shields.io/badge/Slack-Join_our_chat-critical.svg?link=https://join.slack.com/t/wopslangcommunity/shared_invite/zt-nkcy12cy-n8YlAPnOT~ErPODF6k3jOw&logo=slack)](https://join.slack.com/t/wopslangcommunity/shared_invite/zt-nkcy12cy-n8YlAPnOT~ErPODF6k3jOw) ```go func Wopslang = {contributors, { @@ -17,15 +14,14 @@ func Wopslang = {contributors, { ``` ### `#LanguageForAlgorithm` `#WorkingPseudo` + _**Wopslang**_ is for every computer scientist who needs a **pseudocode-like**, but **working** programming language. _**Simple grammar**_ will highlight your logical ideas. _**Fast-runtime**_ will give you immediate feedback to forward. _Be with our project, using ⭐_ -*** - ## Infomation -Version: **Wopslang v0.1.5 alpha** +Version: **Wopslang v0.1 alpha** License: Apache License 2.0 [⚒️ Official Documentation](./doc/README.md) [➕ VSCode Extension](https://github.com/Wopslang/vscode-wops) @@ -58,16 +54,16 @@ Check [howto.md](doc/howto.md) for more detail See [sample folder](./sample) :sparkles: -## Credit +## Credit -|Github Username|Slack Username|Role| -|---|---|---| -|**@RedoC-github**|**@RedoC**|**Lead Programmer of Interpreter**| -|**@pokmui**|**@pokmui**|**Programmer of Interpreter, Admin of Slack**| -|@byunjaewoo|@byunjaewoo|Lead Programmer of Data Structure -|@happybean4|@khanjhy|Planner of Grammar| -|**@rdxxer**|**@codenstory**|**Programmer of Interpreter**| -|@dddddd1234-creator|@dddddd|Lead Programmer of Builtin Function| +| Github Username | Slack Username | Role | +| ------------------- | --------------- | --------------------------------------------- | +| **@RedoC-github** | **@RedoC** | **Lead Programmer of Interpreter** | +| **@pokmui** | **@pokmui** | **Programmer of Interpreter, Admin of Slack** | +| @byunjaewoo | @byunjaewoo | Lead Programmer of Data Structure | +| @happybean4 | @khanjhy | Planner of Grammar | +| **@rdxxer** | **@codenstory** | **Programmer of Interpreter** | +| @dddddd1234-creator | @dddddd | Lead Programmer of Builtin Function | **Bold user** is the Wopslang manager. Special Thanks to @jhhan128 diff --git a/build.sh b/build.sh index 8b5c9d9..181137f 100644 --- a/build.sh +++ b/build.sh @@ -6,25 +6,24 @@ echo -e "\033[92m██║███╗██║██║ ██║██╔═ echo -e "\033[92m╚███╔███╔╝╚██████╔╝██║ ███████║███████╗██║ ██║██║ ╚████║╚██████╔╝\033[m" echo -e "\033[92m ╚══╝╚══╝ ╚═════╝ ╚═╝ ╚══════╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝ \033[m" echo -e "\n" -echo -e "✨ \033[1mWopslang v0.1.5 alpha Builder\033[m" +echo -e "✨ \033[1mWopslang v0.1 alpha Builder\033[m" echo -e "\033[91mWarning: This is alpha version. Some critical issues might be appeared.\033[m" echo -e -n "- make install..." make clean -LOG=`make` -RESULT=`echo $?` +LOG=$(make) +RESULT=$(echo $?) -if [ $RESULT -ne 0 ] -then - echo -e "\033[91mError occured while building Wopslang.\033[m" - echo -e "\033[91m┌─────────────── How to Fix ───────────────┐\033[m" - echo -e "\033[91m│ │\033[m" - echo -e "\033[91m│ 1. Check the error message fix your │\033[m" - echo -e "\033[91m│ environment setting (or installation) │\033[m" - echo -e "\033[91m│ │\033[m" - echo -e "\033[91m│ 2. Ask help to the Wops Community │\033[m" - echo -e "\033[91m│ - github.com/Wopslang/Wops/discussions │\033[m" - echo -e "\033[91m│ │\033[m" - echo -e "\033[91m└──────────────────────────────────────────┘\033[m" -else - echo -e "\033[94mDone! Happy coding with Wopslang :)\033[m" -fi \ No newline at end of file +if [[ ${RESULT} -ne 0 ]]; then + echo -e "\033[91mError occured while building Wopslang.\033[m" + echo -e "\033[91m┌─────────────── How to Fix ───────────────┐\033[m" + echo -e "\033[91m│ │\033[m" + echo -e "\033[91m│ 1. Check the error message fix your │\033[m" + echo -e "\033[91m│ environment setting (or installation) │\033[m" + echo -e "\033[91m│ │\033[m" + echo -e "\033[91m│ 2. Ask help to the Wops Community │\033[m" + echo -e "\033[91m│ - github.com/Wopslang/Wops/discussions │\033[m" + echo -e "\033[91m│ │\033[m" + echo -e "\033[91m└──────────────────────────────────────────┘\033[m" +else + echo -e "\033[94mDone! Happy coding with Wopslang :)\033[m" +fi diff --git a/doc/CHANGELOG b/doc/CHANGELOG index 89e11a1..9450384 100644 --- a/doc/CHANGELOG +++ b/doc/CHANGELOG @@ -2,4 +2,5 @@ -------------|----------------------------|--------- Aug 30, 2021 | Remove Unary Operator +, - | Conflict Oct 1, 2021 | Add File Extention | New - Jun 29, 2022 | New Innovative Grammar | New \ No newline at end of file + Jun 29, 2022 | New Innovative Grammar | New + Oct 18, 2023 | Final v0.1 Grammar | Release \ No newline at end of file diff --git a/doc/README.md b/doc/README.md index 9113b7f..aab1a83 100644 --- a/doc/README.md +++ b/doc/README.md @@ -1,22 +1,23 @@ # 📔 Wopslang Documentation ```go -func Documentation(question) { - Dict doc = loadDoc() - return doc[question] +func Documentation = {question, { + Dict<> doc = loadDoc() + return doc[question] + } } ``` ## 📜 Language Reference -*[Official Reference for v0.1](grammar.md)* +_[Official Reference for v0.1](grammar.md)_ ## ⚡️ Built-in Function -*[Wopslang Builtin Functions for v0.1](https://github.com/Wopslang/Wops/blob/main/lib/functions.md)* +_[Wopslang Builtin Functions for v0.1](../lib/functions.md)_ ## 📓 Guidebook -*[How to install and launch Wopslang](howto.md)* +_[How to install and launch Wopslang](howto.md)_ -© 2021 Wops Team +2023, Wops Team diff --git a/doc/grammar.md b/doc/grammar.md index 7a9fd75..fbaed76 100644 --- a/doc/grammar.md +++ b/doc/grammar.md @@ -1,3 +1,11 @@ + + # Official Wopslang Language Reference `v0.2` ## Index @@ -14,19 +22,15 @@ - [Keywords] - [Operators and Punctuation] - [Integer Literal] + - [Boolean Literal] - [Floating-point Literal] - [Rune Literal] - [String Literal] - - [Boolean Literal] - [Types] - [Variables] -- [Containers] -- [Objects] - - [Object Types] - - [Defining Object] - - [Declaring Object] - [Expressions] - [Blocks] + - [Parenthesis] - [Declarations] - [Operands] - [Calls] @@ -50,7 +54,7 @@ So, make sure to check this page when you updated Wopslang to the newest version > Our language is based on an idea: simple, but powerful. > And because our grammar was also designed with this idea, we developed only the most important expressions. -> However, we know that our standard of *importance* can be different from your standard. +> However, we know that our standard of _importance_ can be different from your standard. > So, please tell us your idea of what to put into Wopslang. > We would love to hear your voice. @@ -83,9 +87,9 @@ digit = "0" ... "9" . ### Comments -Comments can be represented with a form: +Comments can be represented with a form: -- Full-line comments start with `//` and stop at the end of the line. +- comments start with `//` and stop at the end of the line. For example, this form will be allowed: @@ -100,12 +104,12 @@ And these forms won't be allowed: /* Bad :( */ -out(":(") // Bad :( +out(":(") ``` ### Tokens -Token is the word which can be used in Wopslang. There are four types: *Identifiers, Keywords, Operators, Punctuation, and Literals*. White space, formed from spaces (U+0020), horizontal tabs (U+0009), carriage returns (U+000D), and newlines (U+000A), is ignored except as it separates tokens that would otherwise combine into a single token. +Token is the word which can be used in Wopslang. There are four types: _Identifiers, Keywords, Operators, Punctuation, and Literals_. White space, formed from spaces (U+0020), horizontal tabs (U+0009), carriage returns (U+000D), and newlines (U+000A), is ignored except as it separates tokens that would otherwise combine into a single token. ### Identifiers @@ -124,7 +128,7 @@ _WopsV01 αβ ``` -Some identifiers cannot be used. See [Predeclared Identifiers] for more detail. +Some identifiers cannot be used. See [Keywords] for more detail. ### Keywords @@ -132,19 +136,20 @@ The following keywords are reserved and may not be used as identifiers. ```text break const continue -elif else for -if range +for if in ``` +also, all type identifiers could not be used as identifiers too. + ### Operators and Punctuation The following character sequences represent operators (including assignment operators) and punctuation. ```text + && == != ( ) -- || < <= [ ] -* > >= / : = -~ ; % ! <- , +- || < <= * > +>= / = ~ ; % +, ! ``` ### Integer Literal @@ -174,7 +179,10 @@ a56bc // (x) ### Boolean Literal -boolean literal is a bit representing boolean constant: *true `1`, and false `0`*. +boolean literal is a bit representing boolean constant: _true `1`, and false `0`_. +If you assign other integer on a boolean literal, it will be stored as `1`. +Also, the operation between a boolean and an integer is regarded as one between integers but will end up as `1` unless the result is `0`. +Any operation between a boolean and a floating-point or assigning a floating-point to a boolean is prohibited (same with string). ```ebnf bool_lit = "0" | "1". @@ -206,18 +214,18 @@ A rune literal represents a rune constant, an integer value identifying a Unicod After a backslash, certain single-character escapes represent special values: -|Literal|Unicode|Description| -|---|---|--| -|`\a`|U+0007|alert or bell| -|`\b`|U+0008|backspace| -|`\f`|U+000C|form feed| -|`\n`|U+000A|line feed or newline| -|`\r`|U+0007|carriage return| -|`\t`|U+0007|horizontal tab| -|`\v`|U+0007|vertical tab| -|`\\`|U+0007|backslash| -|`\'`|U+0007|single quote| -|`\"`|U+0007|double quote| +| Literal | Unicode | Description | +| ------- | ------- | -------------------- | +| `\a` | U+0007 | alert or bell | +| `\b` | U+0008 | backspace | +| `\f` | U+000C | form feed | +| `\n` | U+000A | line feed or newline | +| `\r` | U+0007 | carriage return | +| `\t` | U+0007 | horizontal tab | +| `\v` | U+0007 | vertical tab | +| `\\` | U+0007 | backslash | +| `\'` | U+0007 | single quote | +| `\"` | U+0007 | double quote | ```ebnf rune_lit = "'" uni_value "'" . @@ -246,14 +254,14 @@ Example: ## Types A data type or simply type is an attribute which notate a particular kind of data item. -There are four kind of type: *Integer, Floating-Point, String, and Boolean*. And it can be notated with these [predeclared identifiers][Predeclared Identifiers]: +There are four kind of type: _Integer, Floating-Point, String, and Boolean_. And it can be notated with these identifiers: -|Identifier|Matching Type|Description| -|---|---|--| -|`int`|Integer|signed 32-bit integers (-2147483648 ~ 2147483647)| -|`double`|Floating-Point|IEEE-754 64-bit floating-point numbers| -|`string`|String|[same with string literal][String Literal]| -|`bool`|Boolean|[same with boolean literal][Boolean Literal]| +| Identifier | Matching Type | Description | +| ---------- | -------------- | ------------------------------------------------- | +| `int` | Integer | signed 32-bit integers (-2147483648 ~ 2147483647) | +| `double` | Floating-Point | IEEE-754 64-bit floating-point numbers | +| `string` | String | [same with string literal][String Literal] | +| `bool` | Boolean | [same with boolean literal][Boolean Literal] | ```ebnf Type = "int" | "double" | "string" | "bool" . @@ -262,7 +270,7 @@ Type = "int" | "double" | "string" | "bool" . ## Variables A variable is a storage for holding a value. The set of available values is determined by the variable's [type][Types]. -There are two types of variable which can be used in Wopslang v0.1: *constant variable, modifiable variable*. You can declare constant variable as adding const keyword in variable declare expression. Also, you should add initial value to declare constant variable and you won't be able to reassign its value. Interpreter can emit the error if value's representing type doesn't match with variable's type. +There are two types of variable which can be used in Wopslang v0.1: _constant variable, modifiable variable_. You can declare constant variable as adding const keyword in variable declare expression. Also, you should add initial value to declare constant variable and you won't be able to reassign its value. Interpreter can emit the error if value's representing type doesn't match with variable's type. ```go int woo = toint(in()) @@ -272,76 +280,6 @@ string poo = "result: " + tostring(woo + ooo) string soo = poo ``` -## Containers - -A container is an array-structure storage for holding multiple values. -There is no need for every element to have the same type, so the container has no specific type. -Values in the container can be a variable, a container, or even statements. -Containers can be represented like following code. - -```go -{1, 2, {3, 4}, 5} -``` - -Special operator (only available in container) `~` denotes the arithmetic integer sequence when it is used in a container. -Basicaly, `a~b` denotes a sequence from `a` to `b` with interval `1`. You can also decide specific interval `c` using `a~b~c`. - -```go -{0 ~ 10} // {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10} -{1 ~ 10 ~ 3} // {1,4,7,10} -``` - -You should aware that `~` contains last element. - -Because objects use containers to store their data, you can assign a container to an object instead of assigning an object to it. -You can also use a container instantly in for statement. -However, you can't declare a container directly and use it. - -```go -Array arr <- {1 ~ 9} -for i in arr $ - for j in {1 ~ 9} $ - out(i, "*", j, "=", i*j) - ; -; -``` -## Objects - -An object is a general storage for various data structures. Objects store data in their *container*. - -### Object Types -Some types, called *object types*, can be used to represent what the object stores in their container. Three types of object types can be used in Wopslang v0.2: `Array`, `Func`, and `Object`. `Array` and `Func` are the predefined object types and represent a list of values and a function, respectively. You can define your objects by using `Object` object type. - -```ebnf -ObjectType = ( "Array" | "Func" | "Object" ) ObjType -``` - -If the object type has argument type, you can add argument types like - -```go - // {} is a type container -``` -For example, -```go -Array arr_dim1 // 1-dim array -Array arr_dim2 // 2-dim array -Func<{int, int}, int> fun_2_int_arg_1_int_ret // (int, int) -> int -``` - -### Defining Object -NOT CONFIRMED YET. STAY TUNED. - -### Declaring Object -There are two ways of assigning a value to an object used in Wopslang v0.2: *Assigning an object directly*, and *Assigning a container into the object's container*. -The former uses the regular operator `=` and works the same with assigning variables. -Latter uses the special operator `<-` only available in Object. -As for adding const keyword, of course, you can declare a constant object with a mandatory initial value. - -```go -Array arr <- {1 ~ 5} -Func<{int, int} int> sum <- {int a, int b, { return a+b }} -``` - ## Expressions ### Blocks @@ -357,33 +295,38 @@ Statements = { Statement } . if and for expression is considered to be in its own block. +### Parenthesis + +Typically, every expression is inline only. However, you can use multiline expressions by wrapping expressions with parenthesis `()`. + +```go +out("Hello, ", "World!", "\n") +out("Hello, ", + "World!", + "\n") +``` + ### Declarations -A declaration bind *identifiers* and *value* to a constant or [variable][Variables]. +A declaration bind _identifiers_ and _value_ to a constant or [variable][Variables]. Every identifier in a program must be declared, and no identifier may be declared twice in the same block. See [Variables] to get more information. ```ebnf -Declaration = ConstVarDel | VarDel | ConstObjDel | ObjDel . +Declaration = ConstVarDel | VarDel . ConstVarDel = "const" Type identifiers "=" Expression . VarDel = Type identifiers [ "=" Expression ] . -ConstObjDel = "const" ObjectType identifiers ( "<-" Container | "=" Expression ) . -ObjDel = ObjectType identifiers [ "<-" Container | "=" Expression ] . ``` To find syntax defination of `Expression`, see [Operators] for more. ### Operands -Operands represent the elementary values in an expression. It can be a *literal*, a *function*, or a *variable*. +Operands represent the elementary values in an expression. It can be a _literal_, a _function_, or a _variable_. ```ebnf -Operand = Literal | OpndName | "(" Expression ")" | Container | ObjType. +Operand = Literal | OpndName | "(" Expression ")" . Literal = integer_lit | float_lit | rune_lit | string_lit . OpndName = identifier . -Container = ConGrp | ConRan . -ConGrp = "{" { ( Container | Statement ) "," } [ Container | Statement ] "}" . -ConRan = "{" Expression "~" Expression [ "~" Expression ] "}" . -ObjType = "<" {Container | Type} ">" . ``` Also, there are some unit expression groups: @@ -402,7 +345,6 @@ foo boo (3 + 0.25) out("Hello, World!\n", "Nice to meet you :D") -{"this", "is", {"a", "container"}} ``` ### Calls @@ -439,28 +381,29 @@ unary_op = "!" | "+" | "-" . Each operator has a different priority for parsing. For instance, unary operators have the highest priority. -|Priority|Operators| -|--------|---------| -|5|`*`, `/`, `%`| -|4|`+`, `-`| -|3|`==`, `!=`, `<`, `<=`, `>`, `>=`| -|2|`&&`| -|1|`\|\|`| +| Priority | Operators | +| -------- | -------------------------------- | +| 5 | `*`, `/`, `%` | +| 4 | `+`, `-` | +| 3 | `==`, `!=`, `<`, `<=`, `>`, `>=` | +| 2 | `&&` | +| 1 | `\|\|` | The leftmost operator in the same priority has a higher priority. For instance, `a+b-c` is the same with `(a+b)-c`. +Also, the unary operator `+` and `-` is different from the binary operator `+` and `-` respectively. These unary operators only represent operand's sign. ### Arithmetic Operators -|Operator|Matching Literals| -|--------|-----------------| -|`+`|integer, float, string| -|`-`|integer, float| -|`*`|integer, float| -|`/`|integer, float| -|`%`|integer| +| Operator | Matching Literals | +| -------- | ---------------------- | +| `+` | integer, float, string | +| `-` | integer, float | +| `*` | integer, float | +| `/` | integer, float | +| `%` | integer | -If you divide by zero(`A/0` or `A%0`, A:expression), interpreter will emit the error. Also, ***If you divide with integers, the result will be integer, too.*** +If you divide by zero(`A/0` or `A%0`, A:expression), interpreter will emit the error. Also, **_If you divide with integers, the result will be integer, too._** ### Conversion @@ -492,7 +435,7 @@ Blank = . The assignment statement assigns a value to the specified variable. ```ebnf -Assignment = identifiers "=" Expression | identifiers "<-" Container . +Assignment = identifiers "=" Expression . ``` For `=` assignment, Left-side operand should be lvalue. @@ -503,12 +446,11 @@ For `<-` assignment, right-side should be a container matching with left-side op a = "Hello, " + in() b = 30 * (50 / 27) // b = 30 c = 0.5 - 1.3 -d <- {1 ~ 5} // d = {1, 2, 3, 4, 5} ``` ### If Statement -*If* statements specify the conditional execution of more than two branches according to the value of a boolean expression. If value is true, `if` branches will be executed, otherwise, highest `elif` branches will be executed. If every `if` and `elif` branches' expression is false, `else` branch will be executed. +_If_ statements specify the conditional execution of more than two branches according to the value of a boolean expression. If value is true, `if` branches will be executed, otherwise, highest `elif` branches will be executed. If every `if` and `elif` branches' expression is false, `else` branch will be executed. For example: @@ -534,16 +476,16 @@ IfStmt = "if" Expression IfBlock ### For Statement -*For* statement represents repeating execution of a block. -There are two types of for statement: *using a single condition*, and *using an array*. +_For_ statement represents repeating execution of a block. +There are two types of for statement: _using a single condition_, and _using an array_. ```ebnf -ForStmt = "for" ( Expression | ArrayClause ) ForBlock . +ForStmt = "for" ( Expression | ForClause ) ForBlock . ``` #### For statement with single condition -A *for* statement with single condition represents repeating execution of a block as long as a boolean condition evaluates to true. The condition is evaluated before each iteration. +A _for_ statement with single condition represents repeating execution of a block as long as a boolean condition evaluates to true. The condition is evaluated before each iteration. ```go for a % 2 $ @@ -551,35 +493,36 @@ for a % 2 $ ; ``` -#### For statement with an array +#### For statement with for clause -A *for* statement with an array assigns one element from the array to a local variable in order at every iteration. +A _for_ statement with for clause use special operator `~` to denote a sequence. +Special operator (only available in for clause) `~` denotes the arithmetic integer sequence. +Basicaly, `a~b` denotes a sequence from `a` to `b-1` with interval `1`. +You can also decide specific interval c using `a~b~c`. +Operator `~` has the lowest priority in the whole operators. +Finally, _for_ statement repeat execution of a block with that sequence. ```ebnf -ArrayClause = identifiers "in" Expression. +ForClause = identifiers "in" Expression "~" Expression [ "~" Expression ]. ``` ```go -Array arr <- {0 ~ 4 ~ 2} -for i in arr $ - for j in {"a", "b", "c"} $ - out(tostring(i) + j + " ") - ; - out("\n") +for i in 0~6~2 $ + out(tostring(i) + "\n") ; ``` Output: ```text -0a 0b 0c -2a 2b 2c -4a 4b 4c +0 +2 +4 ``` ### Break and Continue Statement -A *break* or *continue* statement terminates or passes execution of innermost `for` statement. +A _break_ or _continue_ statement terminates or passes execution of innermost `for` statement. ```ebnf BreakStmt = "break" . @@ -593,38 +536,33 @@ ContinueStmt = "continue" . Redirect to [here][ext-link-1] + [Introduction]: #introduction [Notation]: #notation [Source Code Representation]: #source-code-representation [Lexical Elements]: #lexical-elements [Types]: #types [Variables]: #variables -[Containers]: #containers -[Objects]: #objects -[Object Types]: #object-types -[Defining Object]: #defining-object -[Declaring Object]: #declaring-object [Expressions]: #expressions [Statements]: #statements [If Statement]: #if-statement [For Statement]: #for-statement [Builtin functions]: #builtin-functions [Tokens]: #tokens -[Predeclared Identifiers]: #predeclared-identifiers [UTF-8]: https://en.wikipedia.org/wiki/UTF-8 [Characters]: #characters [Letter and Digits]: #letter-and-digits [Comments]: #comments -[Semicolons]: #semicolons [Identifiers]: #identifiers [Keywords]: #keywords [Operators and Punctuation]: #operators-and-punctuation [Integer Literal]: #integer-literal +[Boolean Literal]: #boolean-literal [Floating-point Literal]: #floating-point-literal [Rune Literal]: #rune-literal [String Literal]: #string-literal -[Boolean Literal]: #boolean-literal [Blocks]: #blocks +[Parenthesis]: #parenthesis [Declarations]: #declarations [Operands]: #operands [Calls]: #calls @@ -638,4 +576,4 @@ Redirect to [here][ext-link-1] [Break and Continue Statement]: #break-and-continue-statement [ext-link-1]: https://github.com/Wopslang/Wops/blob/main/lib/functions.md -© 2023 Wops Team +2023, Wops Team diff --git a/doc/grammar_kr.md b/doc/grammar_kr.md deleted file mode 100644 index de90416..0000000 --- a/doc/grammar_kr.md +++ /dev/null @@ -1,33 +0,0 @@ -# WOPSLANG 언어 레퍼런스 `v0.1` - -## Index - -- [개요] -- [표기] -- [소스코드 표현] - - -## 개요 - -v0.1 알파 버전의 공식 Wopslang 언어 레퍼런스 입니다! -현재 출시 예정인 버전은 테스트 버전이기 때문에, 여기에 있는 많은 정보들은 수정될 수 있습니다. -당연히 여러가지 문법들도 추가될 것입니다. -당신의 Wopslang을 최신 버전으로 업데이트 했을때 꼭 이 문서를 확인해주시기 바랍니다. - ->우리의 언어가 기반으로 하는 생각이 있습니다. '간단하면서도 강력한 언어' ->언어의 문법은 이 생각을 바탕으로 제작되었기 때문에, 현재는 가장 중요한 표현들만 포함하고 있습니다. ->중요도에 대한 우리의 생각과, 여러분의 생각이 다를 수도 있다는 것을 알고 있습니다. ->Wopslang에 추가할 만한 여러분의 생각을 말씀해주세요! ->여러분의 생각을 기다리고 있겠습니다. - -## 표기 - - - -## 소스코드 표현 - - - -[개요]: https://github.com/Wopslang/Wops/blob/main/doc/grammar_kr.md#%EA%B0%9C%EC%9A%94 -[표기]: https://github.com/Wopslang/Wops/blob/main/doc/grammar_kr.md#%ED%91%9C%EA%B8%B0 -[소스코드 표현]: https://github.com/Wopslang/Wops/blob/main/doc/grammar_kr.md#%EC%86%8C%EC%8A%A4%EC%BD%94%EB%93%9C-%ED%91%9C%ED%98%84 diff --git a/doc/howto.md b/doc/howto.md index 707c8ce..11cec68 100644 --- a/doc/howto.md +++ b/doc/howto.md @@ -1,17 +1,20 @@ -# :rocket: How to Launch Wopslang + + +# :rocket: How to Launch Wopslang ## Introduction It is a document containing how to install Wops. If you find an unexpected error during installation, check the installation order again and ask for help if the error continues to appear. - ## Ubuntu OS 1. Open a Terminal. - - - 2. Install 'gcc', 'g++' and 'make', using the `apt` command: ```bash @@ -20,15 +23,12 @@ It is a document containing how to install Wops. If you find an unexpected error sudo apt install make ``` - - 3. Clone our project repository ```bash git clone https://github.com/Wopslang/Wops.git ``` - 4. Use this command in Terminal to build and make executable interpreter: ```bash @@ -43,34 +43,28 @@ Done! 1. Install Git Bash - English: https://git-scm.com/downloads - - Korean: https://xangmin.tistory.com/102 - -2. Install gcc + - English: https://git-scm.com/downloads - English: https://dev.to/gamegods3/how-to-install-gcc-in-windows-10-the-easier-way-422j + - Korean: https://xangmin.tistory.com/102 - Korean: https://jeunna.tistory.com/entry/Windows-gcc-g-%EC%84%A4%EC%B9%98%ED%95%98%EA%B8%B0-MinGW +2. Install gcc - if "the file has been downloaded incorrectly" error occurred, check [this website](https://suji-choi.tistory.com/34) + - English: https://dev.to/gamegods3/how-to-install-gcc-in-windows-10-the-easier-way-422j + - Korean: https://jeunna.tistory.com/entry/Windows-gcc-g-%EC%84%A4%EC%B9%98%ED%95%98%EA%B8%B0-MinGW - + - if "the file has been downloaded incorrectly" error occurred, check [this website](https://suji-choi.tistory.com/34) 3. Install make - English: https://www.stanleyulili.com/git/how-to-install-git-bash-on-windows/ - - Korean: https://ndb796.tistory.com/381 + - English: https://www.stanleyulili.com/git/how-to-install-git-bash-on-windows/ - + - Korean: https://ndb796.tistory.com/381 4. Clone our project repository ```bash git clone https://github.com/Wopslang/Wops.git - ``` - + ``` 5. Use this command in Git Bash to build and make executable interpreter: @@ -80,20 +74,14 @@ Done! ![image](https://user-images.githubusercontent.com/74172008/148321362-b722b387-5fb0-4795-8aab-8dfb984fcf90.png) - Done! - - - - - - +Done! ## To run The library file(`library.so`) should be placed in the path `${ExecutableFilePath}/lib/library.so`. -``` +```bash ./Wopslang .wops ``` -© 2021 Wops Team +2023, Wops Team diff --git a/include/basis.h b/include/basis.h index 50b4a61..c252f17 100644 --- a/include/basis.h +++ b/include/basis.h @@ -1,16 +1,16 @@ /* * include/basis.h - * Wopslang Must-Be-INCLUDED Headerfile + * Wopslang MUST-BE-INCLUDED Headerfile * - * 2021, Wops Team + * 2023, Wops Team * */ #ifndef WOPSLANG_BASIS_H #define WOPSLANG_BASIS_H -using Int=signed int; -using Double=double; -using String=std::string; -using Bool=bool; +using Int = signed int; +using Double = double; +using String = std::string; +using Bool = bool; #endif \ No newline at end of file diff --git a/include/dlfcn.c b/include/dlfcn.c index 376d1e7..b834ae0 100644 --- a/include/dlfcn.c +++ b/include/dlfcn.c @@ -2,76 +2,68 @@ * include/dlfcn.cpp * Wopslang DLFCN-WIN Sourcefile * - * 2021, Wops Team + * 2023, Wops Team * */ +#include "dlfcn.h" + #include #include #include #include #include -#include "dlfcn.h" -typedef struct CACHE_DLFCN{ - long lasterror; - const char *err_rutin; +typedef struct CACHE_DLFCN { + long lasterror; + const char* err_rutin; } CACHE_DLFCN; -CACHE_DLFCN cache = { - 0, - NULL -}; +CACHE_DLFCN cache = {0, NULL}; -void *dlopen(const char *filename, int flags) { - HINSTANCE h_instance; +void* dlopen(const char* filename, int flags) { + HINSTANCE h_instance; - h_instance = LoadLibrary(filename); - if (h_instance == NULL) { - cache.lasterror = GetLastError(); - cache.err_rutin = "dlopen"; - } - return h_instance; + h_instance = LoadLibrary(filename); + if (h_instance == NULL) { + cache.lasterror = GetLastError(); + cache.err_rutin = "dlopen"; + } + return h_instance; } -int dlclose(void *handle) { - BOOL status; - int return_code = 0; +int dlclose(void* handle) { + BOOL status; + int return_code = 0; - status = FreeLibrary( - (HINSTANCE)handle - ); + status = FreeLibrary((HINSTANCE)handle); - if (!status) { - cache.lasterror = GetLastError(); - cache.err_rutin = "dlclose"; - return_code = -1; - } + if (!status) { + cache.lasterror = GetLastError(); + cache.err_rutin = "dlclose"; + return_code = -1; + } - return return_code; + return return_code; } -void *dlsym(void *handle, const char *name) { - FARPROC func_ptr; +void* dlsym(void* handle, const char* name) { + FARPROC func_ptr; - func_ptr = GetProcAddress( - (HINSTANCE)handle, - name - ); - - if (!func_ptr) { - cache.lasterror = GetLastError(); - cache.err_rutin = "dlsym"; - } - return (void *)(intptr_t) func_ptr; -} + func_ptr = GetProcAddress((HINSTANCE)handle, name); -const char *dlerror(void) { - static char* errstr; - if (cache.lasterror) { - sprintf(errstr, "%s error (%ld)", cache.err_rutin, cache.lasterror); - return errstr; - } else { - return NULL; - } + if (!func_ptr) { + cache.lasterror = GetLastError(); + cache.err_rutin = "dlsym"; + } + return (void*)(intptr_t)func_ptr; } +const char* dlerror(void) { + static char* errstr; + if (cache.lasterror) { + sprintf(errstr, "%s error (%ld)", cache.err_rutin, cache.lasterror); + return errstr; + } else { + return NULL; + } +} \ No newline at end of file diff --git a/include/dlfcn.h b/include/dlfcn.h index 19bec5e..2c0ba95 100644 --- a/include/dlfcn.h +++ b/include/dlfcn.h @@ -1,8 +1,8 @@ /* * include/dlfcn.h - * Wopslang DLFCN-WIN headerfile + * Wopslang DLFCN-WIN headerfile * - * 2021, Wops Team + * 2023, Wops Team * */ #ifndef WOPS_DLFCN_H @@ -10,21 +10,21 @@ // Redefine the plag #define RTLD_GLOBAL 0x100 -#define RTLD_LOCAL 0x000 -#define RTLD_LAZY 0x000 -#define RTLD_NOW 0x001 +#define RTLD_LOCAL 0x000 +#define RTLD_LAZY 0x000 +#define RTLD_NOW 0x001 #ifdef __cplusplus extern "C" { #endif - void *dlopen (const char *filename, int flag); - int dlclose (void *handle); - void *dlsym (void *handle, const char *name); - const char *dlerror (void); +void* dlopen(const char* filename, int flag); +int dlclose(void* handle); +void* dlsym(void* handle, const char* name); +const char* dlerror(void); #ifdef __cplusplus } #endif -#endif +#endif \ No newline at end of file diff --git a/lib/functions.md b/lib/functions.md index 69cd538..72e5daf 100644 --- a/lib/functions.md +++ b/lib/functions.md @@ -1,10 +1,10 @@ # 📔 Wopslang Builtin Functions `v0.1` -|Name|Brief Summary|Parameter|Return| -|----|-------------|---------|------| -|out|Standard output|[any s]|None| -|in|Standard input|None|string s| -|toint|Change datatype to integer|any s|int r| -|tostring|Change datatype to string|any s|string r| +| Name | Brief Summary | Parameter | Return | +| -------- | -------------------------- | --------- | -------- | +| out | Standard output | [any s] | none | +| in | Standard input | none | string s | +| toint | Change datatype to integer | any s | int r | +| tostring | Change datatype to string | any s | string r | -2021, Wops Team +2023, Wops Team diff --git a/lib/library.cpp b/lib/library.cpp index d3939b0..0acdcb6 100644 --- a/lib/library.cpp +++ b/lib/library.cpp @@ -6,88 +6,86 @@ * --- * We'll put only I/O functions in Ver 0.1 alpha. * Built-in function development is on the way. Stay tuned. - * - * 2021, Wops Team + * + * 2023, Wops Team * */ -#include -#include #include +#include #include +#include + #include "../src/type/object.h" #include "../src/type/variable.h" // Standard I/O Functions /** -* @brief out([any s]): Standard output -* @name out -* @param [any s] -* @return none -*/ + * @brief out([any s]): Standard output + * @name out + * @param [any s] + * @return none + */ extern "C" Object out(Object s) { - for (Object e: s.GetContainer()) { - if (e.GetBase().GetValue() == "") continue; - if (e.dim) - return {"_", {}, {}, {}, 0, -1, TOO_HIGH_DIMENSION}; - if (e.GetBase()._t == STRING) - std::cout << e.GetBase().trim(e.GetBase().GetValue()); - else - std::cout << e.GetBase().GetValue(); - } - return {"_", {}, {}, {}, 0, -1, OK}; + for (Object e : s.GetContainer()) { + if (e.GetBase().GetValue() == "") continue; + if (e.dim) return {"_", {}, {}, {}, 0, -1, TOO_HIGH_DIMENSION}; + if (e.GetBase()._t == STRING) + std::cout << e.GetBase().trim(e.GetBase().GetValue()); + else + std::cout << e.GetBase().GetValue(); + } + return {"_", {}, {}, {}, 0, -1, OK}; } /** -* @brief string in(): Standard input -* @name in -* @param none -* @return string s -* Terminates inputting when space or new line character is entered -*/ -extern "C" Object in(Object _) { - std::string s; std::cin >> s; - return {"_", {}, {}, Variable("_", "\""+s+"\"", STRING), 0, -1, OK}; + * @brief string in(): Standard input + * @name in + * @param none + * @return string s + * Terminates inputting when space or new line character is entered + */ +extern "C" Object in(Object _) { + std::string s; + std::cin >> s; + return {"_", {}, {}, Variable("_", "\"" + s + "\"", STRING), 0, -1, OK}; } // Type Function /** -* @brief int toint(any s): Change datatype to integer -* @name toint -* @param any s -* @return int r -*/ -extern "C" Object toint(Object s) { - if (s.dim != 1 || s.size[0] != 1) return {"_", {}, {}, {}, 0, -1, TOO_HIGH_DIMENSION}; + * @brief int toint(any s): Change datatype to integer + * @name toint + * @param any s + * @return int r + */ +extern "C" Object toint(Object s) { + if (s.dim != 1 || s.size[0] != 1) return {"_", {}, {}, {}, 0, -1, TOO_HIGH_DIMENSION}; - Object cont = s.GetContainer()[0]; - if (cont.dim) return {"_", {}, {}, {}, 0, -1, TOO_HIGH_DIMENSION}; + Object cont = s.GetContainer()[0]; + if (cont.dim) return {"_", {}, {}, {}, 0, -1, TOO_HIGH_DIMENSION}; - Variable e = cont.GetBase(); - if (e._t == STRING) { - if (e.GetValue()[0] != '"' - || e.GetValue()[e.value.length()-1] != '"' - || e.value.length() < 2 - || std::regex_match(e.trim(e.value), std::regex("/[+-]?\\d+"))) { - return {"_", {}, {}, {}, 0, -1, OBJECT_NOT_MATCHING_DATA}; - } - return {"_", {}, {}, Variable("_", std::to_string(std::stoi(e.trim(e.value)))), 0, -1, OK}; + Variable e = cont.GetBase(); + if (e._t == STRING) { + if (e.GetValue()[0] != '"' || e.GetValue()[e.value.length() - 1] != '"' || e.value.length() < 2 || std::regex_match(e.trim(e.value), std::regex("/[+-]?\\d+"))) { + return {"_", {}, {}, {}, 0, -1, OBJECT_NOT_MATCHING_DATA}; } - return {"_", {}, {}, Variable("_", std::to_string(std::stoi(e.value)), INT), 0, -1, OK}; + return {"_", {}, {}, Variable("_", std::to_string(std::stoi(e.trim(e.value)))), 0, -1, OK}; + } + return {"_", {}, {}, Variable("_", std::to_string(std::stoi(e.value)), INT), 0, -1, OK}; } /** -* @brief string tostring(any s): Change datatype to string -* @name tostring -* @param any s -* @return string r -*/ -extern "C" Object tostring(Object s) { - if (s.dim != 1 || s.size[0] != 1) return {"_", {}, {}, {}, 0, -1, TOO_HIGH_DIMENSION}; + * @brief string tostring(any s): Change datatype to string + * @name tostring + * @param any s + * @return string r + */ +extern "C" Object tostring(Object s) { + if (s.dim != 1 || s.size[0] != 1) return {"_", {}, {}, {}, 0, -1, TOO_HIGH_DIMENSION}; - Object cont = s.GetContainer()[0]; - if (cont.dim) return {"_", {}, {}, {}, 0, -1, TOO_HIGH_DIMENSION}; + Object cont = s.GetContainer()[0]; + if (cont.dim) return {"_", {}, {}, {}, 0, -1, TOO_HIGH_DIMENSION}; - Variable e = cont.GetBase(); - return {"_", {}, {}, Variable("_", "\""+e.GetValue()+"\"", STRING), 0, -1, OK}; + Variable e = cont.GetBase(); + return {"_", {}, {}, Variable("_", "\"" + e.GetValue() + "\"", STRING), 0, -1, OK}; } \ No newline at end of file diff --git a/sample/fizzbuzz.wops b/sample/fizzbuzz.wops index 2aa1698..87a0fc8 100644 --- a/sample/fizzbuzz.wops +++ b/sample/fizzbuzz.wops @@ -1,8 +1,8 @@ // // sample/fizzbuzz.wops -// Wopslang Sample for v0.1.x +// Wopslang Sample for v0.1 // -// 2021, Wops Team +// 2023, Wops Team // int n = 100 diff --git a/sample/hailstone_sequence.wops b/sample/hailstone_sequence.wops index 6814777..1c65fd1 100644 --- a/sample/hailstone_sequence.wops +++ b/sample/hailstone_sequence.wops @@ -1,8 +1,8 @@ // // sample/hailstone_sequence.wops -// Wopslang Sample for v0.1.x +// Wopslang Sample for v0.1 // -// 2022, Wops Team +// 2023, Wops Team // int a = 100 diff --git a/sample/hello_wopslang.wops b/sample/hello_wopslang.wops index d287280..6a02045 100644 --- a/sample/hello_wopslang.wops +++ b/sample/hello_wopslang.wops @@ -1,8 +1,8 @@ // // sample/hello_wopslang.wops -// Wopslang Sample for v0.1.x +// Wopslang Sample for v0.1 // -// 2021, Wops Team +// 2023, Wops Team // out("Hello, Wopslang!\n") diff --git a/sample/multiline.wops b/sample/multiline.wops new file mode 100644 index 0000000..8a5d58b --- /dev/null +++ b/sample/multiline.wops @@ -0,0 +1,31 @@ +// +// sample/multiline.wops +// Wopslang Sample for v0.1 +// +// 2023, Wops Team +// +// THIS IS ONLY A TOY CODE TO TEST PARSING SYSTEM +// +// Pretier code: +// +// int a = 100 * toint(in()) +// for i in 0~a+1 $ +// out(tostring(i) + ", ") +// ; +// out("Wonderful ", "Parser!") +// + +int a = ( + 100 + * + toint( + in() + ) +) + +for i in 0~(a + + 1) $ + out(tostring(i) + + ", " + ); out("Wonderful ", + "Parser!") \ No newline at end of file diff --git a/src/error/signal.h b/src/error/signal.h index b2794ff..843486c 100644 --- a/src/error/signal.h +++ b/src/error/signal.h @@ -2,7 +2,7 @@ * src/error/signal.h * Wopslang Error Signal Headerfile * - * 2021, Wops Team + * 2023, Wops Team * */ #ifndef WOPS_ERRORSIGNAL_H @@ -10,138 +10,182 @@ #include #include + #include "../../include/basis.h" // enum Err // Enumeration of error types enum Err { - OK, - ERROR, - INTERPRETER_CANNOT_OPEN_FILE, - NO_MATCHING_SYNTAX_FOR, - NO_MATCHING_SYNTAX_IF, - NO_MATCHING_SYNTAX_ELIF, - NO_MATCHING_SYNTAX_BREAK, - NO_MATCHING_SYNTAX_CONTINUE, - VARIABLE_HAS_NOT_DECLARED, - VARIABLE_REDECLARE, - ERROR_OCCURED_WHILE_CALLING_FUNCTION, - BREAK_CONTINUE_ONLY_ALLOWED_FOR, - ASSIGN_ON_CONSTANT, - ASSIGN_ON_UNKNOWN, - IF_NO_BOOLEAN_CONDITION, - ELIF_NO_BOOLEAN_CONDITION, - FOR_NO_BOOLEAN_CONDITION, - CANNOT_LOAD_LIBRARY, - CANNOT_LOAD_SYMBOL, - OBJECT_OVERFLOW, - OBJECT_NOT_MATCHING_DATA, - OBJECT_WRONG_DIMENSION, - TOO_HIGH_DIMENSION, - UNMATCHED_PARENTHESIS, - OPERATION_ONLY_BINARY, + OK, + ERROR, + INTERPRETER_CANNOT_OPEN_FILE, + BLANK_VARIABLE_NAME, + BLANK_OPERAND, + BLANK_PARAMETER, + NO_IDENTIFIER_AFTER_OPERATOR, + NO_OPERATION_MATCHING_TYPE, + NO_OPERATION_MATCHING_TYPE_UNARY, + NO_MATCHING_UNARY_OPERATION_FORM, + NO_MATCHING_SYNTAX_EXPRESSION, + NO_MATCHING_SYNTAX_FOR, + NO_MATCHING_SYNTAX_IF, + NO_MATCHING_SYNTAX_ELIF, + NO_MATCHING_STRUCTURE_IF, + NO_MATCHING_SYNTAX_BREAK, + NO_MATCHING_SYNTAX_CONTINUE, + NOT_MATCHING_TYPE_WITH_DEF, + NOT_MATCHING_TYPE_WHEN_COMP, + NOT_CLOSED_BLOCK, + VARIABLE_HAS_NOT_DECLARED, + VARIABLE_REDECLARE, + ERROR_OCCURED_WHILE_CALLING_FUNCTION, + BREAK_CONTINUE_ONLY_ALLOWED_FOR, + ASSIGN_ON_CONSTANT, + ASSIGN_ON_UNKNOWN, + IF_NO_BOOLEAN_CONDITION, + ELIF_NO_BOOLEAN_CONDITION, + FOR_NO_BOOLEAN_CONDITION, + CANNOT_LOAD_LIBRARY, + CANNOT_LOAD_SYMBOL, + OBJECT_OVERFLOW, + OBJECT_NOT_MATCHING_DATA, + OBJECT_WRONG_DIMENSION, + TOO_HIGH_DIMENSION, + UNMATCHED_PARENTHESIS, + OPERATION_ONLY_BINARY, + DIVIDING_WITH_ZERO, }; class ErrHandler { - public: - void CallErr(int error_pos, Err errtype, std::vector arg) { - std::string errmsg; - switch (errtype) { - case OK: - errmsg = "OKAY"; - break; - case ERROR: - errmsg = "ERROR"; - break; - case INTERPRETER_CANNOT_OPEN_FILE: - errmsg = "From Interpreter: cannot open the file"; - break; - case NO_MATCHING_SYNTAX_FOR: - errmsg = "No matching syntax: for"; - break; - case NO_MATCHING_SYNTAX_IF: - errmsg = "No matching syntax: if"; - break; - case NO_MATCHING_SYNTAX_ELIF: - errmsg = "No matching syntax: elif"; - break; - case NO_MATCHING_SYNTAX_BREAK: - errmsg = "No matching syntax: break"; - break; - case NO_MATCHING_SYNTAX_CONTINUE: - errmsg = "No matching syntax: continue"; - break; - case VARIABLE_HAS_NOT_DECLARED: - errmsg = arg[0] + " has not declared yet"; - break; - case VARIABLE_REDECLARE: - errmsg = "Redeclared variable " + arg[0] + ""; - break; - case ERROR_OCCURED_WHILE_CALLING_FUNCTION: - errmsg = "Error occured while calling " + arg[0] + ""; - break; - case BREAK_CONTINUE_ONLY_ALLOWED_FOR: - errmsg = "break and continue statement only allowed to be used in for statements"; - break; - case ASSIGN_ON_CONSTANT: - errmsg = arg[0] + " is constant"; - break; - case ASSIGN_ON_UNKNOWN: - errmsg = "Variable " + arg[0] + " hasn't declared yet"; - break; - case IF_NO_BOOLEAN_CONDITION: - errmsg = "If Statement allows only boolean condition expression"; - break; - case ELIF_NO_BOOLEAN_CONDITION: - errmsg = "Elif Statement allows only boolean condition expression"; - break; - case FOR_NO_BOOLEAN_CONDITION: - errmsg = "For Statement allows only boolean condition expression"; - break; - case CANNOT_LOAD_LIBRARY: - errmsg = "Cannot load library: " + arg[0] + ""; - break; - case CANNOT_LOAD_SYMBOL: - errmsg = "Cannot load symbol: " + arg[0] + ""; - break; - case OBJECT_OVERFLOW: - errmsg = "Size of object " + arg[0] + " is over than limit"; - break; - case OBJECT_NOT_MATCHING_DATA: - errmsg = "Data of object " + arg[0] + " does not match with declaration"; - break; - case OBJECT_WRONG_DIMENSION: - errmsg = "Object " + arg[0] + " has wrong dimension (Expected " + arg[1] + ", Found " + arg[2] + ")"; - break; - case TOO_HIGH_DIMENSION: - errmsg = arg[0] + " has too high dimension for job (Expected " + arg[1] + ", Found " + arg[2] + ")"; - break; - case UNMATCHED_PARENTHESIS: - errmsg = "Unmatched parenthesis"; - break; - case OPERATION_ONLY_BINARY: - errmsg = "Operation " + arg[0] + " cannot be unary"; - break; - } - if (error_pos != -1) { - std::cout << "\e[31m"<< "line " << error_pos << ": " << errmsg << "\e[m."; - exit(1); - } - std::cout << "\e[31m"<< "runtime: " << errmsg << "\e[m."; - exit(1); - return; + public: + void CallErr(int error_pos, Err errtype, std::vector arg) { + std::string errmsg; + switch (errtype) { + case OK: + errmsg = "OKAY"; + break; + case ERROR: + errmsg = "ERROR"; + break; + case INTERPRETER_CANNOT_OPEN_FILE: + errmsg = "From Interpreter: cannot open the file"; + break; + case BLANK_VARIABLE_NAME: + errmsg = "Name of variable should not be blank"; + break; + case BLANK_OPERAND: + errmsg = "Operand should not be blank"; + break; + case BLANK_PARAMETER: + errmsg = "Parameter should not be blank"; + break; + case NO_IDENTIFIER_AFTER_OPERATOR: + errmsg = "Operator " + arg[0] + " cannot appear after identifer"; + break; + case NO_OPERATION_MATCHING_TYPE: + errmsg = "Operator " + arg[0] + " doesn't have operation between " + arg[1] + " and " + arg[2]; + break; + case NO_OPERATION_MATCHING_TYPE_UNARY: + errmsg = "Operator " + arg[0] + " doesn't have operation with " + arg[1]; + break; + case NO_MATCHING_UNARY_OPERATION_FORM: + errmsg = "No matching unary operation form: " + arg[0]; + break; + case NO_MATCHING_SYNTAX_EXPRESSION: + errmsg = "No matching syntax: expression"; + break; + case NO_MATCHING_SYNTAX_FOR: + errmsg = "No matching syntax: for"; + break; + case NO_MATCHING_SYNTAX_IF: + errmsg = "No matching syntax: if"; + break; + case NO_MATCHING_SYNTAX_ELIF: + errmsg = "No matching syntax: elif"; + break; + case NO_MATCHING_STRUCTURE_IF: + errmsg = "No matching structure: if-elif-else"; + break; + case NO_MATCHING_SYNTAX_BREAK: + errmsg = "No matching syntax: break"; + break; + case NO_MATCHING_SYNTAX_CONTINUE: + errmsg = "No matching syntax: continue"; + break; + case NOT_MATCHING_TYPE_WITH_DEF: + errmsg = "Type of " + arg[0] + " doesn't match with definition, " + arg[1]; + break; + case NOT_MATCHING_TYPE_WHEN_COMP: + errmsg = "Comparing with different type variables is not allowed (" + arg[0] + ", " + arg[1] + ")"; + break; + case NOT_CLOSED_BLOCK: + errmsg = "Block is not closed"; + break; + case VARIABLE_HAS_NOT_DECLARED: + errmsg = arg[0] + " has not declared yet"; + break; + case VARIABLE_REDECLARE: + errmsg = "Redeclared variable " + arg[0] + ""; + break; + case ERROR_OCCURED_WHILE_CALLING_FUNCTION: + errmsg = "Error occured while calling " + arg[0] + ""; + break; + case BREAK_CONTINUE_ONLY_ALLOWED_FOR: + errmsg = "break and continue statement only allowed to be used in for statements"; + break; + case ASSIGN_ON_CONSTANT: + errmsg = arg[0] + " is constant"; + break; + case ASSIGN_ON_UNKNOWN: + errmsg = "Variable " + arg[0] + " hasn't declared yet"; + break; + case IF_NO_BOOLEAN_CONDITION: + errmsg = "If Statement allows only boolean condition expression"; + break; + case ELIF_NO_BOOLEAN_CONDITION: + errmsg = "Elif Statement allows only boolean condition expression"; + break; + case FOR_NO_BOOLEAN_CONDITION: + errmsg = "For Statement allows only boolean condition expression"; + break; + case CANNOT_LOAD_LIBRARY: + errmsg = "Cannot load library: " + arg[0] + ""; + break; + case CANNOT_LOAD_SYMBOL: + errmsg = "Cannot load symbol: " + arg[0] + ""; + break; + case OBJECT_OVERFLOW: + errmsg = "Size of object " + arg[0] + " is over than limit"; + break; + case OBJECT_NOT_MATCHING_DATA: + errmsg = "Data of object " + arg[0] + " does not match with declaration"; + break; + case OBJECT_WRONG_DIMENSION: + errmsg = "Object " + arg[0] + " has wrong dimension (Expected " + arg[1] + ", Found " + arg[2] + ")"; + break; + case TOO_HIGH_DIMENSION: + errmsg = arg[0] + " has too high dimension for job (Expected " + arg[1] + ", Found " + arg[2] + ")"; + break; + case UNMATCHED_PARENTHESIS: + errmsg = "Unmatched parenthesis"; + break; + case OPERATION_ONLY_BINARY: + errmsg = "Operation " + arg[0] + " cannot be unary"; + break; + case DIVIDING_WITH_ZERO: + errmsg = "Dividing with zero is not allowed"; + break; } - - // Deprecated - void CallErrDE(int error_pos, std::string errmsg) { - if (error_pos != -1) { - std::cout << "\e[31m"<< "line " << error_pos << ": " << errmsg << "\e[m."; - exit(1); - } - std::cout << "\e[31m"<< "runtime: " << errmsg << "\e[m."; - exit(1); - return; + if (error_pos != -1) { + std::cout << "\e[31m" + << "line " << error_pos << ": " << errmsg << "\e[m."; + exit(1); } + std::cout << "\e[31m" + << "runtime: " << errmsg << "\e[m."; + exit(1); + return; + } }; -#endif +#endif \ No newline at end of file diff --git a/src/import_/eexec_.cpp b/src/import_/eexec_.cpp index 32e0619..ed132e1 100644 --- a/src/import_/eexec_.cpp +++ b/src/import_/eexec_.cpp @@ -2,43 +2,42 @@ * src/import_/eexec_.cpp * Wopslang External Function Executor Sourcefile * - * 2021, Wops Team + * 2023, Wops Team * */ - #include "eexec_.h" // Object EExecFunc(std::string func, Object argv) // Calls a function with argv as a parameter and func as a name. Object EExecFunc(std::string func, Object argv) { - // EMPTY VARIABLE - Object null("_", {}, {}, Variable("_", "", INT), 0); - - void* handle = dlopen("lib/library.so", RTLD_LAZY); - - if (!handle) { - ErrHandler().CallErr(-1, CANNOT_LOAD_LIBRARY, {std::string(dlerror())}); - null.errvalue = CANNOT_LOAD_LIBRARY; - return null; - } - - // function pointer - typedef Object (*t)(Object); - - // reset errors - dlerror(); - - std::string exfunc(func); - t fptr = (t) dlsym(handle, exfunc.c_str()); - const char *dlsym_error = dlerror(); - if (dlsym_error) { - ErrHandler().CallErr(-1, CANNOT_LOAD_SYMBOL, {func}); - dlclose(handle); - null.errvalue = CANNOT_LOAD_SYMBOL; - return null; - } - - Object ret = fptr(argv); + // EMPTY VARIABLE + Object null("_", {}, {}, Variable("_", "", INT), 0); + + void* handle = dlopen("lib/library.so", RTLD_LAZY); + + if (!handle) { + ErrHandler().CallErr(-1, CANNOT_LOAD_LIBRARY, {std::string(dlerror())}); + null.errvalue = CANNOT_LOAD_LIBRARY; + return null; + } + + // function pointer + typedef Object (*t)(Object); + + // reset errors + dlerror(); + + std::string exfunc(func); + t fptr = (t)dlsym(handle, exfunc.c_str()); + const char* dlsym_error = dlerror(); + if (dlsym_error) { + ErrHandler().CallErr(-1, CANNOT_LOAD_SYMBOL, {func}); dlclose(handle); - return ret; -} + null.errvalue = CANNOT_LOAD_SYMBOL; + return null; + } + + Object ret = fptr(argv); + dlclose(handle); + return ret; +} \ No newline at end of file diff --git a/src/import_/eexec_.h b/src/import_/eexec_.h index 38d49b4..f48b9ca 100644 --- a/src/import_/eexec_.h +++ b/src/import_/eexec_.h @@ -2,7 +2,7 @@ * src/import_/eexec_.h * Wopslang External Function Executor Headerfile * - * 2021, Wops Team + * 2023, Wops Team * */ #ifdef _WIN32 @@ -13,9 +13,10 @@ #include #include -#include "../type/variable.h" -#include "../type/object.h" + #include "../error/signal.h" +#include "../type/object.h" +#include "../type/variable.h" #ifndef WOPS_EEXEC_H #define WOPS_EEXEC_H @@ -26,4 +27,4 @@ Calls a function with argv as a parameter and func as a name. */ Object EExecFunc(std::string func, Object argv); -#endif +#endif \ No newline at end of file diff --git a/src/interpreter.cpp b/src/interpreter.cpp index 39da378..c44b308 100644 --- a/src/interpreter.cpp +++ b/src/interpreter.cpp @@ -2,51 +2,60 @@ * src/interpreter.cpp * Wopslang Interpreter Sourcefile * - * 2021, Wops Team + * 2023, Wops Team * * */ -#include #include -#include "runtime/AST.h" +#include + #include "parser/parse.h" +#include "runtime/AST.h" + +int main(int argc, char** argv) { + std::cout << "\e[31m" + << "Warning: This is alpha version. Some critical issues might be appeared." + << "\e[m\n"; + if (argc == 2 || (argc == 3 && String(argv[2]) == "debug") || (argc == 3 && String(argv[2]) == "check")) { + std::ifstream handler(String(argv[1]).data()); + if (!handler.is_open()) ErrHandler().CallErr(-1, INTERPRETER_CANNOT_OPEN_FILE, {}); + + String codeline; + std::vector code; -int main(int argc, char **argv) { - std::cout << "\e[31m" << "Warning: This is alpha version. Some critical issues might be appeared." << "\e[m\n"; - if (argc == 2 || (argc == 3 && String(argv[2]) == "debug") || (argc == 3 && String(argv[2]) == "check")) { - std::ifstream handler(String(argv[1]).data()); - if (!handler.is_open()) - ErrHandler().CallErr(-1, INTERPRETER_CANNOT_OPEN_FILE, {}); - - String codeline; - std::vector code; - - while (std::getline(handler, codeline)) { - code.push_back(codeline); - } - - handler.close(); - - // interpret - std::vector stor; - stor.push_back(Storage()); - AST main(Main, {}, {}, 0); - - if (argc == 3 && String(argv[2]) == "debug") { - std::clock_t end, start = clock(); - Parse(main, code); - main.Execute(stor); - end = clock(); - std::cout << "\n=== DEBUG ===\n\e[32m" << "Running Time(ms): " << (double)(end-start) * 1000 / CLOCKS_PER_SEC << "\e[m\n"; - return 0; - } - if (argc == 3 && String(argv[2]) == "check") { - Parse(main, code); - return 0; - } - Parse(main, code); - main.Execute(stor); - } else { - std::cout << "\e[93m" << "Incorrect command structure. Use command 'Wopslang '" << "\e[m\n"; + while (std::getline(handler, codeline)) { + code.push_back(codeline); + } + + handler.close(); + + // interpret + std::vector stor; + std::vector Token_storage; + std::vector> token_table; + + for (String s : code) token_table.push_back(GetTokenTable(s)); + stor.push_back(Storage()); + AST main(Main, {}, {}, 1); + + if (argc == 3 && String(argv[2]) == "debug") { + std::clock_t end, start = clock(); + Parse(main, token_table, 0, 0, Token_storage); + main.Execute(stor); + end = clock(); + std::cout << "\n=== DEBUG ===\n\e[32m" + << "Running Time(ms): " << (double)(end - start) * 1000 / CLOCKS_PER_SEC << "\e[m\n"; + return 0; + } + if (argc == 3 && String(argv[2]) == "check") { + Parse(main, token_table, 0, 0, Token_storage); + return 0; } -} + Parse(main, token_table, 0, 0, Token_storage); + main.Execute(stor); + } else { + std::cout << "\e[93m" + << "Incorrect command structure. Use command 'Wopslang '" + << "\e[m\n"; + } +} \ No newline at end of file diff --git a/src/parser/parse.cpp b/src/parser/parse.cpp index ad153d4..9aeaef2 100644 --- a/src/parser/parse.cpp +++ b/src/parser/parse.cpp @@ -2,26 +2,22 @@ * src/parser/parse.cpp * Wopslang Parsing Sourcefile * - * 2021, Wops Team + * 2023, Wops Team * * */ #include "parse.h" std::vector oprs{ - '+', '-', '*', '/', '%', '=', '>', '<', '!', '&', '|', '(', ')', '[', ']', ':', ';', ',', '?', '$', '~', + '+', '-', '*', '/', '%', '=', '>', '<', '!', '&', '|', '(', ')', '[', ']', ';', ',', '?', '$', '~', }; -std::vector operators{ - "+", "-", "*", "/", "%", "=", "==", "!=", ">", "<", ">=", "<=", "!", "&&", "||", "//" -}; +std::vector operators{"+", "-", "*", "/", "%", "=", "==", "!=", ">", "<", ">=", "<=", "!", "&&", "||", "//"}; -std::vector> runes{ - {"\a", "a"}, {"\b", "b"}, {"\f", "f"}, {"\n", "n"}, {"\r", "r"}, {"\t", "t"}, {"\v", "v"}, {"\\", "\\"}, {"\'", "'"}, {"\"", "\""} -}; +std::vector> runes{{"\a", "a"}, {"\b", "b"}, {"\f", "f"}, {"\n", "n"}, {"\r", "r"}, {"\t", "t"}, {"\v", "v"}, {"\\", "\\"}, {"\'", "'"}, {"\"", "\""}}; // TODO: improve library system -std::vector funcs {"in", "out", "tostring", "toint"}; +std::vector funcs{"in", "out", "tostring", "toint"}; // TODO: develop this function // Expr ParseExpr(std::vector tokens, int parsing_line) @@ -34,624 +30,1048 @@ std::vector funcs {"in", "out", "tostring", "toint"}; // Deprecated Expr ParseExpr(std::vector tokens, int parsing_line) { - Expr head({0,0,0}, - Object("_", {}, {}, Variable("_", "", OPERATOR), 0, parsing_line, OK), parsing_line); - - if (tokens.size() >= 3 && std::find(funcs.begin(), funcs.end(), tokens[0]) != funcs.end() && - tokens[1] == "(" && tokens[tokens.size()-1] == ")") { - int level = 0; bool isSuitable = 1; - for (int idx = 1; idx < tokens.size(); idx++) { - String token = tokens[idx]; - if (token == "(") level++; - else if (token == ")") level--; - else if (!level) isSuitable = 0; - } - if (isSuitable) { - head = Expr({0,0,1}, Object("_", {}, {}, Variable("_", tokens[0], OPERATOR), 0, parsing_line, OK), parsing_line); - std::vector parameter; - for (int idx = 2; idx < tokens.size()-1; idx++) { - if (tokens[idx] == ",") { - if (parameter.size() == 0) ErrHandler().CallErrDE(parsing_line, "Blank parameter"); - head.AddChild(ParseExpr(parameter, parsing_line)); - parameter.clear(); - continue; - } - parameter.push_back(tokens[idx]); - } - if (parameter.size() != 0) - head.AddChild(ParseExpr(parameter, parsing_line)); - return head; - } - } + Expr head({0, 0, 0}, Object("_", {}, {}, Variable("_", "", OPERATOR), 0, parsing_line, OK), parsing_line); - if (tokens[0] == "(" && tokens[tokens.size()-1] == ")") { - int level = 0; bool isSuitable = 1; - for (int idx = 0; idx < tokens.size(); idx++) { - String token = tokens[idx]; - if (token == "(") level++; - else if (token == ")") level--; - else if (!level) isSuitable = 0; - } - if (isSuitable) - tokens = std::vector(tokens.begin()+1, tokens.end()-1); - } + if (tokens.size() == 0) ErrHandler().CallErr(parsing_line, BLANK_OPERAND, {}); - if (tokens.size() == 0) ErrHandler().CallErrDE(parsing_line, "No operand"); - if (tokens.size() == 1) { - if (std::regex_match(tokens[0], std::regex("[0-9]+"))) { - head = Expr({1, 0, 0}, Object("_", {}, {}, Variable("_", tokens[0], INT), 0, parsing_line), parsing_line); - } else if (std::regex_match(tokens[0], std::regex("[0-9]+.[0-9]+"))) { - head = Expr({1, 0, 0}, Object("_", {}, {}, Variable("_", tokens[0], DOUBLE), 0, parsing_line), parsing_line); - } else if (tokens[0][0] == '\"' && tokens[0][tokens[0].length()-1] == '\"') { - head = Expr({1, 0, 0}, Object("_", {}, {}, Variable("_", tokens[0], STRING), 0, parsing_line), parsing_line); - } else { - head = Expr({0, 1, 0}, Object("_", {}, {}, Variable("_", tokens[0], OPERATOR), 0, parsing_line), parsing_line); + if (tokens.size() >= 3 && std::find(funcs.begin(), funcs.end(), tokens[0]) != funcs.end() && tokens[1] == "(" && tokens[tokens.size() - 1] == ")") { + int level = 0; + bool isSuitable = 1; + for (int idx = 1; idx < tokens.size(); idx++) { + String token = tokens[idx]; + if (token == "(") + level++; + else if (token == ")") + level--; + else if (!level) + isSuitable = 0; + } + if (isSuitable) { + head = Expr({0, 0, 1}, Object("_", {}, {}, Variable("_", tokens[0], OPERATOR), 0, parsing_line, OK), parsing_line); + std::vector parameter; + for (int idx = 2; idx < tokens.size() - 1; idx++) { + if (tokens[idx] == ",") { + if (parameter.size() == 0) ErrHandler().CallErr(parsing_line, BLANK_PARAMETER, {}); + head.AddChild(ParseExpr(parameter, parsing_line)); + parameter.clear(); + continue; } - return head; + parameter.push_back(tokens[idx]); + } + if (parameter.size() != 0) head.AddChild(ParseExpr(parameter, parsing_line)); + return head; } + } - std::vector isTarget(tokens.size(), 0); + if (tokens[0] == "(" && tokens[tokens.size() - 1] == ")") { int level = 0; + bool isSuitable = 1; for (int idx = 0; idx < tokens.size(); idx++) { - String token = tokens[idx]; - if (token == "(") level++; - else if (token == ")") level--; - else if (!level) isTarget[idx] = 1; + String token = tokens[idx]; + if (token == "(") + level++; + else if (token == ")") + level--; + else if (!level) + isSuitable = 0; } - if (level != 0) ErrHandler().CallErr(parsing_line, UNMATCHED_PARENTHESIS, {}); - - // priority 1 - for (int idx = 0; idx < tokens.size(); idx++) { - if (!isTarget[idx]) continue; - String token = tokens[idx]; - if (token == "||") { - if (idx == 0 || idx == tokens.size()-1) ErrHandler().CallErr(parsing_line, OPERATION_ONLY_BINARY, {"||"}); - head = Expr({0, 0, 0}, Object("_", {}, {}, Variable("_", "||", OPERATOR), 0, parsing_line), parsing_line); - head.SetChildren({ - ParseExpr(std::vector(tokens.begin(), tokens.begin()+idx), parsing_line), - ParseExpr(std::vector(tokens.begin()+idx+1, tokens.end()), parsing_line) - }); - return head; + if (isSuitable) tokens = std::vector(tokens.begin() + 1, tokens.end() - 1); + } + + if (tokens.size() == 1) { + if (std::regex_match(tokens[0], std::regex("[0-9]+"))) { + head = Expr({1, 0, 0}, Object("_", {}, {}, Variable("_", tokens[0], INT), 0, parsing_line), parsing_line); + } else if (std::regex_match(tokens[0], std::regex("[0-9]+.[0-9]+"))) { + head = Expr({1, 0, 0}, Object("_", {}, {}, Variable("_", tokens[0], DOUBLE), 0, parsing_line), parsing_line); + } else if (tokens[0][0] == '\"' && tokens[0][tokens[0].length() - 1] == '\"') { + head = Expr({1, 0, 0}, Object("_", {}, {}, Variable("_", tokens[0], STRING), 0, parsing_line), parsing_line); + } else { + head = Expr({0, 1, 0}, Object("_", {}, {}, Variable("_", tokens[0], OPERATOR), 0, parsing_line), parsing_line); + } + return head; + } + + std::vector isTarget(tokens.size(), 0); + int level = 0; + for (int idx = 0; idx < tokens.size(); idx++) { + String token = tokens[idx]; + if (token == "(") + level++; + else if (token == ")") + level--; + else if (!level) + isTarget[idx] = 1; + } + if (level != 0) ErrHandler().CallErr(parsing_line, UNMATCHED_PARENTHESIS, {}); + + // priority 1 + for (int idx = 0; idx < tokens.size(); idx++) { + if (!isTarget[idx]) continue; + String token = tokens[idx]; + if (token == "||") { + if (idx == 0 || idx == tokens.size() - 1) ErrHandler().CallErr(parsing_line, OPERATION_ONLY_BINARY, {"||"}); + head = Expr({0, 0, 0}, Object("_", {}, {}, Variable("_", "||", OPERATOR), 0, parsing_line), parsing_line); + head.SetChildren({ParseExpr(std::vector(tokens.begin(), tokens.begin() + idx), parsing_line), ParseExpr(std::vector(tokens.begin() + idx + 1, tokens.end()), parsing_line)}); + return head; + } + } + + // priority 2 + for (int idx = 0; idx < tokens.size(); idx++) { + if (!isTarget[idx]) continue; + String token = tokens[idx]; + if (token == "&&") { + if (idx == 0 || idx == tokens.size() - 1) ErrHandler().CallErr(parsing_line, OPERATION_ONLY_BINARY, {"&&"}); + head = Expr({0, 0, 0}, Object("_", {}, {}, Variable("_", "&&", OPERATOR), 0, parsing_line), parsing_line); + head.SetChildren({ParseExpr(std::vector(tokens.begin(), tokens.begin() + idx), parsing_line), ParseExpr(std::vector(tokens.begin() + idx + 1, tokens.end()), parsing_line)}); + return head; + } + } + + // priority 3 + for (int idx = 0; idx < tokens.size(); idx++) { + if (!isTarget[idx]) continue; + String token = tokens[idx]; + if (token == "==") { + if (idx == 0 || idx == tokens.size() - 1) ErrHandler().CallErr(parsing_line, OPERATION_ONLY_BINARY, {"=="}); + head = Expr({0, 0, 0}, Object("_", {}, {}, Variable("_", "==", OPERATOR), 0, parsing_line), parsing_line); + head.SetChildren({ParseExpr(std::vector(tokens.begin(), tokens.begin() + idx), parsing_line), ParseExpr(std::vector(tokens.begin() + idx + 1, tokens.end()), parsing_line)}); + return head; + } + if (token == "!=") { + if (idx == 0 || idx == tokens.size() - 1) ErrHandler().CallErr(parsing_line, OPERATION_ONLY_BINARY, {"!="}); + head = Expr({0, 0, 0}, Object("_", {}, {}, Variable("_", "!=", OPERATOR), 0, parsing_line), parsing_line); + head.SetChildren({ParseExpr(std::vector(tokens.begin(), tokens.begin() + idx), parsing_line), ParseExpr(std::vector(tokens.begin() + idx + 1, tokens.end()), parsing_line)}); + return head; + } + if (token == "<") { + if (idx == 0 || idx == tokens.size() - 1) ErrHandler().CallErr(parsing_line, OPERATION_ONLY_BINARY, {"<"}); + head = Expr({0, 0, 0}, Object("_", {}, {}, Variable("_", "<", OPERATOR), 0, parsing_line), parsing_line); + head.SetChildren({ParseExpr(std::vector(tokens.begin(), tokens.begin() + idx), parsing_line), ParseExpr(std::vector(tokens.begin() + idx + 1, tokens.end()), parsing_line)}); + return head; + } + if (token == "<=") { + if (idx == 0 || idx == tokens.size() - 1) ErrHandler().CallErr(parsing_line, OPERATION_ONLY_BINARY, {"<="}); + head = Expr({0, 0, 0}, Object("_", {}, {}, Variable("_", "<=", OPERATOR), 0, parsing_line), parsing_line); + head.SetChildren({ParseExpr(std::vector(tokens.begin(), tokens.begin() + idx), parsing_line), ParseExpr(std::vector(tokens.begin() + idx + 1, tokens.end()), parsing_line)}); + return head; + } + if (token == ">") { + if (idx == 0 || idx == tokens.size() - 1) ErrHandler().CallErr(parsing_line, OPERATION_ONLY_BINARY, {">"}); + head = Expr({0, 0, 0}, Object("_", {}, {}, Variable("_", ">", OPERATOR), 0, parsing_line), parsing_line); + head.SetChildren({ParseExpr(std::vector(tokens.begin(), tokens.begin() + idx), parsing_line), ParseExpr(std::vector(tokens.begin() + idx + 1, tokens.end()), parsing_line)}); + return head; + } + if (token == ">=") { + if (idx == 0 || idx == tokens.size() - 1) ErrHandler().CallErr(parsing_line, OPERATION_ONLY_BINARY, {">="}); + head = Expr({0, 0, 0}, Object("_", {}, {}, Variable("_", ">=", OPERATOR), 0, parsing_line), parsing_line); + head.SetChildren({ParseExpr(std::vector(tokens.begin(), tokens.begin() + idx), parsing_line), ParseExpr(std::vector(tokens.begin() + idx + 1, tokens.end()), parsing_line)}); + return head; + } + } + + // priority 4 + for (int idx = 0; idx < tokens.size(); idx++) { + String token = tokens[idx]; + if (!isTarget[idx]) continue; + if (token == "+") { + if (idx != 0 && std::find(operators.begin(), operators.end(), tokens[idx - 1]) != operators.end()) continue; + if (idx == tokens.size() - 1) ErrHandler().CallErr(parsing_line, OPERATION_ONLY_BINARY, {"+"}); + if (idx == 0) { + if (tokens.size() != 2) ErrHandler().CallErr(parsing_line, NO_MATCHING_UNARY_OPERATION_FORM, {"+"}); + if (std::regex_match(tokens[1], std::regex("[0-9]+"))) { + head = Expr({1, 0, 0}, Object("_", {}, {}, Variable("_", tokens[1], INT), 0, parsing_line), parsing_line); + } else if (std::regex_match(tokens[1], std::regex("[0-9]+.[0-9]+"))) { + head = Expr({1, 0, 0}, Object("_", {}, {}, Variable("_", tokens[1], DOUBLE), 0, parsing_line), parsing_line); + } else if (tokens[1][0] == '\"' && tokens[1][tokens[1].length() - 1] == '\"') { + ErrHandler().CallErr(parsing_line, NO_OPERATION_MATCHING_TYPE_UNARY, {"+", "string"}); + } else { + ErrHandler().CallErr(parsing_line, NO_OPERATION_MATCHING_TYPE_UNARY, {"+", "lvalue"}); } + return head; + } + head = Expr({0, 0, 0}, Object("_", {}, {}, Variable("_", "+", OPERATOR), 0, parsing_line), parsing_line); + head.SetChildren({ParseExpr(std::vector(tokens.begin(), tokens.begin() + idx), parsing_line), ParseExpr(std::vector(tokens.begin() + idx + 1, tokens.end()), parsing_line)}); + return head; } - - // priority 2 - for (int idx = 0; idx < tokens.size(); idx++) { - if (!isTarget[idx]) continue; - String token = tokens[idx]; - if (token == "&&") { - if (idx == 0 || idx == tokens.size()-1) ErrHandler().CallErr(parsing_line, OPERATION_ONLY_BINARY, {"&&"}); - head = Expr({0, 0, 0}, Object("_", {}, {}, Variable("_", "&&", OPERATOR), 0, parsing_line), parsing_line); - head.SetChildren({ - ParseExpr(std::vector(tokens.begin(), tokens.begin()+idx), parsing_line), - ParseExpr(std::vector(tokens.begin()+idx+1, tokens.end()), parsing_line) - }); - return head; + if (token == "-") { + if (idx == tokens.size() - 1) ErrHandler().CallErr(parsing_line, OPERATION_ONLY_BINARY, {"-"}); + if (std::find(operators.begin(), operators.end(), tokens[idx - 1]) != operators.end()) continue; + if (idx == 0) { + if (tokens.size() != 2) ErrHandler().CallErr(parsing_line, NO_MATCHING_UNARY_OPERATION_FORM, {"-"}); + if (std::regex_match(tokens[1], std::regex("[0-9]+"))) { + head = Expr({1, 0, 0}, Object("_", {}, {}, Variable("_", "-" + tokens[1], INT), 0, parsing_line), parsing_line); + } else if (std::regex_match(tokens[1], std::regex("[0-9]+.[0-9]+"))) { + head = Expr({1, 0, 0}, Object("_", {}, {}, Variable("_", "-" + tokens[1], DOUBLE), 0, parsing_line), parsing_line); + } else if (tokens[1][0] == '\"' && tokens[1][tokens[1].length() - 1] == '\"') { + ErrHandler().CallErr(parsing_line, NO_OPERATION_MATCHING_TYPE_UNARY, {"string"}); + } else { + ErrHandler().CallErr(parsing_line, NO_OPERATION_MATCHING_TYPE_UNARY, {"lvalue"}); } + return head; + } + head = Expr({0, 0, 0}, Object("_", {}, {}, Variable("_", "-", OPERATOR), 0, parsing_line), parsing_line); + head.SetChildren({ParseExpr(std::vector(tokens.begin(), tokens.begin() + idx), parsing_line), ParseExpr(std::vector(tokens.begin() + idx + 1, tokens.end()), parsing_line)}); + return head; + } + } + + // priority 5 + for (int idx = 0; idx < tokens.size(); idx++) { + String token = tokens[idx]; + if (!isTarget[idx]) continue; + if (token == "*") { + if (idx == 0 || idx == tokens.size() - 1) ErrHandler().CallErr(parsing_line, NO_MATCHING_UNARY_OPERATION_FORM, {"*"}); + head = Expr({0, 0, 0}, Object("_", {}, {}, Variable("_", "*", OPERATOR), 0, parsing_line), parsing_line); + head.SetChildren({ParseExpr(std::vector(tokens.begin(), tokens.begin() + idx), parsing_line), ParseExpr(std::vector(tokens.begin() + idx + 1, tokens.end()), parsing_line)}); + return head; } + if (token == "/") { + if (idx == 0 || idx == tokens.size() - 1) ErrHandler().CallErr(parsing_line, NO_MATCHING_UNARY_OPERATION_FORM, {"/"}); + head = Expr({0, 0, 0}, Object("_", {}, {}, Variable("_", "/", OPERATOR), 0, parsing_line), parsing_line); + head.SetChildren({ParseExpr(std::vector(tokens.begin(), tokens.begin() + idx), parsing_line), ParseExpr(std::vector(tokens.begin() + idx + 1, tokens.end()), parsing_line)}); + return head; + } + if (token == "%") { + if (idx == 0 || idx == tokens.size() - 1) ErrHandler().CallErr(parsing_line, NO_MATCHING_UNARY_OPERATION_FORM, {"%"}); + head = Expr({0, 0, 0}, Object("_", {}, {}, Variable("_", "%", OPERATOR), 0, parsing_line), parsing_line); + head.SetChildren({ParseExpr(std::vector(tokens.begin(), tokens.begin() + idx), parsing_line), ParseExpr(std::vector(tokens.begin() + idx + 1, tokens.end()), parsing_line)}); + return head; + } + } + + // priority 6 + for (int idx = 0; idx < tokens.size(); idx++) { + String token = tokens[idx]; + if (!isTarget[idx]) continue; + if (token == "!") { + if (idx == tokens.size() - 1) ErrHandler().CallErr(parsing_line, NO_IDENTIFIER_AFTER_OPERATOR, {"!"}); + head = Expr({0, 0, 0}, Object("_", {}, {}, Variable("_", "!", OPERATOR), 0, parsing_line), parsing_line); + head.SetChildren({ParseExpr({tokens[idx + 1]}, parsing_line)}); + return head; + } + } - // priority 3 - for (int idx = 0; idx < tokens.size(); idx++) { - if (!isTarget[idx]) continue; - String token = tokens[idx]; - if (token == "==") { - if (idx == 0 || idx == tokens.size()-1) ErrHandler().CallErr(parsing_line, OPERATION_ONLY_BINARY, {"=="}); - head = Expr({0, 0, 0}, Object("_", {}, {}, Variable("_", "==", OPERATOR), 0, parsing_line), parsing_line); - head.SetChildren({ - ParseExpr(std::vector(tokens.begin(), tokens.begin()+idx), parsing_line), - ParseExpr(std::vector(tokens.begin()+idx+1, tokens.end()), parsing_line) - }); - return head; - } - if (token == "!=") { - if (idx == 0 || idx == tokens.size()-1) ErrHandler().CallErr(parsing_line, OPERATION_ONLY_BINARY, {"!="}); - head = Expr({0, 0, 0}, Object("_", {}, {}, Variable("_", "!=", OPERATOR), 0, parsing_line), parsing_line); - head.SetChildren({ - ParseExpr(std::vector(tokens.begin(), tokens.begin()+idx), parsing_line), - ParseExpr(std::vector(tokens.begin()+idx+1, tokens.end()), parsing_line) - }); - return head; - } - if (token == "<") { - if (idx == 0 || idx == tokens.size()-1) ErrHandler().CallErr(parsing_line, OPERATION_ONLY_BINARY, {"<"}); - head = Expr({0, 0, 0}, Object("_", {}, {}, Variable("_", "<", OPERATOR), 0, parsing_line), parsing_line); - head.SetChildren({ - ParseExpr(std::vector(tokens.begin(), tokens.begin()+idx), parsing_line), - ParseExpr(std::vector(tokens.begin()+idx+1, tokens.end()), parsing_line) - }); - return head; - } - if (token == "<=") { - if (idx == 0 || idx == tokens.size()-1) ErrHandler().CallErr(parsing_line, OPERATION_ONLY_BINARY, {"<="}); - head = Expr({0, 0, 0}, Object("_", {}, {}, Variable("_", "<=", OPERATOR), 0, parsing_line), parsing_line); - head.SetChildren({ - ParseExpr(std::vector(tokens.begin(), tokens.begin()+idx), parsing_line), - ParseExpr(std::vector(tokens.begin()+idx+1, tokens.end()), parsing_line) - }); - return head; - } - if (token == ">") { - if (idx == 0 || idx == tokens.size()-1) ErrHandler().CallErr(parsing_line, OPERATION_ONLY_BINARY, {">"}); - head = Expr({0, 0, 0}, Object("_", {}, {}, Variable("_", ">", OPERATOR), 0, parsing_line), parsing_line); - head.SetChildren({ - ParseExpr(std::vector(tokens.begin(), tokens.begin()+idx), parsing_line), - ParseExpr(std::vector(tokens.begin()+idx+1, tokens.end()), parsing_line) - }); - return head; - } - if (token == ">=") { - if (idx == 0 || idx == tokens.size()-1) ErrHandler().CallErr(parsing_line, OPERATION_ONLY_BINARY, {">="}); - head = Expr({0, 0, 0}, Object("_", {}, {}, Variable("_", ">=", OPERATOR), 0, parsing_line), parsing_line); - head.SetChildren({ - ParseExpr(std::vector(tokens.begin(), tokens.begin()+idx), parsing_line), - ParseExpr(std::vector(tokens.begin()+idx+1, tokens.end()), parsing_line) - }); - return head; + ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_EXPRESSION, {}); +} + +// std::vector GetTokenTable(String code) +// get token table from the string code (a single code line) +std::vector GetTokenTable(String code) { + bool is_searching_string = false; + bool is_searching_blank = false; + std::vector token_table; + for (int idx = 0; idx < code.length(); idx++) { + if (code[idx] == ' ' && !is_searching_string) { + if (is_searching_blank) { + code.erase(code.begin() + idx); + idx--; + continue; + } + is_searching_blank = true; + + String token; + token.resize(idx); + + if (idx != 0) { + std::copy(code.begin(), code.begin() + idx, token.begin()); + token_table.push_back(token); + } + + code.erase(0, idx + 1); + idx = -1; + continue; + } else + is_searching_blank = false; + if (code[idx] == '"') { + is_searching_string = !(is_searching_string); + if (!is_searching_string) { + String token; + token.resize(idx + 1); + std::copy(code.begin(), code.begin() + idx + 1, token.begin()); + + // rune exception + for (std::pair rune : runes) { + while (token.find("\\" + rune.second) != String::npos) { + token.replace(token.find("\\" + rune.second), 2, rune.first); + } } - } + token_table.push_back(token); - // :TODO remove all CallErrDE() + code.erase(0, idx + 1); + idx = -1; + } + continue; + } + if (std::find(oprs.begin(), oprs.end(), code[idx]) != oprs.end() && !is_searching_string) { + bool alreadyChecked = false; + switch (code[idx]) { + case '=': + case '!': + case '<': + case '>': { + if (code.length() > idx + 1 && code[idx + 1] == '=') { + String token; + token.resize(idx); - // priority 4 - for (int idx = 0; idx < tokens.size(); idx++) { - String token = tokens[idx]; - if (!isTarget[idx]) continue; - if (token == "+") { - if (idx != 0 && std::find(operators.begin(), operators.end(), tokens[idx - 1]) != operators.end()) - continue; - if (idx == tokens.size()-1) ErrHandler().CallErr(parsing_line, OPERATION_ONLY_BINARY, {"+"}); - if (idx == 0) { - if (tokens.size() != 2) ErrHandler().CallErrDE(parsing_line, "invalid unary operation form"); - if (std::regex_match(tokens[1], std::regex("[0-9]+"))) { - head = Expr({1, 0, 0}, Object("_", {}, {}, Variable("_", tokens[1], INT), 0, parsing_line), parsing_line); - } else if (std::regex_match(tokens[1], std::regex("[0-9]+.[0-9]+"))) { - head = Expr({1, 0, 0}, Object("_", {}, {}, Variable("_", tokens[1], DOUBLE), 0, parsing_line), parsing_line); - } else if (tokens[1][0] == '\"' && tokens[1][tokens[1].length()-1] == '\"') { - ErrHandler().CallErrDE(parsing_line, "operator + in unary use cannot be used with string constant"); - } else { - ErrHandler().CallErrDE(parsing_line, "operator + in unary use cannot be used with lvalue"); - } - return head; + if (idx != 0) { + std::copy(code.begin(), code.begin() + idx, token.begin()); + token_table.push_back(token); } - head = Expr({0, 0, 0}, Object("_", {}, {}, Variable("_", "+", OPERATOR), 0, parsing_line), parsing_line); - head.SetChildren({ - ParseExpr(std::vector(tokens.begin(), tokens.begin()+idx), parsing_line), - ParseExpr(std::vector(tokens.begin()+idx+1, tokens.end()), parsing_line) - }); - return head; + + token.resize(2); + std::copy(code.begin() + idx, code.begin() + idx + 2, token.begin()); + token_table.push_back(token); + + code.erase(0, idx + 2); + idx = -1; + alreadyChecked = true; + } + break; } - if (token == "-") { - if (idx == tokens.size()-1) ErrHandler().CallErrDE(parsing_line, "operator - cannot be unary"); - if (std::find(operators.begin(), operators.end(), tokens[idx - 1]) != operators.end()) - continue; - if (idx == 0) { - if (tokens.size() != 2) ErrHandler().CallErrDE(parsing_line, "invalid unary operation form"); - if (std::regex_match(tokens[1], std::regex("[0-9]+"))) { - head = Expr({1, 0, 0}, Object("_", {}, {}, Variable("_", "-" + tokens[1], INT), 0, parsing_line), parsing_line); - } else if (std::regex_match(tokens[1], std::regex("[0-9]+.[0-9]+"))) { - head = Expr({1, 0, 0}, Object("_", {}, {}, Variable("_", "-" + tokens[1], DOUBLE), 0, parsing_line), parsing_line); - } else if (tokens[1][0] == '\"' && tokens[1][tokens[1].length()-1] == '\"') { - ErrHandler().CallErrDE(parsing_line, "operator - in unary use cannot be used with string constant"); - } else { - ErrHandler().CallErrDE(parsing_line, "operator - in unary use cannot be used with lvalue"); - } - return head; + case '&': { + if (code.length() > idx + 1 && code[idx + 1] == '&') { + String token; + token.resize(idx); + + if (idx != 0) { + std::copy(code.begin(), code.begin() + idx, token.begin()); + token_table.push_back(token); } - head = Expr({0, 0, 0}, Object("_", {}, {}, Variable("_", "-", OPERATOR), 0, parsing_line), parsing_line); - head.SetChildren({ - ParseExpr(std::vector(tokens.begin(), tokens.begin()+idx), parsing_line), - ParseExpr(std::vector(tokens.begin()+idx+1, tokens.end()), parsing_line) - }); - return head; - } - } - // priority 5 - for (int idx = 0; idx < tokens.size(); idx++) { - String token = tokens[idx]; - if (!isTarget[idx]) continue; - if (token == "*") { - if (idx == 0 || idx == tokens.size()-1) ErrHandler().CallErrDE(parsing_line, "operator * cannot be unary"); - head = Expr({0, 0, 0}, Object("_", {}, {}, Variable("_", "*", OPERATOR), 0, parsing_line), parsing_line); - head.SetChildren({ - ParseExpr(std::vector(tokens.begin(), tokens.begin()+idx), parsing_line), - ParseExpr(std::vector(tokens.begin()+idx+1, tokens.end()), parsing_line) - }); - return head; - } - if (token == "/") { - if (idx == 0 || idx == tokens.size()-1) ErrHandler().CallErrDE(parsing_line, "operator / cannot be unary"); - head = Expr({0, 0, 0}, Object("_", {}, {}, Variable("_", "/", OPERATOR), 0, parsing_line), parsing_line); - head.SetChildren({ - ParseExpr(std::vector(tokens.begin(), tokens.begin()+idx), parsing_line), - ParseExpr(std::vector(tokens.begin()+idx+1, tokens.end()), parsing_line) - }); - return head; + token.resize(2); + std::copy(code.begin() + idx, code.begin() + idx + 2, token.begin()); + token_table.push_back(token); + + code.erase(0, idx + 2); + idx = -1; + alreadyChecked = true; + } + break; } - if (token == "%") { - if (idx == 0 || idx == tokens.size()-1) ErrHandler().CallErrDE(parsing_line, "operator % cannot be unary"); - head = Expr({0, 0, 0}, Object("_", {}, {}, Variable("_", "%", OPERATOR), 0, parsing_line), parsing_line); - head.SetChildren({ - ParseExpr(std::vector(tokens.begin(), tokens.begin()+idx), parsing_line), - ParseExpr(std::vector(tokens.begin()+idx+1, tokens.end()), parsing_line) - }); - return head; + case '|': { + if (code.length() > idx + 1 && code[idx + 1] == '|') { + String token; + token.resize(idx); + + if (idx != 0) { + std::copy(code.begin(), code.begin() + idx, token.begin()); + token_table.push_back(token); + } + + token.resize(2); + std::copy(code.begin() + idx, code.begin() + idx + 2, token.begin()); + token_table.push_back(token); + + code.erase(0, idx + 2); + idx = -1; + alreadyChecked = true; + } + break; } - } + case '/': { + if (code.length() > idx + 1 && code[idx + 1] == '/') { + String token; + token.resize(idx); - // priority 6 - for (int idx = 0; idx < tokens.size(); idx++) { - String token = tokens[idx]; - if (!isTarget[idx]) continue; - if (token == "!") { - if (idx == tokens.size()-1) ErrHandler().CallErrDE(parsing_line, "operator ! cannot appear after identifier"); - head = Expr({0, 0, 0}, Object("_", {}, {}, Variable("_", "!", OPERATOR), 0, parsing_line), parsing_line); - head.SetChildren({ - ParseExpr({tokens[idx+1]}, parsing_line) - }); - return head; + if (idx != 0) { + std::copy(code.begin(), code.begin() + idx, token.begin()); + token_table.push_back(token); + } + + token.resize(2); + std::copy(code.begin() + idx, code.begin() + idx + 2, token.begin()); + token_table.push_back(token); + + code.erase(0, idx + 2); + idx = -1; + alreadyChecked = true; + } + break; } - } + } + if (alreadyChecked) continue; + + String token; + token.resize(idx); + + if (idx != 0) { + std::copy(code.begin(), code.begin() + idx, token.begin()); + token_table.push_back(token); + } - ErrHandler().CallErrDE(parsing_line, "invalid expression."); + token = code[idx]; + token_table.push_back(token); + + code.erase(0, idx + 1); + idx = -1; + continue; + } + } + if (code.length()) token_table.push_back(code); + return token_table; } -// std::vector GetTokenTable(String code) -// get token table from the string code (a single code line) -std::vector GetTokenTable(String code) { - bool is_searching_string = false; - bool is_searching_blank = false; - std::vector token_table; - for (int idx = 0; idx < code.length(); idx++) { - if (code[idx] == ' ' && !is_searching_string) { - if (is_searching_blank) { - code.erase(code.begin()+idx); idx--; - continue; - } - is_searching_blank = true; +// int Parse(AST& head, std::vector> Token_table, int parse_start, int arg_idx, std::vector& token_storage) +// ** return value is a pair of the end of line of parsing block and parsing index ** +std::pair Parse(AST& head, std::vector> Token_table, int parse_start, int arg_idx, std::vector& token_storage) { + int parsing_line = head.codeline; // base parsing line = 1 + StmtType prev_stmt = Main; + for (; parsing_line <= Token_table.size(); parsing_line++) { + std::vector token_table = Token_table[parsing_line - 1]; + + for (int idx = parse_start; idx < token_table.size(); idx++) { + if (token_table[idx] == "//") break; + if (token_table[idx] == "(") { + // BracketBlock is only for adding bracket-inside tokens into token_table. + // Thus, bracket_block isn't added in AST + AST bracket_block(BracketBlock, {}, {}, parsing_line); + token_storage.push_back("("); + + std::pair res = Parse(bracket_block, Token_table, idx + 1, 0, token_storage); + + parsing_line = res.first; + idx = res.second; + token_table = Token_table[parsing_line - 1]; + continue; + } + if (token_table[idx] == ")") { + token_storage.push_back(")"); + return {parsing_line, idx}; + } + switch (head.GetStmt()) { + case Main: { + // if-family statement + if (token_table[idx] == "if") { + AST if_block(IfStmt, {}, {}, parsing_line); + std::pair res = Parse(if_block, Token_table, idx + 1, 1, token_storage); + head.AddChild(if_block); - String token; token.resize(idx); + parsing_line = res.first; + idx = res.second; + prev_stmt = IfStmt; + token_table = Token_table[parsing_line - 1]; + token_storage = {}; // if not need -> remove + continue; + } - if (idx != 0) { - std::copy(code.begin(), code.begin()+idx, token.begin()); - token_table.push_back(token); + if (token_table[idx] == "?") { + if (prev_stmt == IfStmt || prev_stmt == ElifStmt) { + if (token_storage.empty()) { // else + AST else_block(ElseStmt, {}, {}, parsing_line); + std::pair res = Parse(else_block, Token_table, idx + 1, 0, token_storage); + head.AddChild(else_block); + + parsing_line = res.first; + idx = res.second; + prev_stmt = ElseStmt; + token_table = Token_table[parsing_line - 1]; + token_storage = {}; // if not need -> remove + continue; + } else { // elif + AST elif_block(ElifStmt, {}, {ParseExpr(token_storage, parsing_line)}, parsing_line); + token_storage = {}; + std::pair res = Parse(elif_block, Token_table, idx + 1, 0, token_storage); + head.AddChild(elif_block); + + parsing_line = res.first; + idx = res.second; + prev_stmt = ElifStmt; + token_storage = {}; // if not need -> remove + token_table = Token_table[parsing_line - 1]; + continue; + } } + ErrHandler().CallErr(parsing_line, NO_MATCHING_STRUCTURE_IF, {}); + } - code.erase(0, idx+1); - idx = -1; + // for statement + if (token_table[idx] == "for") { + AST for_block(ForStmt, {}, {}, parsing_line); + std::pair res = Parse(for_block, Token_table, idx + 1, 1, token_storage); + head.AddChild(for_block); + + parsing_line = res.first; + idx = res.second; + prev_stmt = ForStmt; + token_table = Token_table[parsing_line - 1]; + token_storage = {}; // if not need -> remove continue; - } else is_searching_blank = false; - if (code[idx] == '"') { - is_searching_string = !(is_searching_string); - if (!is_searching_string) { - String token; token.resize(idx+1); - std::copy(code.begin(), code.begin()+idx+1, token.begin()); - - // rune exception - for (std::pair rune: runes) { - while (token.find("\\" + rune.second) != String::npos) { - token.replace(token.find("\\" + rune.second), 2, rune.first); - } - } - token_table.push_back(token); + } + + if (token_table[idx] == "$") ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_EXPRESSION, {}); - code.erase(0, idx+1); - idx = -1; + if (token_table[idx] == "=") { + if (token_storage.size() == 1) { // assignment + AST assignment(Assignment, {Object("_", {}, {}, {"_", token_storage[0]})}, {}, parsing_line); + token_storage = {}; + + std::pair res = Parse(assignment, Token_table, idx + 1, 1, token_storage); + head.AddChild(assignment); + + parsing_line = res.first; + idx = res.second; + prev_stmt = Assignment; + token_table = Token_table[parsing_line - 1]; + token_storage = {}; + continue; + } + if (token_storage.size() == 2) { // declaration + AST var_del(VarDel, {Object("_", {}, {}, {"_", token_storage[0]}), Object("_", {}, {}, {"_", token_storage[1]})}, {}, parsing_line); + token_storage = {}; + + std::pair res = Parse(var_del, Token_table, idx + 1, 1, token_storage); + head.AddChild(var_del); + + parsing_line = res.first; + idx = res.second; + prev_stmt = Assignment; + token_table = Token_table[parsing_line - 1]; + token_storage = {}; + continue; } + ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_EXPRESSION, {}); + } + + // const variable declaration + if (token_table[idx] == "const") { + AST const_del(ConstDel, {}, {}, parsing_line); + std::pair res = Parse(const_del, Token_table, idx + 1, 1, token_storage); + head.AddChild(const_del); + + parsing_line = res.first; + idx = res.second; + prev_stmt = ConstDel; + token_table = Token_table[parsing_line - 1]; + token_storage = {}; continue; + } + + // break statement + if (token_table[idx] == "break") { + AST break_stmt(BreakStmt, {}, {}, parsing_line); + head.AddChild(break_stmt); + prev_stmt = BreakStmt; + } + + // continue statement + if (token_table[idx] == "continue") { + AST continue_stmt(ContinueStmt, {}, {}, parsing_line); + head.AddChild(continue_stmt); + prev_stmt = ContinueStmt; + } + break; } - if (std::find(oprs.begin(), oprs.end(), code[idx]) != oprs.end() && !is_searching_string) { - bool alreadyChecked = false; - switch (code[idx]) { - case '=': - case '!': - case '<': - case '>': { - if (code.length() > idx+1 && code[idx+1] == '=') { - String token; token.resize(idx); - - if (idx != 0) { - std::copy(code.begin(), code.begin()+idx, token.begin()); - token_table.push_back(token); - } - - token.resize(2); std::copy(code.begin()+idx, code.begin()+idx+2, token.begin()); - token_table.push_back(token); - - code.erase(0, idx+2); - idx = -1; - alreadyChecked = true; - } - break; - } - case '&': { - if (code.length() > idx+1 && code[idx+1] == '&') { - String token; token.resize(idx); - - if (idx != 0) { - std::copy(code.begin(), code.begin()+idx, token.begin()); - token_table.push_back(token); - } - - token.resize(2); std::copy(code.begin()+idx, code.begin()+idx+2, token.begin()); - token_table.push_back(token); - - code.erase(0, idx+2); - idx = -1; - alreadyChecked = true; - } - break; - } - case '|': { - if (code.length() > idx+1 && code[idx+1] == '|') { - String token; token.resize(idx); - - if (idx != 0) { - std::copy(code.begin(), code.begin()+idx, token.begin()); - token_table.push_back(token); - } - - token.resize(2); std::copy(code.begin()+idx, code.begin()+idx+2, token.begin()); - token_table.push_back(token); - - code.erase(0, idx+2); - idx = -1; - alreadyChecked = true; - } - break; - } - case '/': { - if (code.length() > idx+1 && code[idx+1] == '/') { - String token; token.resize(idx); - - if (idx != 0) { - std::copy(code.begin(), code.begin()+idx, token.begin()); - token_table.push_back(token); - } - - token.resize(2); std::copy(code.begin()+idx, code.begin()+idx+2, token.begin()); - token_table.push_back(token); - - code.erase(0, idx+2); - idx = -1; - alreadyChecked = true; - } - break; + + // if-family statement + case IfStmt: { + // if-family statement + if (token_table[idx] == "if") { + if (arg_idx == 1) ErrHandler().CallErr(parsing_line, NO_MATCHING_STRUCTURE_IF, {}); + AST if_block(IfStmt, {}, {}, parsing_line); + std::pair res = Parse(if_block, Token_table, idx + 1, 1, token_storage); + head.AddChild(if_block); + + parsing_line = res.first; + idx = res.second; + prev_stmt = IfStmt; + token_table = Token_table[parsing_line - 1]; + token_storage = {}; // if not need -> remove + continue; + } + + if (token_table[idx] == "?") { + if (arg_idx == 1) { + head.AddExpr(ParseExpr(token_storage, parsing_line)); + token_storage = {}; + head.codeline = parsing_line; + return Parse(head, Token_table, idx + 1, 2, token_storage); + } else { + if (prev_stmt == IfStmt || prev_stmt == ElifStmt) { + if (token_storage.empty()) { // else + AST else_block(ElseStmt, {}, {}, parsing_line); + std::pair res = Parse(else_block, Token_table, idx + 1, 0, token_storage); + head.AddChild(else_block); + + parsing_line = res.first; + idx = res.second; + prev_stmt = ElseStmt; + token_table = Token_table[parsing_line - 1]; + token_storage = {}; // if not need -> remove + continue; + } else { // elif + AST elif_block(ElifStmt, {}, {ParseExpr(token_storage, parsing_line)}, parsing_line); + token_storage = {}; + std::pair res = Parse(elif_block, Token_table, idx + 1, 0, token_storage); + head.AddChild(elif_block); + + parsing_line = res.first; + idx = res.second; + prev_stmt = ElifStmt; + token_table = Token_table[parsing_line - 1]; + token_storage = {}; // if not need -> remove + continue; } + } + ErrHandler().CallErr(parsing_line, NO_MATCHING_STRUCTURE_IF, {}); } - if (alreadyChecked) continue; - - String token; token.resize(idx); + } - if (idx != 0) { - std::copy(code.begin(), code.begin()+idx, token.begin()); - token_table.push_back(token); + // for statement + if (token_table[idx] == "for") { + if (arg_idx == 1) ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_IF, {}); + AST for_block(ForStmt, {}, {}, parsing_line); + std::pair res = Parse(for_block, Token_table, idx + 1, 1, token_storage); + head.AddChild(for_block); + + parsing_line = res.first; + idx = res.second; + prev_stmt = ForStmt; + token_table = Token_table[parsing_line - 1]; + token_storage = {}; // if not need -> remove + continue; + } + + if (token_table[idx] == "$") ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_EXPRESSION, {}); + + if (token_table[idx] == "=") { + if (arg_idx == 1) ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_IF, {}); + if (token_storage.size() == 1) { // assignment + AST assignment(Assignment, {Object("_", {}, {}, {"_", token_storage[0]})}, {}, parsing_line); + token_storage = {}; + + std::pair res = Parse(assignment, Token_table, idx + 1, 1, token_storage); + head.AddChild(assignment); + + parsing_line = res.first; + idx = res.second; + prev_stmt = Assignment; + token_table = Token_table[parsing_line - 1]; + token_storage = {}; + continue; } - - token = code[idx]; - token_table.push_back(token); - - code.erase(0, idx+1); - idx = -1; + if (token_storage.size() == 2) { // declaration + AST var_del(VarDel, {Object("_", {}, {}, {"_", token_storage[0]}), Object("_", {}, {}, {"_", token_storage[1]})}, {}, parsing_line); + token_storage = {}; + + std::pair res = Parse(var_del, Token_table, idx + 1, 1, token_storage); + head.AddChild(var_del); + + parsing_line = res.first; + idx = res.second; + prev_stmt = Assignment; + token_table = Token_table[parsing_line - 1]; + token_storage = {}; + continue; + } + ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_EXPRESSION, {}); + } + + // const variable declaration + if (token_table[idx] == "const") { + if (arg_idx == 1) ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_IF, {}); + AST const_del(ConstDel, {}, {}, parsing_line); + std::pair res = Parse(const_del, Token_table, idx + 1, 1, token_storage); + head.AddChild(const_del); + + parsing_line = res.first; + idx = res.second; + prev_stmt = ConstDel; + token_table = Token_table[parsing_line - 1]; + token_storage = {}; continue; - } - } - if (code.length()) token_table.push_back(code); - return token_table; -} + } -// int Parse(AST& head, std::vector codes) -// ** return value is the end of line of parsing block ** -int Parse(AST& head, std::vector codes) { - int parsing_line = head.codeline; // base parsing line = 0 - for (int idx = 0; idx < codes.size(); idx++) { - String code = codes[idx]; - parsing_line++; - std::vector token_table = GetTokenTable(code); - - // blank statement - if (!token_table.size()) continue; - - // comment - if (token_table[0] == "//") continue; - - // end line of the parsing block - if (token_table.size() == 1 && token_table[0] == ";") return parsing_line; - - // if statement - if (token_table[0] == "if") { - if (token_table[token_table.size()-1] != "?") - ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_IF, {}); - - AST if_block(IfStmt, {}, { - ParseExpr(std::vector(token_table.begin()+1, token_table.end()-1), parsing_line) - }, parsing_line); - - int end_block = Parse( - if_block, - std::vector(codes.begin()+parsing_line-head.codeline, codes.end()) - ); + // break statement + if (token_table[idx] == "break") { + if (arg_idx == 1) ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_IF, {}); + AST break_stmt(BreakStmt, {}, {}, parsing_line); + head.AddChild(break_stmt); + } - head.AddChild(if_block); + // continue statement + if (token_table[idx] == "continue") { + if (arg_idx == 1) ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_IF, {}); + AST continue_stmt(ContinueStmt, {}, {}, parsing_line); + head.AddChild(continue_stmt); + } - idx += end_block - parsing_line; - - // check elif statement - parsing_line = end_block; - - std::vector end_block_token_table = GetTokenTable(codes[idx]); - if (end_block_token_table.size() == 1) continue; - idx--; parsing_line--; // need to check + if (token_table[idx] == ";") { + if (arg_idx == 1) ErrHandler().CallErr(parsing_line, NO_MATCHING_STRUCTURE_IF, {}); + if (token_storage.size() != 0) { + AST expression(Expression, {}, {ParseExpr(token_storage, parsing_line)}, parsing_line); + head.AddChild(expression); + } + return {parsing_line, idx}; + } + break; } - - // elif & else statement - else if (token_table[0] == ";") { - if (token_table.size() != 1 && token_table[token_table.size()-1] != "?") - ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_ELIF, {}); - if (head.GetStmt() == IfStmt || head.GetStmt() == ElifStmt) return parsing_line; // should be parsed in a lower level - if (token_table.size() == 2) { // else statement - AST else_block(ElseStmt, {}, {}, parsing_line); - int end_block = Parse( - else_block, - std::vector(codes.begin()+parsing_line-head.codeline, codes.end()) - ); + case ElifStmt: + case ElseStmt: { + // if-family statement + if (token_table[idx] == "if") { + AST if_block(IfStmt, {}, {}, parsing_line); + std::pair res = Parse(if_block, Token_table, idx + 1, 1, token_storage); + head.AddChild(if_block); + parsing_line = res.first; + idx = res.second; + prev_stmt = IfStmt; + token_table = Token_table[parsing_line - 1]; + token_storage = {}; // if not need -> remove + continue; + } + + if (token_table[idx] == "?") { + if (prev_stmt == IfStmt || prev_stmt == ElifStmt) { + if (token_storage.empty()) { // else + AST else_block(ElseStmt, {}, {}, parsing_line); + std::pair res = Parse(else_block, Token_table, idx + 1, 0, token_storage); head.AddChild(else_block); - // check whether a elif/else statement follows - idx += end_block - parsing_line; - - parsing_line = end_block; - - std::vector end_block_token_table = GetTokenTable(codes[idx]); - if (end_block_token_table.size() == 1) continue; // zero possiblity - idx--; parsing_line--; + parsing_line = res.first; + idx = res.second; + prev_stmt = ElseStmt; + token_table = Token_table[parsing_line - 1]; + token_storage = {}; // if not need -> remove continue; + } else { // elif + AST elif_block(ElifStmt, {}, {ParseExpr(token_storage, parsing_line)}, parsing_line); + token_storage = {}; + std::pair res = Parse(elif_block, Token_table, idx + 1, 0, token_storage); + head.AddChild(elif_block); + + parsing_line = res.first; + idx = res.second; + prev_stmt = ElifStmt; + token_table = Token_table[parsing_line - 1]; + token_storage = {}; // if not need -> remove + continue; + } } - AST elif_block(ElifStmt, {}, { - ParseExpr( - std::vector(token_table.begin()+1, token_table.end()-1), - parsing_line - ) - }, parsing_line); - - int end_block = Parse( - elif_block, - std::vector(codes.begin()+parsing_line-head.codeline, codes.end()) - ); - - head.AddChild(elif_block); - - idx += end_block - parsing_line; - - // check whether a elif/else statement follows - parsing_line = end_block; - - std::vector end_block_token_table = GetTokenTable(codes[idx]); - if (end_block_token_table.size() == 1) continue; // zero possiblity - idx--; parsing_line--; - } + ErrHandler().CallErr(parsing_line, NO_MATCHING_STRUCTURE_IF, {}); + } - // for statement - else if (token_table[0] == "for") { - if (token_table[token_table.size()-1] != "$") - ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_FOR, {}); - - // for statement with for clause - if (std::find(token_table.begin(), token_table.end(), "in") != token_table.end()) { - if (token_table.size() < 9 || token_table[2] != "in") - ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_FOR, {}); - - // check range - std::vector rangeidx_list; - for (int rangeidx = 3; rangeidx < token_table.size()-1; rangeidx++) - if (token_table[rangeidx] == "~") { - rangeidx_list.push_back(rangeidx); - } - - // grammar checking (ex. 1~2 (x), 1~~2 (x), 3~5~1 (o)) - if (rangeidx_list.size() != 2 || - rangeidx_list[0] - 2 == 1 || - rangeidx_list[1] - rangeidx_list[0] == 1 || - token_table.size()-1 - rangeidx_list[1] == 1) - ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_FOR, {}); - - AST for_block(ForClauseStmt, { - Object("_", {}, {}, Variable("_", token_table[1], OPERATOR), 0, parsing_line, OK) - }, { - ParseExpr(std::vector(token_table.begin()+3, token_table.begin()+rangeidx_list[0]), parsing_line), - ParseExpr(std::vector(token_table.begin()+rangeidx_list[0]+1, token_table.begin()+rangeidx_list[1]), parsing_line), - ParseExpr(std::vector(token_table.begin()+rangeidx_list[1]+1, token_table.end()-1), parsing_line), - }, parsing_line); - - int end_block = Parse( - for_block, - std::vector(codes.begin()+parsing_line-head.codeline, codes.end()) - ); - - head.AddChild(for_block); - - idx += end_block - parsing_line; - parsing_line = end_block; - continue; - } + // for statement + if (token_table[idx] == "for") { + AST for_block(ForStmt, {}, {}, parsing_line); + std::pair res = Parse(for_block, Token_table, idx + 1, 1, token_storage); + head.AddChild(for_block); - // for statement with single condition - AST for_block(ForSCStmt, {}, { - ParseExpr(std::vector(token_table.begin()+1, token_table.end()-1), parsing_line), - }, parsing_line); + parsing_line = res.first; + idx = res.second; + prev_stmt = ForStmt; + token_table = Token_table[parsing_line - 1]; + token_storage = {}; // if not need -> remove + continue; + } - int end_block = Parse( - for_block, - std::vector(codes.begin()+parsing_line-head.codeline, codes.end()) - ); + if (token_table[idx] == "$") ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_EXPRESSION, {}); - head.AddChild(for_block); + if (token_table[idx] == "=") { + if (token_storage.size() == 1) { // assignment + AST assignment(Assignment, {Object("_", {}, {}, {"_", token_storage[0]})}, {}, parsing_line); + token_storage = {}; - idx += end_block - parsing_line; - parsing_line = end_block; - } + std::pair res = Parse(assignment, Token_table, idx + 1, 1, token_storage); + head.AddChild(assignment); - // break statement - else if (token_table[0] == "break") { - if (token_table.size() > 1) - ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_FOR, {}); + parsing_line = res.first; + idx = res.second; + prev_stmt = Assignment; + token_table = Token_table[parsing_line - 1]; + token_storage = {}; + continue; + } + if (token_storage.size() == 2) { // declaration + AST var_del(VarDel, {Object("_", {}, {}, {"_", token_storage[0]}), Object("_", {}, {}, {"_", token_storage[1]})}, {}, parsing_line); + token_storage = {}; + + std::pair res = Parse(var_del, Token_table, idx + 1, 1, token_storage); + head.AddChild(var_del); + + parsing_line = res.first; + idx = res.second; + prev_stmt = Assignment; + token_table = Token_table[parsing_line - 1]; + token_storage = {}; + continue; + } + ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_EXPRESSION, {}); + } + + // const variable declaration + if (token_table[idx] == "const") { + AST const_del(ConstDel, {}, {}, parsing_line); + std::pair res = Parse(const_del, Token_table, idx + 1, 1, token_storage); + head.AddChild(const_del); + + parsing_line = res.first; + idx = res.second; + prev_stmt = ConstDel; + token_table = Token_table[parsing_line - 1]; + token_storage = {}; + continue; + } + // break statement + if (token_table[idx] == "break") { AST break_stmt(BreakStmt, {}, {}, parsing_line); head.AddChild(break_stmt); - } + } - // continue statement - else if (token_table[0] == "continue") { - if (token_table.size() > 1) - ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_CONTINUE, {}); + // continue statement + if (token_table[idx] == "continue") { AST continue_stmt(ContinueStmt, {}, {}, parsing_line); head.AddChild(continue_stmt); + } + + if (token_table[idx] == ";") { + if (token_storage.size() != 0) { + AST expression(Expression, {}, {ParseExpr(token_storage, parsing_line)}, parsing_line); + head.AddChild(expression); + } + return {parsing_line, idx}; + } + break; } - // Assignment - else if (token_table.size() > 2 && token_table[1] == "=") { - AST assignment(Assignment, { - Object("_", {}, {}, Variable("_", token_table[0], OPERATOR), 0, parsing_line, OK) - }, { - ParseExpr(std::vector(token_table.begin()+2, token_table.end()), parsing_line) - }, parsing_line); + // for statement + case ForStmt: { + // if-family statement + if (token_table[idx] == "if") { + if (arg_idx != 5) ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_FOR, {}); + AST if_block(IfStmt, {}, {}, parsing_line); + std::pair res = Parse(if_block, Token_table, idx + 1, 1, token_storage); + head.AddChild(if_block); - head.AddChild(assignment); - } + parsing_line = res.first; + idx = res.second; + prev_stmt = IfStmt; + token_table = Token_table[parsing_line - 1]; + token_storage = {}; // if not need -> remove + continue; + } + + if (token_table[idx] == "?") { + if (arg_idx != 5) ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_FOR, {}); + if (prev_stmt == IfStmt || prev_stmt == ElifStmt) { + if (token_storage.empty()) { // else + AST else_block(ElseStmt, {}, {}, parsing_line); + std::pair res = Parse(else_block, Token_table, idx + 1, 0, token_storage); + head.AddChild(else_block); - // VarDel - else if (token_table.size() > 3 && token_table[2] == "=") { - AST vardel(VarDel, { - Object("_", {}, {}, Variable("_", token_table[0], OPERATOR), 0, parsing_line, OK), - Object("_", {}, {}, Variable("_", token_table[1], OPERATOR), 0, parsing_line, OK) - }, { - ParseExpr(std::vector(token_table.begin()+3, token_table.end()), parsing_line) - }, parsing_line); + parsing_line = res.first; + idx = res.second; + prev_stmt = ElseStmt; + token_table = Token_table[parsing_line - 1]; + token_storage = {}; // if not need -> remove + continue; + } else { // elif + AST elif_block(ElifStmt, {}, {ParseExpr(token_storage, parsing_line)}, parsing_line); + token_storage = {}; + std::pair res = Parse(elif_block, Token_table, idx + 1, 0, token_storage); + head.AddChild(elif_block); + + parsing_line = res.first; + idx = res.second; + prev_stmt = ElifStmt; + token_table = Token_table[parsing_line - 1]; + token_storage = {}; // if not need -> remove + continue; + } + } + ErrHandler().CallErr(parsing_line, NO_MATCHING_STRUCTURE_IF, {}); + } + + // for statement + if (token_table[idx] == "for") { + if (arg_idx != 5) ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_FOR, {}); + AST for_block(ForStmt, {}, {}, parsing_line); + std::pair res = Parse(for_block, Token_table, idx + 1, 1, token_storage); + head.AddChild(for_block); - head.AddChild(vardel); - } + parsing_line = res.first; + idx = res.second; + prev_stmt = ForStmt; + token_storage = {}; // if not need -> remove + token_table = Token_table[parsing_line - 1]; + continue; + } + + if (token_table[idx] == "=") { + if (arg_idx != 5) ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_FOR, {}); + if (token_storage.size() == 1) { // assignment + AST assignment(Assignment, {Object("_", {}, {}, {"_", token_storage[0]})}, {}, parsing_line); + token_storage = {}; + + std::pair res = Parse(assignment, Token_table, idx + 1, 1, token_storage); + head.AddChild(assignment); + + parsing_line = res.first; + idx = res.second; + prev_stmt = Assignment; + token_table = Token_table[parsing_line - 1]; + token_storage = {}; + continue; + } + if (token_storage.size() == 2) { // declaration + AST var_del(VarDel, {Object("_", {}, {}, {"_", token_storage[0]}), Object("_", {}, {}, {"_", token_storage[1]})}, {}, parsing_line); + token_storage = {}; + + std::pair res = Parse(var_del, Token_table, idx + 1, 1, token_storage); + head.AddChild(var_del); + + parsing_line = res.first; + idx = res.second; + prev_stmt = Assignment; + token_table = Token_table[parsing_line - 1]; + token_storage = {}; + continue; + } + ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_EXPRESSION, {}); + } + + // const variable declaration + if (token_table[idx] == "const") { + if (arg_idx != 5) ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_FOR, {}); + AST const_del(ConstDel, {}, {}, parsing_line); + std::pair res = Parse(const_del, Token_table, idx + 1, 1, token_storage); + head.AddChild(const_del); + + parsing_line = res.first; + idx = res.second; + prev_stmt = ConstDel; + token_table = Token_table[parsing_line - 1]; + token_storage = {}; + continue; + } - // ConstDel - else if (token_table.size() > 4 && token_table[0] == "const" && token_table[3] == "=") { - AST constdel(ConstDel, { - Object("_", {}, {}, Variable("_", token_table[1], OPERATOR), 0, parsing_line, OK), - Object("_", {}, {}, Variable("_", token_table[2], OPERATOR), 0, parsing_line, OK) - }, { - ParseExpr(std::vector(token_table.begin()+4, token_table.end()), parsing_line) - }, parsing_line); + // break statement + if (token_table[idx] == "break") { + if (arg_idx != 5) ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_FOR, {}); + AST break_stmt(BreakStmt, {}, {}, parsing_line); + head.AddChild(break_stmt); + } - head.AddChild(constdel); + // continue statement + if (token_table[idx] == "continue") { + if (arg_idx != 5) ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_FOR, {}); + AST continue_stmt(ContinueStmt, {}, {}, parsing_line); + head.AddChild(continue_stmt); + } + if (token_table[idx] == "in") { + if (arg_idx != 1 || token_storage.size() != 1) ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_FOR, {}); + head.AddArg(Object("_", {}, {}, {"_", "C"}, 0, parsing_line)); + head.AddArg(Object("_", {}, {}, {"_", token_storage[0]}, 0, parsing_line)); + token_storage = {}; + return Parse(head, Token_table, idx + 1, 2, token_storage); + } + if (token_table[idx] == "~") { + if (arg_idx == 2 | arg_idx == 3) { + head.AddExpr(ParseExpr(token_storage, parsing_line)); + token_storage = {}; + return Parse(head, Token_table, idx + 1, arg_idx + 1, token_storage); + } + ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_FOR, {}); + } + if (token_table[idx] == "$") { + if (arg_idx == 1) { + head.AddArg(Object("_", {}, {}, {"_", "S"}, 0, parsing_line)); + head.AddExpr(ParseExpr(token_storage, parsing_line)); + token_storage = {}; + head.codeline = parsing_line; + return Parse(head, Token_table, idx + 1, 5, token_storage); + } + if (arg_idx == 3) { // omission of + head.AddExpr(ParseExpr(token_storage, parsing_line)); + head.AddExpr(Expr({1, 0, 0}, Object("_", {}, {}, {"_", "1", INT}), parsing_line)); + token_storage = {}; + head.codeline = parsing_line; + return Parse(head, Token_table, idx + 1, 5, token_storage); + } + if (arg_idx == 4) { + head.AddExpr(ParseExpr(token_storage, parsing_line)); + token_storage = {}; + head.codeline = parsing_line; + return Parse(head, Token_table, idx + 1, 5, token_storage); + } + ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_FOR, {}); + } + if (token_table[idx] == ";") { + if (arg_idx != 5) ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_FOR, {}); + if (token_storage.size() != 0) { + AST expression(Expression, {}, {ParseExpr(token_storage, parsing_line)}, parsing_line); + head.AddChild(expression); + } + return {parsing_line, idx}; + } + break; } - // Expression - else { - AST expression(Expression, {}, { - ParseExpr(token_table, parsing_line) - }, parsing_line); - - head.AddChild(expression); + // const variable declaration + case ConstDel: { + if (token_table[idx] == "if" || token_table[idx] == "?" || token_table[idx] == "for" || token_table[idx] == "continue" || token_table[idx] == "const" || token_table[idx] == "break" || token_table[idx] == "$" || token_table[idx] == ";") ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_EXPRESSION, {}); + if (token_table[idx] == "=") { + if (token_storage.size() == 2) { // declaration + head.AddArg(Object("_", {}, {}, {"_", token_storage[0]})); + head.AddArg(Object("_", {}, {}, {"_", token_storage[1]})); + token_storage = {}; + + return Parse(head, Token_table, idx + 1, 2, token_storage); + } + ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_EXPRESSION, {}); + } } + } + token_storage.push_back(token_table[idx]); + } + + parse_start = 0; + switch (head.GetStmt()) { + case ElifStmt: + case ElseStmt: + case Main: { + if (token_storage.size() == 0) continue; + AST expression(Expression, {}, {ParseExpr(token_storage, parsing_line)}, parsing_line); + head.AddChild(expression); + token_storage = {}; + break; + } + case IfStmt: { + if (arg_idx == 1) ErrHandler().CallErr(parsing_line, NO_MATCHING_STRUCTURE_IF, {}); + if (token_storage.size() == 0) continue; + AST expression(Expression, {}, {ParseExpr(token_storage, parsing_line)}, parsing_line); + head.AddChild(expression); + token_storage = {}; + break; + } + case ForStmt: { + if (arg_idx != 5) ErrHandler().CallErr(parsing_line, NO_MATCHING_SYNTAX_FOR, {}); + if (token_storage.size() == 0) continue; + AST expression(Expression, {}, {ParseExpr(token_storage, parsing_line)}, parsing_line); + head.AddChild(expression); + token_storage = {}; + break; + } + case VarDel: + case ConstDel: + case Assignment: { + head.AddExpr(ParseExpr(token_storage, parsing_line)); + return {parsing_line, token_table.size()}; + } } + prev_stmt = Expression; + } + switch (head.GetStmt()) { + case BracketBlock: + ErrHandler().CallErr(parsing_line, UNMATCHED_PARENTHESIS, {}); + break; + case IfStmt: + case ElifStmt: + case ElseStmt: + ErrHandler().CallErr(parsing_line, NOT_CLOSED_BLOCK, {}); + break; + } } \ No newline at end of file diff --git a/src/parser/parse.h b/src/parser/parse.h index d64c452..c983481 100644 --- a/src/parser/parse.h +++ b/src/parser/parse.h @@ -2,23 +2,24 @@ * src/parser/parse.h * Wopslang Parsing Headerfile * - * 2021, Wops Team + * 2023, Wops Team * */ #include +#include +#include +#include #include #include -#include -#include -#include -#include "../runtime/AST.h" + #include "../error/signal.h" +#include "../runtime/AST.h" #ifndef WOPS_PARSE_H #define WOPS_PARSE_H -int Parse(AST& head, std::vector codes); +std::pair Parse(AST& head, std::vector> Token_table, int parse_start, int arg_idx, std::vector& token_storage); Expr ParseExpr(std::vector tokens, int parsing_line); std::vector GetTokenTable(String code); -#endif +#endif \ No newline at end of file diff --git a/src/runtime/AST.h b/src/runtime/AST.h index de39821..78a0bbb 100644 --- a/src/runtime/AST.h +++ b/src/runtime/AST.h @@ -8,30 +8,31 @@ #ifndef WOPS_AST_H #define WOPS_AST_H -#include #include #include #include +#include + #include "../import_/eexec_.h" -#include "../type/variable.h" #include "../type/object.h" #include "../type/operator.h" +#include "../type/variable.h" // enum TYPE {...} // Enumeration of statement types enum StmtType { - Main, - ConstDel, - VarDel, - Expression, - Assignment, - BreakStmt, - ContinueStmt, - IfStmt, - ElifStmt, - ElseStmt, - ForClauseStmt, - ForSCStmt, // For statement with single condition + Main, + ConstDel, + VarDel, + Expression, + Assignment, + BreakStmt, + ContinueStmt, + IfStmt, + ElifStmt, + ElseStmt, + ForStmt, + BracketBlock, // () }; typedef std::unordered_map Storage; @@ -39,187 +40,167 @@ typedef std::unordered_map Storage; /** * class Expr * Expression Syntax Tree class - * + * * Structure - * + * * private * - bool constant, variable, call (token's type) * - Variable token - * - std::vector children + * - std::vector children * - int codeline */ class Expr { - private: - bool constant = 0, variable = 0, call = 0; - Object token; // base object (variable) - std::vector children; - int codeline; - - public: - // constructor - Expr(std::vector t, Object tkn, int _codeline) { - token = tkn, constant = t[0], variable = t[1], call = t[2], codeline = _codeline; - } - - void SetChildren(std::vector rplcment) { - children = rplcment; - } - - void AddChild(Expr child) { - children.push_back(child); - } - - // execute from the tree root - Object Execute(std::vector& storages) { - std::string tkn = token.GetBase().GetValue(); - - if (variable) { - auto iter = storages[0].find(tkn); - bool wasErrorOccured = true; - Object ret; - for (Storage storage: storages) { - iter = storage.find(tkn); - if (iter != storage.end()) { - ret = iter->second; - wasErrorOccured = false; - break; - } - } - if (wasErrorOccured) // has variable declared? - ErrHandler().CallErr(codeline, VARIABLE_HAS_NOT_DECLARED, {tkn}); - - ret.runtime_codeline = codeline; - return ret; - } - if (constant) { - return Object("_", {}, {}, token.GetBase(), 0, codeline, OK); - } - if (call) { - Object arg; - std::vector container; - for (Expr child: children) { - container.push_back(child.Execute(storages)); - } - arg.runtime_codeline = codeline; - arg.dim = 1; arg.ReplaceContainer(container); arg.size = { (Int)container.size() }; - Object res = EExecFunc(tkn, arg); - if (res.errvalue != OK) - ErrHandler().CallErr(codeline, res.errvalue, {tkn}); - - return res; - } - - // Binary Operation - if (tkn == "+") { - Object value = children[0].Execute(storages), operand = children[1].Execute(storages); - if (value.dim != operand.dim) ErrHandler().CallErr(codeline, OBJECT_WRONG_DIMENSION, {tkn, std::to_string(value.dim), std::to_string(operand.dim)}); - if (value.dim == 0) - return Object("_", {}, {}, value.GetBase() + operand.GetBase(), 0, codeline, OK); - ErrHandler().CallErr(codeline, TOO_HIGH_DIMENSION, {tkn, "0", std::to_string(operand.dim)}); - } - if (tkn == "-") { - Object value = children[0].Execute(storages), operand = children[1].Execute(storages); - if (value.dim != operand.dim) ErrHandler().CallErr(codeline, OBJECT_WRONG_DIMENSION, {tkn, std::to_string(value.dim), std::to_string(operand.dim)}); - if (value.dim == 0) - return Object("_", {}, {}, value.GetBase() - operand.GetBase(), 0, codeline, OK); - ErrHandler().CallErr(codeline, TOO_HIGH_DIMENSION, {tkn, "0", std::to_string(operand.dim)}); - } - if (tkn == "*") { - Object value = children[0].Execute(storages), operand = children[1].Execute(storages); - if (value.dim != operand.dim) ErrHandler().CallErr(codeline, OBJECT_WRONG_DIMENSION, {tkn, std::to_string(value.dim), std::to_string(operand.dim)}); - if (value.dim == 0) - return Object("_", {}, {}, value.GetBase() * operand.GetBase(), 0, codeline, OK); - ErrHandler().CallErr(codeline, TOO_HIGH_DIMENSION, {tkn, "0", std::to_string(operand.dim)}); - } - if (tkn == "/") { - Object value = children[0].Execute(storages), operand = children[1].Execute(storages); - if (value.dim != operand.dim) ErrHandler().CallErr(codeline, OBJECT_WRONG_DIMENSION, {tkn, std::to_string(value.dim), std::to_string(operand.dim)}); - if (value.dim == 0) - return Object("_", {}, {}, value.GetBase() / operand.GetBase(), 0, codeline, OK); - ErrHandler().CallErr(codeline, TOO_HIGH_DIMENSION, {tkn, "0", std::to_string(operand.dim)}); - } - if (tkn == "%") { - Object value = children[0].Execute(storages), operand = children[1].Execute(storages); - if (value.dim != operand.dim) ErrHandler().CallErr(codeline, OBJECT_WRONG_DIMENSION, {tkn, std::to_string(value.dim), std::to_string(operand.dim)}); - if (value.dim == 0) - return Object("_", {}, {}, value.GetBase() % operand.GetBase(), 0, codeline, OK); - ErrHandler().CallErr(codeline, TOO_HIGH_DIMENSION, {tkn, "0", std::to_string(operand.dim)}); - } - if (tkn == "==") { - Object value = children[0].Execute(storages), operand = children[1].Execute(storages); - if (value.dim != operand.dim) ErrHandler().CallErr(codeline, OBJECT_WRONG_DIMENSION, {tkn, std::to_string(value.dim), std::to_string(operand.dim)}); - if (value.dim == 0) - return Object("_", {}, {}, value.GetBase() == operand.GetBase(), 0, codeline, OK); - ErrHandler().CallErr(codeline, TOO_HIGH_DIMENSION, {tkn, "0", std::to_string(operand.dim)}); - } - if (tkn == "!=") { - Object value = children[0].Execute(storages), operand = children[1].Execute(storages); - if (value.dim != operand.dim) ErrHandler().CallErr(codeline, OBJECT_WRONG_DIMENSION, {tkn, std::to_string(value.dim), std::to_string(operand.dim)}); - if (value.dim == 0) - return Object("_", {}, {}, value.GetBase() != operand.GetBase(), 0, codeline, OK); - ErrHandler().CallErr(codeline, TOO_HIGH_DIMENSION, {tkn, "0", std::to_string(operand.dim)}); - } - if (tkn == ">") { - Object value = children[0].Execute(storages), operand = children[1].Execute(storages); - if (value.dim != operand.dim) ErrHandler().CallErr(codeline, OBJECT_WRONG_DIMENSION, {tkn, std::to_string(value.dim), std::to_string(operand.dim)}); - if (value.dim == 0) - return Object("_", {}, {}, value.GetBase() > operand.GetBase(), 0, codeline, OK); - ErrHandler().CallErr(codeline, TOO_HIGH_DIMENSION, {tkn, "0", std::to_string(operand.dim)}); - } - if (tkn == ">=") { - Object value = children[0].Execute(storages), operand = children[1].Execute(storages); - if (value.dim != operand.dim) ErrHandler().CallErr(codeline, OBJECT_WRONG_DIMENSION, {tkn, std::to_string(value.dim), std::to_string(operand.dim)}); - if (value.dim == 0) - return Object("_", {}, {}, value.GetBase() >= operand.GetBase(), 0, codeline, OK); - ErrHandler().CallErr(codeline, TOO_HIGH_DIMENSION, {tkn, "0", std::to_string(operand.dim)}); - } - if (tkn == "<") { - Object value = children[0].Execute(storages), operand = children[1].Execute(storages); - if (value.dim != operand.dim) ErrHandler().CallErr(codeline, OBJECT_WRONG_DIMENSION, {tkn, std::to_string(value.dim), std::to_string(operand.dim)}); - if (value.dim == 0) - return Object("_", {}, {}, value.GetBase() < operand.GetBase(), 0, codeline, OK); - ErrHandler().CallErr(codeline, TOO_HIGH_DIMENSION, {tkn, "0", std::to_string(operand.dim)}); - } - if (tkn == "<=") { - Object value = children[0].Execute(storages), operand = children[1].Execute(storages); - if (value.dim != operand.dim) ErrHandler().CallErr(codeline, OBJECT_WRONG_DIMENSION, {tkn, std::to_string(value.dim), std::to_string(operand.dim)}); - if (value.dim == 0) - return Object("_", {}, {}, value.GetBase() <= operand.GetBase(), 0, codeline, OK); - ErrHandler().CallErr(codeline, TOO_HIGH_DIMENSION, {tkn, "0", std::to_string(operand.dim)}); - } - if (tkn == "||") { - Object value = children[0].Execute(storages), operand = children[1].Execute(storages); - if (value.dim != operand.dim) ErrHandler().CallErr(codeline, OBJECT_WRONG_DIMENSION, {tkn, std::to_string(value.dim), std::to_string(operand.dim)}); - if (value.dim == 0) - return Object("_", {}, {}, value.GetBase() || operand.GetBase(), 0, codeline, OK); - ErrHandler().CallErr(codeline, TOO_HIGH_DIMENSION, {tkn, "0", std::to_string(operand.dim)}); - } - if (tkn == "&&") { - Object value = children[0].Execute(storages), operand = children[1].Execute(storages); - if (value.dim != operand.dim) ErrHandler().CallErr(codeline, OBJECT_WRONG_DIMENSION, {tkn, std::to_string(value.dim), std::to_string(operand.dim)}); - if (value.dim == 0) - return Object("_", {}, {}, value.GetBase() && operand.GetBase(), 0, codeline, OK); - ErrHandler().CallErr(codeline, TOO_HIGH_DIMENSION, {tkn, "0", std::to_string(operand.dim)}); - } - - // Unary Operation - if (tkn == "!") { - Object value = children[0].Execute(storages); - if (value.dim == 0) - return Object("_", {}, {}, !value.GetBase(), 0, codeline, OK); - ErrHandler().CallErr(codeline, TOO_HIGH_DIMENSION, {tkn, "0", std::to_string(value.dim)}); - } - } + private: + bool constant = 0, variable = 0, call = 0; + Object token; // base object (variable) + std::vector children; + int codeline; + + public: + // constructor + Expr(std::vector t, Object tkn, int _codeline) { token = tkn, constant = t[0], variable = t[1], call = t[2], codeline = _codeline; } + + void SetChildren(std::vector rplcment) { children = rplcment; } + + void AddChild(Expr child) { children.push_back(child); } + + // execute from the tree root + Object Execute(std::vector& storages) { + std::string tkn = token.GetBase().GetValue(); + + if (variable) { + auto iter = storages[0].find(tkn); + bool wasErrorOccured = true; + Object ret; + for (Storage storage : storages) { + iter = storage.find(tkn); + if (iter != storage.end()) { + ret = iter->second; + wasErrorOccured = false; + break; + } + } + if (wasErrorOccured) // has variable declared? + ErrHandler().CallErr(codeline, VARIABLE_HAS_NOT_DECLARED, {tkn}); + + ret.runtime_codeline = codeline; + return ret; + } + if (constant) { + return Object("_", {}, {}, token.GetBase(), 0, codeline, OK); + } + if (call) { + Object arg; + std::vector container; + for (Expr child : children) { + container.push_back(child.Execute(storages)); + } + arg.runtime_codeline = codeline; + arg.dim = 1; + arg.ReplaceContainer(container); + arg.size = {(Int)container.size()}; + Object res = EExecFunc(tkn, arg); + if (res.errvalue != OK) ErrHandler().CallErr(codeline, res.errvalue, {tkn}); + + return res; + } + + // Binary Operation + if (tkn == "+") { + Object value = children[0].Execute(storages), operand = children[1].Execute(storages); + if (value.dim != operand.dim) ErrHandler().CallErr(codeline, OBJECT_WRONG_DIMENSION, {tkn, std::to_string(value.dim), std::to_string(operand.dim)}); + if (value.dim == 0) return Object("_", {}, {}, value.GetBase() + operand.GetBase(), 0, codeline, OK); + ErrHandler().CallErr(codeline, TOO_HIGH_DIMENSION, {tkn, "0", std::to_string(operand.dim)}); + } + if (tkn == "-") { + Object value = children[0].Execute(storages), operand = children[1].Execute(storages); + if (value.dim != operand.dim) ErrHandler().CallErr(codeline, OBJECT_WRONG_DIMENSION, {tkn, std::to_string(value.dim), std::to_string(operand.dim)}); + if (value.dim == 0) return Object("_", {}, {}, value.GetBase() - operand.GetBase(), 0, codeline, OK); + ErrHandler().CallErr(codeline, TOO_HIGH_DIMENSION, {tkn, "0", std::to_string(operand.dim)}); + } + if (tkn == "*") { + Object value = children[0].Execute(storages), operand = children[1].Execute(storages); + if (value.dim != operand.dim) ErrHandler().CallErr(codeline, OBJECT_WRONG_DIMENSION, {tkn, std::to_string(value.dim), std::to_string(operand.dim)}); + if (value.dim == 0) return Object("_", {}, {}, value.GetBase() * operand.GetBase(), 0, codeline, OK); + ErrHandler().CallErr(codeline, TOO_HIGH_DIMENSION, {tkn, "0", std::to_string(operand.dim)}); + } + if (tkn == "/") { + Object value = children[0].Execute(storages), operand = children[1].Execute(storages); + if (value.dim != operand.dim) ErrHandler().CallErr(codeline, OBJECT_WRONG_DIMENSION, {tkn, std::to_string(value.dim), std::to_string(operand.dim)}); + if (value.dim == 0) return Object("_", {}, {}, value.GetBase() / operand.GetBase(), 0, codeline, OK); + ErrHandler().CallErr(codeline, TOO_HIGH_DIMENSION, {tkn, "0", std::to_string(operand.dim)}); + } + if (tkn == "%") { + Object value = children[0].Execute(storages), operand = children[1].Execute(storages); + if (value.dim != operand.dim) ErrHandler().CallErr(codeline, OBJECT_WRONG_DIMENSION, {tkn, std::to_string(value.dim), std::to_string(operand.dim)}); + if (value.dim == 0) return Object("_", {}, {}, value.GetBase() % operand.GetBase(), 0, codeline, OK); + ErrHandler().CallErr(codeline, TOO_HIGH_DIMENSION, {tkn, "0", std::to_string(operand.dim)}); + } + if (tkn == "==") { + Object value = children[0].Execute(storages), operand = children[1].Execute(storages); + if (value.dim != operand.dim) ErrHandler().CallErr(codeline, OBJECT_WRONG_DIMENSION, {tkn, std::to_string(value.dim), std::to_string(operand.dim)}); + if (value.dim == 0) return Object("_", {}, {}, value.GetBase() == operand.GetBase(), 0, codeline, OK); + ErrHandler().CallErr(codeline, TOO_HIGH_DIMENSION, {tkn, "0", std::to_string(operand.dim)}); + } + if (tkn == "!=") { + Object value = children[0].Execute(storages), operand = children[1].Execute(storages); + if (value.dim != operand.dim) ErrHandler().CallErr(codeline, OBJECT_WRONG_DIMENSION, {tkn, std::to_string(value.dim), std::to_string(operand.dim)}); + if (value.dim == 0) return Object("_", {}, {}, value.GetBase() != operand.GetBase(), 0, codeline, OK); + ErrHandler().CallErr(codeline, TOO_HIGH_DIMENSION, {tkn, "0", std::to_string(operand.dim)}); + } + if (tkn == ">") { + Object value = children[0].Execute(storages), operand = children[1].Execute(storages); + if (value.dim != operand.dim) ErrHandler().CallErr(codeline, OBJECT_WRONG_DIMENSION, {tkn, std::to_string(value.dim), std::to_string(operand.dim)}); + if (value.dim == 0) return Object("_", {}, {}, value.GetBase() > operand.GetBase(), 0, codeline, OK); + ErrHandler().CallErr(codeline, TOO_HIGH_DIMENSION, {tkn, "0", std::to_string(operand.dim)}); + } + if (tkn == ">=") { + Object value = children[0].Execute(storages), operand = children[1].Execute(storages); + if (value.dim != operand.dim) ErrHandler().CallErr(codeline, OBJECT_WRONG_DIMENSION, {tkn, std::to_string(value.dim), std::to_string(operand.dim)}); + if (value.dim == 0) return Object("_", {}, {}, value.GetBase() >= operand.GetBase(), 0, codeline, OK); + ErrHandler().CallErr(codeline, TOO_HIGH_DIMENSION, {tkn, "0", std::to_string(operand.dim)}); + } + if (tkn == "<") { + Object value = children[0].Execute(storages), operand = children[1].Execute(storages); + if (value.dim != operand.dim) ErrHandler().CallErr(codeline, OBJECT_WRONG_DIMENSION, {tkn, std::to_string(value.dim), std::to_string(operand.dim)}); + if (value.dim == 0) return Object("_", {}, {}, value.GetBase() < operand.GetBase(), 0, codeline, OK); + ErrHandler().CallErr(codeline, TOO_HIGH_DIMENSION, {tkn, "0", std::to_string(operand.dim)}); + } + if (tkn == "<=") { + Object value = children[0].Execute(storages), operand = children[1].Execute(storages); + if (value.dim != operand.dim) ErrHandler().CallErr(codeline, OBJECT_WRONG_DIMENSION, {tkn, std::to_string(value.dim), std::to_string(operand.dim)}); + if (value.dim == 0) return Object("_", {}, {}, value.GetBase() <= operand.GetBase(), 0, codeline, OK); + ErrHandler().CallErr(codeline, TOO_HIGH_DIMENSION, {tkn, "0", std::to_string(operand.dim)}); + } + if (tkn == "||") { + Object value = children[0].Execute(storages), operand = children[1].Execute(storages); + if (value.dim != operand.dim) ErrHandler().CallErr(codeline, OBJECT_WRONG_DIMENSION, {tkn, std::to_string(value.dim), std::to_string(operand.dim)}); + if (value.dim == 0) return Object("_", {}, {}, value.GetBase() || operand.GetBase(), 0, codeline, OK); + ErrHandler().CallErr(codeline, TOO_HIGH_DIMENSION, {tkn, "0", std::to_string(operand.dim)}); + } + if (tkn == "&&") { + Object value = children[0].Execute(storages), operand = children[1].Execute(storages); + if (value.dim != operand.dim) ErrHandler().CallErr(codeline, OBJECT_WRONG_DIMENSION, {tkn, std::to_string(value.dim), std::to_string(operand.dim)}); + if (value.dim == 0) return Object("_", {}, {}, value.GetBase() && operand.GetBase(), 0, codeline, OK); + ErrHandler().CallErr(codeline, TOO_HIGH_DIMENSION, {tkn, "0", std::to_string(operand.dim)}); + } + + // Unary Operation + if (tkn == "!") { + Object value = children[0].Execute(storages); + if (value.dim == 0) return Object("_", {}, {}, !value.GetBase(), 0, codeline, OK); + ErrHandler().CallErr(codeline, TOO_HIGH_DIMENSION, {tkn, "0", std::to_string(value.dim)}); + } + } }; - /** - * class AST + * class AST * Abstract Syntax Tree class - * + * * Structure - * + * * private * - StmtType _t * - std::vector childStmt @@ -227,9 +208,9 @@ class Expr { * - std::vector argument * public * - int codeline - * + * * expression - * + * * if AST's type is one of these: * - ConstDel * - VarDel @@ -240,297 +221,256 @@ class Expr { * - ElseStmt * - ForClauseStmt * - ForSCStmt - * + * * expression will not be blank. (length 1) - * + * * argument - * + * * argument can have different formation. * - _t = ConstDel or VarDel: argument[2] = {TYPE, IDENTIFIER} * - _t = Assignment: argument[1] = {IDENTIFIER} * - _t = ForClauseStmt: argument[1] = {VARIABLE} (+ START, STOP, STEP expr) * - others: argument[0] = {} - * + * * every argument's type(Variable::_t) should be OPERATOR. */ class AST { - private: - StmtType _t; - std::vector childStmt; - std::vector expression; - std::vector argument; - - public: - int codeline; - - // constructor - AST(StmtType t, std::vector argv, std::vector expr, int _codeline) { - _t = t, argument = argv, expression = expr, codeline = _codeline; - } - - void SetChildren(std::vector rplcment) { - childStmt = rplcment; - } - - void AddChild(AST child) { - childStmt.push_back(child); - } - - void SetExpr(std::vector rplcment) { - expression = rplcment; - } - - void AddExpr(Expr expr) { - expression.push_back(expr); - } - - void SetArg(std::vector argv) { - argument = argv; - } - - void AddArg(Object argv) { - argument.push_back(argv); - } - - StmtType GetStmt() { return _t; } - - // storages: smaller index, inner variable - std::pair Execute(std::vector& storages) { - switch (_t) { - case Main: { - bool ignoreif = 0; - for (AST ast: childStmt) { - if (ignoreif) { - if (ast._t == ElifStmt || ast._t == ElseStmt) continue; - ignoreif = 0; - } - - std::pair res = ast.Execute(storages); - if (res.first >= 1) - ErrHandler().CallErr(codeline, BREAK_CONTINUE_ONLY_ALLOWED_FOR, {}); - - if (res.second) { - ignoreif = 1; - continue; - } - } - break; - } - - case ConstDel: { - Object v_type = argument[0], v_identifier = argument[1]; - if (v_type.dim != 0 && v_identifier.dim != 0) ErrHandler().CallErr(codeline, TOO_HIGH_DIMENSION, {"Expression", "0", std::to_string(v_type.dim)}); - for (Storage& storage: storages) { - if (storage.find(v_identifier.GetBase().GetValue()) != storage.end()) - ErrHandler().CallErr(codeline, VARIABLE_REDECLARE, {v_identifier.GetBase().GetValue()}); - } - - TYPE v_t = v_type.GetBase().GetValue() == "int" ? INT : ( - v_type.GetBase().GetValue() == "bool" ? BOOL : ( - v_type.GetBase().GetValue() == "string" ? STRING : DOUBLE - ) - ); - - storages[0].insert({v_identifier.GetBase().GetValue(), {v_identifier.GetBase().GetValue(), {}, {}, - Variable( - v_identifier.GetBase().GetValue(), - expression[0].Execute(storages).GetBase().GetValue(), - v_t, - true) - , 0, codeline, OK}}); - - break; - } - - case VarDel: { - Object v_type = argument[0], v_identifier = argument[1]; - for (Storage& storage: storages) { - if (storage.find(v_identifier.GetBase().GetValue()) != storage.end()) - ErrHandler().CallErr(codeline, VARIABLE_REDECLARE, {v_identifier.GetBase().GetValue()}); - } - - TYPE v_t = v_type.GetBase().GetValue() == "int" ? INT : ( - v_type.GetBase().GetValue() == "bool" ? BOOL : ( - v_type.GetBase().GetValue() == "string" ? STRING : DOUBLE - ) - ); - - storages[0].insert({v_identifier.GetBase().GetValue(), {v_identifier.GetBase().GetValue(), {}, {}, - Variable( - v_identifier.GetBase().GetValue(), - expression[0].Execute(storages).GetBase().GetValue(), - v_t, - false) - , 0, codeline, OK}}); - break; - } - - case Expression: - expression[0].Execute(storages); - break; - - case Assignment: { - Object v_identifier = argument[0]; - bool wasErrorOccured = true; - for (Storage& storage: storages) - if (storage.find(v_identifier.GetBase().GetValue()) != storage.end()) { - if (storage[v_identifier.GetBase().GetValue()].GetBase().constant) - ErrHandler().CallErr(codeline, ASSIGN_ON_CONSTANT, {v_identifier.GetBase().GetValue()}); - storage[v_identifier.GetBase().GetValue()].GetBase().Substitute(expression[0].Execute(storages).GetBase().GetValue()); - wasErrorOccured = false; - break; - } - if (wasErrorOccured) - ErrHandler().CallErr(codeline, ASSIGN_ON_UNKNOWN, {v_identifier.GetBase().GetValue()}); - break; - } - - case BreakStmt: - return {2, false}; - - case ContinueStmt: - return {1, false}; - - case IfStmt: { - storages.insert(storages.begin(), Storage()); - Object condition = expression[0].Execute(storages); - if (condition.GetBase()._t != BOOL) - ErrHandler().CallErr(codeline, IF_NO_BOOLEAN_CONDITION, {}); - if (condition.GetBase().GetValue() == "0") { - return {0, false}; - } - bool ignoreif = 0; - for (AST ast: childStmt) { - if (ignoreif) { - if (ast._t == ElifStmt || ast._t == ElseStmt) continue; - ignoreif = 0; - } - std::pair res = ast.Execute(storages); - if (res.first >= 1) { - return {res.first, res.second}; - ErrHandler().CallErr(codeline, BREAK_CONTINUE_ONLY_ALLOWED_FOR, {}); - } - if (res.second) { - ignoreif = 1; - continue; - } - } - storages.erase(storages.begin()); - return {0, true}; - } - - case ElifStmt: { - storages.insert(storages.begin(), Storage()); - Object condition = expression[0].Execute(storages); - if (condition.GetBase()._t != BOOL) - ErrHandler().CallErr(codeline, ELIF_NO_BOOLEAN_CONDITION, {}); - if (condition.GetBase().GetValue() == "0") { - return {0, false}; - } - bool ignoreif = 0; - for (AST ast: childStmt) { - if (ignoreif) { - if (ast._t == ElifStmt || ast._t == ElseStmt) continue; - ignoreif = 0; - } - std::pair res = ast.Execute(storages); - if (res.first >= 1) { - return {res.first, res.second}; - ErrHandler().CallErr(codeline, BREAK_CONTINUE_ONLY_ALLOWED_FOR, {}); - } - if (res.second) { - ignoreif = 1; - continue; - } - } - storages.erase(storages.begin()); - return {0, true}; - } - - case ElseStmt: { - storages.insert(storages.begin(), Storage()); - bool ignoreif = 0; - for (AST ast: childStmt) { - if (ignoreif) { - if (ast._t == ElifStmt || ast._t == ElseStmt) continue; - ignoreif = 0; - } - std::pair res = ast.Execute(storages); - if (res.first >= 1) { - return {res.first, res.second}; - ErrHandler().CallErr(codeline, BREAK_CONTINUE_ONLY_ALLOWED_FOR, {}); - } - if (res.second) { - ignoreif = 1; - continue; - } - } - storages.erase(storages.begin()); - return {0, true}; - } - - case ForClauseStmt: { - for (int idx = std::stoi(expression[0].Execute(storages).GetBase().GetValue()); idx < std::stoi(expression[1].Execute(storages).GetBase().GetValue()); idx += std::stoi(expression[2].Execute(storages).GetBase().GetValue())) { - storages.insert(storages.begin(), Storage()); - storages[0][argument[0].GetBase().GetValue()] = Object(argument[0].GetBase().GetValue(), {}, {}, Variable(argument[0].GetBase().GetValue(), std::to_string(idx), INT), 0, codeline, OK); - bool ignoreif = 0; - bool flowstmt = 0; - for (AST ast: childStmt) { - if (ignoreif) { - if (ast._t == ElifStmt || ast._t == ElseStmt) continue; - ignoreif = 0; - } - std::pair res = ast.Execute(storages); - if (res.first == 2) { - flowstmt = 1; - break; - } - if (res.first == 1) break; - if (res.second) { - ignoreif = 1; - continue; - } - } - storages.erase(storages.begin()); - if (flowstmt) break; - } - break; - } - - case ForSCStmt: { - while (1) { - storages.insert(storages.begin(), Storage()); - Object condition = expression[0].Execute(storages); - if (condition.GetBase()._t != BOOL) - ErrHandler().CallErr(codeline, FOR_NO_BOOLEAN_CONDITION, {}); - if (condition.GetBase().GetValue() == "0") break; - - bool ignoreif = 0; - bool flowstmt = 0; - for (AST ast: childStmt) { - if (ignoreif) { - if (ast._t == ElifStmt || ast._t == ElseStmt) continue; - ignoreif = 0; - } - std::pair res = ast.Execute(storages); - if (res.first == 2) { - flowstmt = 1; - break; - } - if (res.first == 1) break; - if (res.second) { - ignoreif = 1; - continue; - } - } - storages.erase(storages.begin()); - if (flowstmt) break; - } - break; - } - } - return {0, false}; - } + private: + StmtType _t; + std::vector childStmt; + std::vector expression; + std::vector argument; + + public: + int codeline; + + // constructor + AST(StmtType t, std::vector argv, std::vector expr, int _codeline) { _t = t, argument = argv, expression = expr, codeline = _codeline; } + + void SetChildren(std::vector rplcment) { childStmt = rplcment; } + + void AddChild(AST child) { childStmt.push_back(child); } + + void SetExpr(std::vector rplcment) { expression = rplcment; } + + void AddExpr(Expr expr) { expression.push_back(expr); } + + void SetArg(std::vector argv) { argument = argv; } + + void AddArg(Object argv) { argument.push_back(argv); } + + StmtType GetStmt() { return _t; } + + // storages: smaller index, inner variable + std::pair Execute(std::vector& storages) { + switch (_t) { + case Main: { + bool ignoreif = 0; + for (AST ast : childStmt) { + if (ignoreif) { + if (ast._t == ElifStmt || ast._t == ElseStmt) continue; + ignoreif = 0; + } + + std::pair res = ast.Execute(storages); + if (res.first >= 1) ErrHandler().CallErr(codeline, BREAK_CONTINUE_ONLY_ALLOWED_FOR, {}); + + if (res.second) { + ignoreif = 1; + continue; + } + } + break; + } + + case ConstDel: { + Object v_type = argument[0], v_identifier = argument[1]; + if (v_type.dim != 0 && v_identifier.dim != 0) ErrHandler().CallErr(codeline, TOO_HIGH_DIMENSION, {"Expression", "0", std::to_string(v_type.dim)}); + for (Storage& storage : storages) { + if (storage.find(v_identifier.GetBase().GetValue()) != storage.end()) ErrHandler().CallErr(codeline, VARIABLE_REDECLARE, {v_identifier.GetBase().GetValue()}); + } + + TYPE v_t = v_type.GetBase().GetValue() == "int" ? INT : (v_type.GetBase().GetValue() == "bool" ? BOOL : (v_type.GetBase().GetValue() == "string" ? STRING : DOUBLE)); + + storages[0].insert({v_identifier.GetBase().GetValue(), {v_identifier.GetBase().GetValue(), {}, {}, Variable(v_identifier.GetBase().GetValue(), expression[0].Execute(storages).GetBase().GetValue(), v_t, true), 0, codeline, OK}}); + + break; + } + + case VarDel: { + Object v_type = argument[0], v_identifier = argument[1]; + for (Storage& storage : storages) { + if (storage.find(v_identifier.GetBase().GetValue()) != storage.end()) ErrHandler().CallErr(codeline, VARIABLE_REDECLARE, {v_identifier.GetBase().GetValue()}); + } + + TYPE v_t = v_type.GetBase().GetValue() == "int" ? INT : (v_type.GetBase().GetValue() == "bool" ? BOOL : (v_type.GetBase().GetValue() == "string" ? STRING : DOUBLE)); + + storages[0].insert({v_identifier.GetBase().GetValue(), {v_identifier.GetBase().GetValue(), {}, {}, Variable(v_identifier.GetBase().GetValue(), expression[0].Execute(storages).GetBase().GetValue(), v_t, false), 0, codeline, OK}}); + break; + } + + case Expression: + expression[0].Execute(storages); + break; + + case Assignment: { + Object v_identifier = argument[0]; + bool wasErrorOccured = true; + for (Storage& storage : storages) + if (storage.find(v_identifier.GetBase().GetValue()) != storage.end()) { + if (storage[v_identifier.GetBase().GetValue()].GetBase().constant) ErrHandler().CallErr(codeline, ASSIGN_ON_CONSTANT, {v_identifier.GetBase().GetValue()}); + storage[v_identifier.GetBase().GetValue()].GetBase().Substitute(expression[0].Execute(storages).GetBase().GetValue()); + wasErrorOccured = false; + break; + } + if (wasErrorOccured) ErrHandler().CallErr(codeline, ASSIGN_ON_UNKNOWN, {v_identifier.GetBase().GetValue()}); + break; + } + + case BreakStmt: + return {2, false}; + + case ContinueStmt: + return {1, false}; + + case IfStmt: { + storages.insert(storages.begin(), Storage()); + Object condition = expression[0].Execute(storages); + if (condition.GetBase()._t != BOOL) ErrHandler().CallErr(codeline, IF_NO_BOOLEAN_CONDITION, {}); + if (condition.GetBase().GetValue() == "0") { + return {0, false}; + } + bool ignoreif = 0; + for (AST ast : childStmt) { + if (ignoreif) { + if (ast._t == ElifStmt || ast._t == ElseStmt) continue; + ignoreif = 0; + } + std::pair res = ast.Execute(storages); + if (res.first >= 1) { + return {res.first, res.second}; + ErrHandler().CallErr(codeline, BREAK_CONTINUE_ONLY_ALLOWED_FOR, {}); + } + if (res.second) { + ignoreif = 1; + continue; + } + } + storages.erase(storages.begin()); + return {0, true}; + } + + case ElifStmt: { + storages.insert(storages.begin(), Storage()); + Object condition = expression[0].Execute(storages); + if (condition.GetBase()._t != BOOL) ErrHandler().CallErr(codeline, ELIF_NO_BOOLEAN_CONDITION, {}); + if (condition.GetBase().GetValue() == "0") { + return {0, false}; + } + bool ignoreif = 0; + for (AST ast : childStmt) { + if (ignoreif) { + if (ast._t == ElifStmt || ast._t == ElseStmt) continue; + ignoreif = 0; + } + std::pair res = ast.Execute(storages); + if (res.first >= 1) { + return {res.first, res.second}; + ErrHandler().CallErr(codeline, BREAK_CONTINUE_ONLY_ALLOWED_FOR, {}); + } + if (res.second) { + ignoreif = 1; + continue; + } + } + storages.erase(storages.begin()); + return {0, true}; + } + + case ElseStmt: { + storages.insert(storages.begin(), Storage()); + bool ignoreif = 0; + for (AST ast : childStmt) { + if (ignoreif) { + if (ast._t == ElifStmt || ast._t == ElseStmt) continue; + ignoreif = 0; + } + std::pair res = ast.Execute(storages); + if (res.first >= 1) { + return {res.first, res.second}; + ErrHandler().CallErr(codeline, BREAK_CONTINUE_ONLY_ALLOWED_FOR, {}); + } + if (res.second) { + ignoreif = 1; + continue; + } + } + storages.erase(storages.begin()); + return {0, true}; + } + + case ForStmt: { + if (argument.size() >= 1) { + if (argument[0].GetBase().GetValue() == "C" && argument.size() == 2) { // for clause + for (int idx = std::stoi(expression[0].Execute(storages).GetBase().GetValue()); idx < std::stoi(expression[1].Execute(storages).GetBase().GetValue()); idx += std::stoi(expression[2].Execute(storages).GetBase().GetValue())) { + storages.insert(storages.begin(), Storage()); + storages[0][argument[1].GetBase().GetValue()] = Object(argument[1].GetBase().GetValue(), {}, {}, Variable(argument[1].GetBase().GetValue(), std::to_string(idx), INT), 0, codeline, OK); + bool ignoreif = 0; + bool flowstmt = 0; + for (AST ast : childStmt) { + if (ignoreif) { + if (ast._t == ElifStmt || ast._t == ElseStmt) continue; + ignoreif = 0; + } + std::pair res = ast.Execute(storages); + if (res.first == 2) { + flowstmt = 1; + break; + } + if (res.first == 1) break; + if (res.second) { + ignoreif = 1; + continue; + } + } + storages.erase(storages.begin()); + if (flowstmt) break; + } + } else { // single condition + while (1) { + storages.insert(storages.begin(), Storage()); + Object condition = expression[0].Execute(storages); + if (condition.GetBase()._t != BOOL) ErrHandler().CallErr(codeline, FOR_NO_BOOLEAN_CONDITION, {}); + if (condition.GetBase().GetValue() == "0") break; + + bool ignoreif = 0; + bool flowstmt = 0; + for (AST ast : childStmt) { + if (ignoreif) { + if (ast._t == ElifStmt || ast._t == ElseStmt) continue; + ignoreif = 0; + } + std::pair res = ast.Execute(storages); + if (res.first == 2) { + flowstmt = 1; + break; + } + if (res.first == 1) break; + if (res.second) { + ignoreif = 1; + continue; + } + } + storages.erase(storages.begin()); + if (flowstmt) break; + } + } + break; + } + } + } + return {0, false}; + } }; -#endif +#endif \ No newline at end of file diff --git a/src/type/object.h b/src/type/object.h index 89745ba..728d9c8 100644 --- a/src/type/object.h +++ b/src/type/object.h @@ -2,118 +2,121 @@ * src/type/object.h * Wopslang Object Template Headerfile * - * 2021, Wops Team + * 2023, Wops Team * */ #ifndef WOPS_OBJECT_H #define WOPS_OBJECT_H -#include "variable.h" #include +#include "variable.h" + /** - * class Object + * class Object * Wopslang Object Class * * Structure * * Private * - data - * Public - * - size + * Public + * - size * - precalc_size * - dim * - runtime_codeline - * - token + * - token * - errvalue -*/ + */ class Object { - private: - std::vector data; // for base, data = {} - Variable base; // base (0-dim) + private: + std::vector data; // for base, data = {} + Variable base; // base (0-dim) - public: - // a[100][200][300] -> size = {100, 200, 300}, dim = 3 - // single variable -> dim = 0 - std::vector size; // multiplication of all size <= 10^9 - std::vector precalc_size; - Int dim; - Int runtime_codeline; // for error analyzing - String token; - Err errvalue; // special variable: only used to deliver error code + public: + // a[100][200][300] -> size = {100, 200, 300}, dim = 3 + // single variable -> dim = 0 + std::vector size; // multiplication of all size <= 10^9 + std::vector precalc_size; + Int dim; + Int runtime_codeline; // for error analyzing + String token; + Err errvalue; // special variable: only used to deliver error code - // constructor - Object(String objname = "_", std::vector objdata = {}, std::vector objsize = {}, Variable objbase = {}, Int objdim = 0, Int codeline = -1, Err err = OK) { - token = objname; - data = objdata; - base = objbase; - size = objsize; - dim = objdim; - runtime_codeline = codeline; - errvalue = err; - Prepare(); - } + // constructor + Object(String objname = "_", std::vector objdata = {}, std::vector objsize = {}, Variable objbase = {}, Int objdim = 0, Int codeline = -1, Err err = OK) { + token = objname; + data = objdata; + base = objbase; + size = objsize; + dim = objdim; + runtime_codeline = codeline; + errvalue = err; + Prepare(); + } - // void Prepare() - // Prerequisite Job - void Prepare() { - if (!dim) return; - if (dim != size.size()) ErrHandler().CallErr(runtime_codeline, OBJECT_WRONG_DIMENSION, {token, std::to_string(dim), std::to_string(size.size())}); + // void Prepare() + // Prerequisite Job + void Prepare() { + if (!dim) return; + if (dim != size.size()) ErrHandler().CallErr(runtime_codeline, OBJECT_WRONG_DIMENSION, {token, std::to_string(dim), std::to_string(size.size())}); - precalc_size.resize(dim); - precalc_size[dim-1] = 1; - for (int idx = dim-2; idx >= 0; idx--) { - Int *checker; *checker = precalc_size[idx+1]*size[idx+1]; - if (precalc_size[idx+1] > 0 && size[idx+1] > 0 && *checker < 0) ErrHandler().CallErr(runtime_codeline, OBJECT_OVERFLOW, {token}); - if (precalc_size[idx+1] < 0 && size[idx+1] < 0 && *checker > 0) ErrHandler().CallErr(runtime_codeline, OBJECT_OVERFLOW, {token}); - if (precalc_size[idx+1]*size[idx+1] > 1000000000) ErrHandler().CallErr(runtime_codeline, OBJECT_OVERFLOW, {token}); - precalc_size[idx] = precalc_size[idx+1]*size[idx+1]; - } - if (precalc_size[0]*size[0] != data.size()) ErrHandler().CallErr(runtime_codeline, OBJECT_NOT_MATCHING_DATA, {token}); + precalc_size.resize(dim); + precalc_size[dim - 1] = 1; + for (int idx = dim - 2; idx >= 0; idx--) { + Int* checker; + *checker = precalc_size[idx + 1] * size[idx + 1]; + if (precalc_size[idx + 1] > 0 && size[idx + 1] > 0 && *checker < 0) ErrHandler().CallErr(runtime_codeline, OBJECT_OVERFLOW, {token}); + if (precalc_size[idx + 1] < 0 && size[idx + 1] < 0 && *checker > 0) ErrHandler().CallErr(runtime_codeline, OBJECT_OVERFLOW, {token}); + if (precalc_size[idx + 1] * size[idx + 1] > 1000000000) ErrHandler().CallErr(runtime_codeline, OBJECT_OVERFLOW, {token}); + precalc_size[idx] = precalc_size[idx + 1] * size[idx + 1]; } + if (precalc_size[0] * size[0] != data.size()) ErrHandler().CallErr(runtime_codeline, OBJECT_NOT_MATCHING_DATA, {token}); + } - // Object At(std::vector dimidx) - // Get the data addressed by dimidx - Object At(std::vector dimidx) { - if (!dim) return Object("_", {}, {}, base); - if (dim != dimidx.size()) ErrHandler().CallErr(runtime_codeline, OBJECT_WRONG_DIMENSION, {token, std::to_string(dim), std::to_string(dimidx.size())}); + // Object At(std::vector dimidx) + // Get the data addressed by dimidx + Object At(std::vector dimidx) { + if (!dim) return Object("_", {}, {}, base); + if (dim != dimidx.size()) ErrHandler().CallErr(runtime_codeline, OBJECT_WRONG_DIMENSION, {token, std::to_string(dim), std::to_string(dimidx.size())}); - Int idx = IdxFinder(dimidx); - if (idx >= data.size()) ErrHandler().CallErr(runtime_codeline, OBJECT_OVERFLOW, {token}); - return data[IdxFinder(dimidx)]; - } + Int idx = IdxFinder(dimidx); + if (idx >= data.size()) ErrHandler().CallErr(runtime_codeline, OBJECT_OVERFLOW, {token}); + return data[IdxFinder(dimidx)]; + } - // void Replace(std::vector dimidx, Object newdata) - // Replace the data addressed by dimidx with newdata - void Replace(std::vector dimidx, Object newdata) { - if (dim != newdata.dim) ErrHandler().CallErr(runtime_codeline, OBJECT_WRONG_DIMENSION, {token, std::to_string(dim), std::to_string(newdata.dim)}); - if (dimidx.size() != dim) ErrHandler().CallErr(runtime_codeline, OBJECT_WRONG_DIMENSION, {token, std::to_string(dim), std::to_string(dimidx.size())}); - if (!dim) { base = newdata.base; return; } - data[IdxFinder(dimidx)] = newdata; + // void Replace(std::vector dimidx, Object newdata) + // Replace the data addressed by dimidx with newdata + void Replace(std::vector dimidx, Object newdata) { + if (dim != newdata.dim) ErrHandler().CallErr(runtime_codeline, OBJECT_WRONG_DIMENSION, {token, std::to_string(dim), std::to_string(newdata.dim)}); + if (dimidx.size() != dim) ErrHandler().CallErr(runtime_codeline, OBJECT_WRONG_DIMENSION, {token, std::to_string(dim), std::to_string(dimidx.size())}); + if (!dim) { + base = newdata.base; + return; } + data[IdxFinder(dimidx)] = newdata; + } - // void ReplaceContainer(std::vector container) - // Replace whole data with container - void ReplaceContainer(std::vector container) { - data = container; - } + // void ReplaceContainer(std::vector container) + // Replace whole data with container + void ReplaceContainer(std::vector container) { data = container; } - // std::vector GetContainer() - // Getter function for data - std::vector GetContainer() { return data; } + // std::vector GetContainer() + // Getter function for data + std::vector GetContainer() { return data; } - // Variable GetBase() - // Getter function for base - Variable& GetBase() { - if (dim) ErrHandler().CallErr(runtime_codeline, TOO_HIGH_DIMENSION, {token, "0", std::to_string(dim)}); - return base; - } + // Variable GetBase() + // Getter function for base + Variable& GetBase() { + if (dim) ErrHandler().CallErr(runtime_codeline, TOO_HIGH_DIMENSION, {token, "0", std::to_string(dim)}); + return base; + } - // Int IdxFinder(std::vector dimidx) - Int IdxFinder(std::vector dimidx) { - Int cur = 0; - for (int idx = 0; idx < dim; idx++) cur += dimidx[idx]*precalc_size[idx]; - return cur; - } + // Int IdxFinder(std::vector dimidx) + Int IdxFinder(std::vector dimidx) { + Int cur = 0; + for (int idx = 0; idx < dim; idx++) cur += dimidx[idx] * precalc_size[idx]; + return cur; + } }; -#endif +#endif \ No newline at end of file diff --git a/src/type/operator.h b/src/type/operator.h index 9eac19b..274787b 100644 --- a/src/type/operator.h +++ b/src/type/operator.h @@ -2,42 +2,35 @@ * src/type/operator.h * Wopslang Variable Operation Master Headerfile * - * 2021, Wops Team + * 2023, Wops Team * */ #ifndef WOPS_OPERATOR_H #define WOPS_OPERATOR_H #include + #include "variable.h" enum op_ { - // Arithmetic - PLU, // + - MIN, // - - MUL, // * - DIV, // / - MOD, // % - ASSIGN, // = - - // Relational - EQ, // == - NEQ, // != - LG, // > - SM, // < - LGE, // >= - SME, // <= + // Arithmetic + PLU, // + + MIN, // - + MUL, // * + DIV, // / + MOD, // % + ASSIGN, // = - // Logical - LNOT, // ! - LAND, // && - LOR, // || + // Relational + EQ, // == + NEQ, // != + LG, // > + SM, // < + LGE, // >= + SME, // <= - // Bit (will be updated soon) - BNOT, // ~ - BAND, // & - BOR, // | - BXOR, // ^ - BLSH, // << - BRSH, // >> + // Logical + LNOT, // ! + LAND, // && + LOR, // || }; -#endif +#endif \ No newline at end of file diff --git a/src/type/variable.h b/src/type/variable.h index d108831..83be31c 100644 --- a/src/type/variable.h +++ b/src/type/variable.h @@ -2,24 +2,26 @@ * src/type/variable.h * Wopslang Variable Template Headerfile * - * 2021, Wops Team + * 2023, Wops Team * */ #ifndef WOPS_VARIABLE_H #define WOPS_VARIABLE_H #include + #include "../error/signal.h" // enum TYPE {INT, DOUBLE, STRING, BOOL, OPERATOR} // Enumeration of data types enum TYPE { - INT, - DOUBLE, - STRING, - BOOL, - OPERATOR // +, -, *, ... + INT, + DOUBLE, + STRING, + BOOL, + OPERATOR // +, -, *, ... }; +const std::string type_strname[] = {"INT", "DOUBLE", "STRING", "BOOL", "OPERATOR"}; /** * class Variable * Variable container class: each variable has a single value. @@ -30,282 +32,293 @@ enum TYPE { * - value * - token (=variable name) * - type -*/ + */ class Variable { - private: - public: - String value; - String token; - bool constant = 0; - int runtime_codeline; // for error analyzing - TYPE _t; - - // constructor - Variable(String varname = "_", String val = "", TYPE t = OPERATOR, int _runtime_codeline = -1, bool con = 0) { - runtime_codeline = _runtime_codeline; - _t = t; - token = varname; - constant = con; - - if (varname == "") ErrHandler().CallErrDE(runtime_codeline, "Name of variable should not be blank. How about using '_'?"); - if (Substitute(val) == ERROR) ErrHandler().CallErrDE(runtime_codeline, "Type of value does not match with declaration"); + private: + public: + String value; + String token; + bool constant = 0; + int runtime_codeline; // for error analyzing + TYPE _t; + + // constructor + Variable(String varname = "_", String val = "", TYPE t = OPERATOR, int _runtime_codeline = -1, bool con = 0) { + runtime_codeline = _runtime_codeline; + _t = t; + token = varname; + constant = con; + + if (varname == "") ErrHandler().CallErr(runtime_codeline, BLANK_VARIABLE_NAME, {}); + if (Substitute(val) == ERROR) ErrHandler().CallErr(runtime_codeline, NOT_MATCHING_TYPE_WITH_DEF, {varname, type_strname[t]}); + } + + // operation + Variable operator+(Variable operand) { + if (operand.GetValue() == "" || GetValue() == "") ErrHandler().CallErr(runtime_codeline, BLANK_OPERAND, {}); + Variable res = Variable("_", "", _t); + + switch (_t) { + case BOOL: + if (operand._t == STRING || operand._t == DOUBLE) ErrHandler().CallErr(runtime_codeline, NO_OPERATION_MATCHING_TYPE, {"+", "boolean", type_strname[operand._t]}); + res.Substitute(std::to_string(std::stoi(value) + std::stoi(operand.value) != 0)); + break; + case INT: + if (operand._t == STRING) ErrHandler().CallErr(runtime_codeline, NO_OPERATION_MATCHING_TYPE, {"+", "int", "string"}); + if (operand._t == DOUBLE) + res.Substitute(std::to_string((Int)(std::stoi(value) + std::stod(operand.value)))); + else + res.Substitute(std::to_string(std::stoi(value) + std::stoi(operand.value))); + break; + case DOUBLE: + if (operand._t == STRING) ErrHandler().CallErr(runtime_codeline, NO_OPERATION_MATCHING_TYPE, {"+", "double", "string"}); + if (operand._t == DOUBLE) + res.Substitute(std::to_string(std::stod(value) + std::stod(operand.value))); + else + res.Substitute(std::to_string(std::stod(value) + std::stoi(operand.value))); + break; + case STRING: + if (operand._t != STRING) ErrHandler().CallErr(runtime_codeline, NO_OPERATION_MATCHING_TYPE, {"+", "string", type_strname[operand._t]}); + res.Substitute("\"" + trim(value) + trim(operand.value) + "\""); + break; } - - // operation - Variable operator + (Variable operand) { - if (operand.GetValue() == "" || GetValue() == "") ErrHandler().CallErrDE(runtime_codeline, "Operand should not be blank."); - Variable res = Variable("_", "", _t); - - switch (_t) { - case BOOL: - case INT: - if (operand._t == STRING) ErrHandler().CallErrDE(runtime_codeline, "No matching operation between int and string was found."); - if (operand._t == DOUBLE) - res.Substitute(std::to_string((Int)(std::stoi(value)+std::stod(operand.value)))); - else - res.Substitute(std::to_string(std::stoi(value)+std::stoi(operand.value))); - break; - case DOUBLE: - if (operand._t == STRING) ErrHandler().CallErrDE(runtime_codeline, "No matching operation between double and string was found."); - if (operand._t == DOUBLE) - res.Substitute(std::to_string(std::stod(value)+std::stod(operand.value))); - else - res.Substitute(std::to_string(std::stod(value)+std::stoi(operand.value))); - break; - case STRING: - if (operand._t != STRING) ErrHandler().CallErrDE(runtime_codeline, "The only string can operate with string."); - res.Substitute("\""+trim(value)+trim(operand.value)+"\""); - break; - } - return res; + return res; + } + + Variable operator-(Variable operand) { + if (operand.GetValue() == "" || GetValue() == "") ErrHandler().CallErr(runtime_codeline, BLANK_OPERAND, {}); + Variable res = Variable("_", "", _t); + + if (operand._t == STRING || _t == STRING) ErrHandler().CallErr(runtime_codeline, NO_OPERATION_MATCHING_TYPE, {"-", type_strname[_t], type_strname[operand._t]}); + switch (_t) { + case BOOL: + if (operand._t == STRING || operand._t == DOUBLE) ErrHandler().CallErr(runtime_codeline, NO_OPERATION_MATCHING_TYPE, {"-", "boolean", type_strname[operand._t]}); + res.Substitute(std::to_string(std::stoi(value) - std::stoi(operand.value) != 0)); + break; + case INT: + if (operand._t == DOUBLE) + res.Substitute(std::to_string((Int)(std::stoi(value) - std::stod(operand.value)))); + else + res.Substitute(std::to_string(std::stoi(value) - std::stoi(operand.value))); + break; + case DOUBLE: + if (operand._t == DOUBLE) + res.Substitute(std::to_string(std::stod(value) - std::stod(operand.value))); + else + res.Substitute(std::to_string(std::stod(value) - std::stoi(operand.value))); + break; } - - Variable operator - (Variable operand) { - if (operand.GetValue() == "" || GetValue() == "") ErrHandler().CallErrDE(runtime_codeline, "Operand should not be blank."); - Variable res = Variable("_", "", _t); - - if (operand._t == STRING || _t == STRING) ErrHandler().CallErrDE(runtime_codeline, "No matching operation with string and any was found."); - switch (_t) { - case BOOL: - case INT: - if (operand._t == DOUBLE) - res.Substitute(std::to_string((Int)(std::stoi(value)-std::stod(operand.value)))); - else - res.Substitute(std::to_string(std::stoi(value)-std::stoi(operand.value))); - break; - case DOUBLE: - if (operand._t == DOUBLE) - res.Substitute(std::to_string(std::stod(value)-std::stod(operand.value))); - else - res.Substitute(std::to_string(std::stod(value)-std::stoi(operand.value))); - break; - } - return res; + return res; + } + + Variable operator*(Variable operand) { + if (operand.GetValue() == "" || GetValue() == "") ErrHandler().CallErr(runtime_codeline, BLANK_OPERAND, {}); + Variable res = Variable("_", "", _t); + + if (operand._t == STRING || _t == STRING) ErrHandler().CallErr(runtime_codeline, NO_OPERATION_MATCHING_TYPE, {"*", type_strname[_t], type_strname[operand._t]}); + switch (_t) { + case BOOL: + if (operand._t == STRING || operand._t == DOUBLE) ErrHandler().CallErr(runtime_codeline, NO_OPERATION_MATCHING_TYPE, {"*", "boolean", type_strname[operand._t]}); + res.Substitute(std::to_string(std::stoi(value) * std::stoi(operand.value) != 0)); + break; + case INT: + if (operand._t == DOUBLE) + res.Substitute(std::to_string((Int)(std::stoi(value) * std::stod(operand.value)))); + else + res.Substitute(std::to_string(std::stoi(value) * std::stoi(operand.value))); + break; + case DOUBLE: + if (operand._t == DOUBLE) + res.Substitute(std::to_string(std::stod(value) * std::stod(operand.value))); + else + res.Substitute(std::to_string(std::stod(value) * std::stoi(operand.value))); + break; } - - Variable operator * (Variable operand) { - if (operand.GetValue() == "" || GetValue() == "") ErrHandler().CallErrDE(runtime_codeline, "Operand should not be blank."); - Variable res = Variable("_", "", _t); - - if (operand._t == STRING || _t == STRING) ErrHandler().CallErrDE(runtime_codeline, "No matching operation with string and any was found."); - switch (_t) { - case BOOL: - case INT: - if (operand._t == DOUBLE) - res.Substitute(std::to_string((Int)(std::stoi(value)*std::stod(operand.value)))); - else - res.Substitute(std::to_string(std::stoi(value)*std::stoi(operand.value))); - break; - case DOUBLE: - if (operand._t == DOUBLE) - res.Substitute(std::to_string(std::stod(value)*std::stod(operand.value))); - else - res.Substitute(std::to_string(std::stod(value)*std::stoi(operand.value))); - break; - } - return res; + return res; + } + + Variable operator/(Variable operand) { + if (operand.GetValue() == "" || GetValue() == "") ErrHandler().CallErr(runtime_codeline, BLANK_OPERAND, {}); + Variable res = Variable("_", "", _t); + + if (operand._t == STRING || _t == STRING) ErrHandler().CallErr(runtime_codeline, NO_OPERATION_MATCHING_TYPE, {"/", type_strname[_t], type_strname[operand._t]}); + if (operand.GetValue() == "0") ErrHandler().CallErr(runtime_codeline, DIVIDING_WITH_ZERO, {}); + switch (_t) { + case BOOL: + if (operand._t == STRING || operand._t == DOUBLE) ErrHandler().CallErr(runtime_codeline, NO_OPERATION_MATCHING_TYPE, {"/", "boolean", type_strname[operand._t]}); + res.Substitute(std::to_string(std::stoi(value) / std::stoi(operand.value) != 0)); + break; + case INT: + if (operand._t == DOUBLE) + res.Substitute(std::to_string((Int)(std::stoi(value) / std::stod(operand.value)))); + else + res.Substitute(std::to_string(std::stoi(value) / std::stoi(operand.value))); + break; + case DOUBLE: + if (operand._t == DOUBLE) + res.Substitute(std::to_string(std::stod(value) / std::stod(operand.value))); + else + res.Substitute(std::to_string(std::stod(value) / std::stoi(operand.value))); + break; } - - Variable operator / (Variable operand) { - if (operand.GetValue() == "" || GetValue() == "") ErrHandler().CallErrDE(runtime_codeline, "Operand should not be blank."); - Variable res = Variable("_", "", _t); - - if (operand._t == STRING || _t == STRING) ErrHandler().CallErrDE(runtime_codeline, "No matching operation with string and any was found."); - if (operand.GetValue() == "0") ErrHandler().CallErrDE(runtime_codeline, "Not allowed to divide with zero"); - switch (_t) { - case BOOL: - case INT: - if (operand._t == DOUBLE) - res.Substitute(std::to_string((Int)(std::stoi(value)/std::stod(operand.value)))); - else - res.Substitute(std::to_string(std::stoi(value)/std::stoi(operand.value))); - break; - case DOUBLE: - if (operand._t == DOUBLE) - res.Substitute(std::to_string(std::stod(value)/std::stod(operand.value))); - else - res.Substitute(std::to_string(std::stod(value)/std::stoi(operand.value))); - break; - } - return res; + return res; + } + + Variable operator%(Variable operand) { + if (operand.GetValue() == "" || GetValue() == "") ErrHandler().CallErr(runtime_codeline, BLANK_OPERAND, {}); + Variable res = Variable("_", "", _t); + + if (operand._t == STRING || _t == STRING) ErrHandler().CallErr(runtime_codeline, NO_OPERATION_MATCHING_TYPE, {"%", type_strname[_t], type_strname[operand._t]}); + if (operand.GetValue() == "0") ErrHandler().CallErr(runtime_codeline, DIVIDING_WITH_ZERO, {}); + switch (_t) { + case INT: + res.Substitute(std::to_string(std::stoi(value) % std::stoi(operand.value))); + break; } + return res; + } - Variable operator % (Variable operand) { - if (operand.GetValue() == "" || GetValue() == "") ErrHandler().CallErrDE(runtime_codeline, "Operand should not be blank."); - Variable res = Variable("_", "", _t); + Variable operator==(Variable operand) { + if (operand.GetValue() == "" || GetValue() == "") ErrHandler().CallErr(runtime_codeline, BLANK_OPERAND, {}); + Variable res = Variable("_", "", BOOL); - if (operand._t == STRING || _t == STRING) ErrHandler().CallErrDE(runtime_codeline, "No matching operation with string and any was found."); - if (operand.GetValue() == "0") ErrHandler().CallErrDE(runtime_codeline, "Not allowed to divide with zero"); - switch (_t) { - case INT: - res.Substitute(std::to_string(std::stoi(value)%std::stoi(operand.value))); - break; - } - return res; - } + if (operand._t != _t) ErrHandler().CallErr(runtime_codeline, NOT_MATCHING_TYPE_WHEN_COMP, {type_strname[_t], type_strname[operand._t]}); + res.Substitute(std::to_string(operand.GetValue() == GetValue())); - Variable operator == (Variable operand) { - if (operand.GetValue() == "" || GetValue() == "") ErrHandler().CallErrDE(runtime_codeline, "Operand should not be blank."); - Variable res = Variable("_", "", BOOL); + return res; + } - if (operand._t != _t) ErrHandler().CallErrDE(runtime_codeline, "Not allowed to compare between different type variables."); - res.Substitute(std::to_string(operand.GetValue()==GetValue())); + Variable operator!=(Variable operand) { + if (operand.GetValue() == "" || GetValue() == "") ErrHandler().CallErr(runtime_codeline, BLANK_OPERAND, {}); + Variable res = Variable("_", "", BOOL); - return res; - } + if (operand._t != _t) ErrHandler().CallErr(runtime_codeline, NOT_MATCHING_TYPE_WHEN_COMP, {type_strname[_t], type_strname[operand._t]}); + res.Substitute(std::to_string(operand.GetValue() != GetValue())); - Variable operator != (Variable operand) { - if (operand.GetValue() == "" || GetValue() == "") ErrHandler().CallErrDE(runtime_codeline, "Operand should not be blank."); - Variable res = Variable("_", "", BOOL); + return res; + } - if (operand._t != _t) ErrHandler().CallErrDE(runtime_codeline, "Not allowed to compare between different type variables."); - res.Substitute(std::to_string(operand.GetValue()!=GetValue())); + Variable operator>(Variable operand) { + if (operand.GetValue() == "" || GetValue() == "") ErrHandler().CallErr(runtime_codeline, BLANK_OPERAND, {}); + Variable res = Variable("_", "", BOOL); - return res; + try { + res.Substitute(std::to_string(operand.GetValue() > GetValue())); + } catch (const std::exception& e) { + ErrHandler().CallErr(runtime_codeline, ERROR_OCCURED_WHILE_CALLING_FUNCTION, {">"}); } - Variable operator > (Variable operand) { - if (operand.GetValue() == "" || GetValue() == "") ErrHandler().CallErrDE(runtime_codeline, "Operand should not be blank."); - Variable res = Variable("_", "", BOOL); + return res; + } - try { - res.Substitute(std::to_string(operand.GetValue()>GetValue())); - } - catch(const std::exception& e) { - ErrHandler().CallErrDE(runtime_codeline, "Something went wrong :("); - } + Variable operator<(Variable operand) { + if (operand.GetValue() == "" || GetValue() == "") ErrHandler().CallErr(runtime_codeline, BLANK_OPERAND, {}); + Variable res = Variable("_", "", BOOL); - return res; + try { + res.Substitute(std::to_string(operand.GetValue() < GetValue())); + } catch (const std::exception& e) { + ErrHandler().CallErr(runtime_codeline, ERROR_OCCURED_WHILE_CALLING_FUNCTION, {"<"}); } - Variable operator < (Variable operand) { - if (operand.GetValue() == "" || GetValue() == "") ErrHandler().CallErrDE(runtime_codeline, "Operand should not be blank."); - Variable res = Variable("_", "", BOOL); + return res; + } - try { - res.Substitute(std::to_string(operand.GetValue()=(Variable operand) { + if (operand.GetValue() == "" || GetValue() == "") ErrHandler().CallErr(runtime_codeline, BLANK_OPERAND, {}); + Variable res = Variable("_", "", BOOL); - return res; + try { + res.Substitute(std::to_string(operand.GetValue() >= GetValue())); + } catch (const std::exception& e) { + ErrHandler().CallErr(runtime_codeline, ERROR_OCCURED_WHILE_CALLING_FUNCTION, {">="}); } - Variable operator >= (Variable operand) { - if (operand.GetValue() == "" || GetValue() == "") ErrHandler().CallErrDE(runtime_codeline, "Operand should not be blank."); - Variable res = Variable("_", "", BOOL); + return res; + } - try { - res.Substitute(std::to_string(operand.GetValue()>=GetValue())); - } - catch(const std::exception& e) { - ErrHandler().CallErrDE(runtime_codeline, "Something went wrong :("); - } + Variable operator<=(Variable operand) { + if (operand.GetValue() == "" || GetValue() == "") ErrHandler().CallErr(runtime_codeline, BLANK_OPERAND, {}); + Variable res = Variable("_", "", BOOL); - return res; + try { + res.Substitute(std::to_string(operand.GetValue() <= GetValue())); + } catch (const std::exception& e) { + ErrHandler().CallErr(runtime_codeline, ERROR_OCCURED_WHILE_CALLING_FUNCTION, {"<="}); } - Variable operator <= (Variable operand) { - if (operand.GetValue() == "" || GetValue() == "") ErrHandler().CallErrDE(runtime_codeline, "Operand should not be blank."); - Variable res = Variable("_", "", BOOL); + return res; + } - try { - res.Substitute(std::to_string(operand.GetValue()<=GetValue())); - } - catch(const std::exception& e) { - ErrHandler().CallErrDE(runtime_codeline, "Something went wrong :("); - } + Variable operator!() { + Variable res = Variable("_", "", BOOL); - return res; - } + if (_t != BOOL) ErrHandler().CallErr(runtime_codeline, NO_OPERATION_MATCHING_TYPE_UNARY, {"!"}); + res.Substitute(std::to_string(!(std::stoi(GetValue())))); + return res; + } - Variable operator ! () { - Variable res = Variable("_", "", BOOL); + Variable operator&&(Variable operand) { + if (operand.GetValue() == "" || GetValue() == "") ErrHandler().CallErr(runtime_codeline, BLANK_OPERAND, {}); + Variable res = Variable("_", "", BOOL); + if (_t != BOOL || operand._t != BOOL) ErrHandler().CallErr(runtime_codeline, NO_OPERATION_MATCHING_TYPE, {"&&", type_strname[_t], type_strname[operand._t]}); - if (_t != BOOL) ErrHandler().CallErrDE(runtime_codeline, "Operation ! allows only boolean variables."); - res.Substitute(std::to_string( - !(std::stoi(GetValue())) - )); - return res; - } - - Variable operator && (Variable operand) { - if (operand.GetValue() == "" || GetValue() == "") ErrHandler().CallErrDE(runtime_codeline, "Operand should not be blank."); - Variable res = Variable("_", "", BOOL); - if (_t != BOOL || operand._t != BOOL) ErrHandler().CallErrDE(runtime_codeline, "Operation && allows only boolean variables."); + res.Substitute(std::to_string(std::stoi(operand.GetValue()) && std::stoi(GetValue()))); - res.Substitute(std::to_string(std::stoi(operand.GetValue())&&std::stoi(GetValue()))); + return res; + } - return res; - } + Variable operator||(Variable operand) { + if (operand.GetValue() == "" || GetValue() == "") ErrHandler().CallErr(runtime_codeline, BLANK_OPERAND, {}); + Variable res = Variable("_", "", BOOL); + if (_t != BOOL || operand._t != BOOL) ErrHandler().CallErr(runtime_codeline, NO_OPERATION_MATCHING_TYPE, {"||", type_strname[_t], type_strname[operand._t]}); - Variable operator || (Variable operand) { - if (operand.GetValue() == "" || GetValue() == "") ErrHandler().CallErrDE(runtime_codeline, "Operand should not be blank."); - Variable res = Variable("_", "", BOOL); - if (_t != BOOL || operand._t != BOOL) ErrHandler().CallErrDE(runtime_codeline, "Operation || allows only boolean variables."); + res.Substitute(std::to_string(std::stoi(operand.GetValue()) || std::stoi(GetValue()))); - res.Substitute(std::to_string(std::stoi(operand.GetValue())||std::stoi(GetValue()))); + return res; + } - return res; - } + // management + inline Err Substitute(String newval); // substitute + inline String GetValue(); // extract - // management - inline Err Substitute(String newval); // substitute - inline String GetValue(); // extract - - // utility - inline String trim(String s) { s = s.erase(0,1); return s.erase(s.length()-1, 1); } + // utility + inline String trim(String s) { + s = s.erase(0, 1); + return s.erase(s.length() - 1, 1); + } }; inline Err Variable::Substitute(String newval) { - if (newval == "") return OK; - try { - switch (_t) { - case INT: - value = std::to_string(std::stoi(newval)); - break; - case DOUBLE: - value = std::to_string(std::stod(newval)); - break; - case BOOL: - value = std::to_string(std::stoi(newval)); - break; - case STRING: - if (newval == "") {value = newval; break;} - if (newval[0] != '"' || newval[newval.length()-1] != '"' || newval.length() < 2) return ERROR; - value = newval; - break; - case OPERATOR: - value = newval; - break; + if (newval == "") return OK; + try { + switch (_t) { + case INT: + value = std::to_string(std::stoi(newval)); + break; + case DOUBLE: + value = std::to_string(std::stod(newval)); + break; + case BOOL: + value = std::to_string(std::stoi(newval)); + break; + case STRING: + if (newval == "") { + value = newval; + break; } + if (newval[0] != '"' || newval[newval.length() - 1] != '"' || newval.length() < 2) return ERROR; + value = newval; + break; + case OPERATOR: + value = newval; + break; } - catch(const std::exception& e) { - return ERROR; - } + } catch (const std::exception& e) { + return ERROR; + } - return OK; + return OK; } inline String Variable::GetValue() { return value; } @@ -313,8 +326,8 @@ inline String Variable::GetValue() { return value; } // struct VariableWithCode // Has Variable class and Err enum as elements. struct VariableWithCode { - Variable var; - Err error; + Variable var; + Err error; }; -#endif +#endif \ No newline at end of file