├── .github ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── ci.yml ├── .gitignore ├── CODEOWNERS ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── TRUTH.md ├── ast.c ├── ast.h ├── docs ├── brainrot-user-guide.md └── the-brainrot-programming-language.md ├── examples ├── README.md ├── bubble_sort.brainrot ├── fibonacci.brainrot ├── fizz_buzz.brainrot ├── heat_equation_1d.brainrot ├── hello_world.brainrot ├── sieve_of_eras.brainrot └── twoSum.brainrot ├── lang.l ├── lang.y ├── lib ├── arena.c ├── arena.h ├── hm.c ├── hm.h ├── input.c ├── input.h ├── mem.c └── mem.h ├── run_valgrind_tests.sh ├── test_cases ├── add_two_numbers.brainrot ├── array_initialization.brainrot ├── bool_array.brainrot ├── boolean.brainrot ├── char.brainrot ├── char_array.brainrot ├── chill.brainrot ├── circle_area.brainrot ├── circle_area_double.brainrot ├── comparison_edge_case.brainrot ├── const.brainrot ├── division_by_zero.brainrot ├── division_edge_cases.brainrot ├── do-while.brainrot ├── double_array.brainrot ├── double_vs_float.brainrot ├── fib.brainrot ├── fizz_buzz.brainrot ├── fizz_buzz_short.brainrot ├── float.brainrot ├── float_array.brainrot ├── float_precision.brainrot ├── for_loop.brainrot ├── for_loop_break.brainrot ├── func-modifier.brainrot ├── func_scope.brainrot ├── hello_world.brainrot ├── inc-dec.brainrot ├── int.brainrot ├── int_array.brainrot ├── integer_overflow.brainrot ├── is_prime.brainrot ├── max_gigachad.brainrot ├── mixed_types.brainrot ├── modulo.brainrot ├── modulo_edge_case.brainrot ├── mul_two_numbers.brainrot ├── multi_array.brainrot ├── nest-loop.brainrot ├── next-prime.brainrot ├── output_error.brainrot ├── rage_quit.brainrot ├── scientific_notation.brainrot ├── short_array.brainrot ├── sizeof.brainrot ├── slorp_char.brainrot ├── slorp_double.brainrot ├── slorp_float.brainrot ├── slorp_int.brainrot ├── slorp_short.brainrot ├── slorp_string.brainrot ├── switch_case.brainrot ├── type_conversion.brainrot ├── uint.brainrot ├── unsigned_integer_wrap.brainrot ├── while_loop.brainrot └── while_loop_break.brainrot └── tests ├── .gitignore ├── README.md ├── expected_results.json ├── requirements.txt └── test_brainrot.py /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | 4 | 5 | ## Related Issue 6 | 7 | 8 | 9 | Fixes # 10 | 11 | ## Type of Change 12 | 13 | - [ ] Bug fix (non-breaking change which fixes an issue) 14 | - [ ] New feature (non-breaking change which adds functionality) 15 | - [ ] Breaking change (fix or feature that would cause existing functionality to change) 16 | - [ ] Documentation update 17 | - [ ] Performance improvement 18 | - [ ] Refactor 19 | 20 | ## Checklist 21 | 22 | - [ ] My code follows the style guidelines of this project 23 | - [ ] I have performed a self-review of my own code 24 | - [ ] I have documented my changes in the code or documentation 25 | - [ ] I have added tests that prove my changes work (if applicable) 26 | - [ ] I have run the unit tests locally 27 | - [ ] I have run the valgrind memory tests locally 28 | - [ ] All new and existing tests pass 29 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Brainrot CI 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: ["main"] 7 | paths-ignore: 8 | - "**/*.md" 9 | - "CODEOWNERS" 10 | - "Makefile" 11 | pull_request: 12 | branches: ["main"] 13 | paths-ignore: 14 | - "**/*.md" 15 | - "CODEOWNERS" 16 | - "Makefile" 17 | 18 | jobs: 19 | build: 20 | runs-on: ubuntu-latest 21 | 22 | steps: 23 | - name: Checkout code 24 | uses: actions/checkout@v4 25 | 26 | - name: Install build dependencies 27 | run: | 28 | sudo apt-get update 29 | sudo apt-get install gcc flex bison libfl-dev -y 30 | 31 | - name: Build Brainrot 32 | run: | 33 | make 34 | 35 | - name: Upload build artifacts 36 | uses: actions/upload-artifact@v4 37 | with: 38 | name: brainrot 39 | path: brainrot 40 | 41 | test: 42 | runs-on: ubuntu-latest 43 | needs: build 44 | 45 | steps: 46 | - name: Checkout code 47 | uses: actions/checkout@v4 48 | 49 | - name: Download Brainrot artifact 50 | uses: actions/download-artifact@v4 51 | with: 52 | name: brainrot 53 | 54 | - name: Grant execute permissions to Brainrot 55 | run: chmod +x brainrot 56 | 57 | - name: Install Python and dependencies 58 | run: | 59 | sudo apt-get update 60 | sudo apt-get install python3 python3-pip valgrind -y 61 | python3 -m venv .venv 62 | source .venv/bin/activate 63 | pip install -r requirements.txt 64 | working-directory: tests 65 | 66 | - name: Run Pytest 67 | run: | 68 | source .venv/bin/activate 69 | pytest -v test_brainrot.py 70 | working-directory: tests 71 | 72 | - name: Run Valgrind on all .brainrot tests 73 | run: | 74 | chmod +x run_valgrind_tests.sh 75 | ./run_valgrind_tests.sh 76 | working-directory: . 77 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | brainrot 3 | lang.tab.c 4 | lang.tab.h 5 | lex.yy.c 6 | lang.gv 7 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @araujo88 @SIGMazer 2 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Brainrot 2 | 3 | Welcome to Brainrot! We're excited that you want to contribute. This document provides guidelines and information for contributing to the project. 4 | 5 | ## Code of Conduct 6 | 7 | By participating in this project, you are expected to uphold our Code of Conduct (follows standard open source practices). 8 | 9 | ## Getting Started 10 | 11 | 1. Fork the repository 12 | 2. Clone your fork: `git clone https://github.com/yourusername/Brainrot.git` 13 | 3. Create a branch for your changes: `git checkout -b feature/your-feature-name` 14 | 15 | ## Development Environment 16 | 17 | ### Prerequisites 18 | 19 | - C compiler (gcc recommended) 20 | - Flex and Bison 21 | - Valgrind 22 | - Make 23 | 24 | ### Building the Project 25 | 26 | ```bash 27 | make clean 28 | make 29 | ``` 30 | 31 | ### Running Tests 32 | 33 | The test suite can be run using: 34 | 35 | ```bash 36 | make test 37 | ``` 38 | 39 | ### Running Memory Leak Tests 40 | 41 | Make `run_valgrind_tests.sh` executable: 42 | 43 | ```bash 44 | sudo chmod +x run_valgrind_tests.sh 45 | ``` 46 | 47 | Run: 48 | 49 | ```bash 50 | ./run_valgrind_tests.sh 51 | ``` 52 | 53 | ## Project Structure 54 | 55 | - `ast.h` / `ast.c`: Abstract Syntax Tree implementation 56 | - `lang.y`: Bison grammar file 57 | - `lang.l`: Flex lexer file 58 | - `examples/`: Example Brainrot programs 59 | - `tests/`: Test suite 60 | 61 | ## Adding New Features 62 | 63 | 1. First, check existing issues and PRs to avoid duplicate work 64 | 2. Create an issue discussing the feature before implementing 65 | 3. Follow the existing code style 66 | 4. Add appropriate tests in `tests/` 67 | 5. Add example usage in `examples/` 68 | 69 | ## Testing Guidelines 70 | 71 | 1. All new features must include tests 72 | 2. Test files go in `tests/` 73 | 3. Expected outputs should be added to `expected_results.json` 74 | 4. Tests should cover: 75 | - Happy path 76 | - Error conditions 77 | - Edge cases 78 | 79 | ## Pull Request Process 80 | 81 | 1. Update documentation as needed 82 | 2. Add or update tests 83 | 3. Ensure all tests pass 84 | 4. Update CHANGELOG.md if applicable 85 | 5. Reference any related issues 86 | 87 | Example PR format: 88 | 89 | ```markdown 90 | ## Description 91 | 92 | Brief description of changes 93 | 94 | ## Related Issue 95 | 96 | Fixes # 97 | 98 | ## Type of Change 99 | 100 | - [ ] Bug fix 101 | - [ ] New feature 102 | - [ ] Documentation update 103 | - [ ] Performance improvement 104 | ``` 105 | 106 | ## Style Guide 107 | 108 | ### C Code Style 109 | 110 | - Use 4 spaces for indentation 111 | - Maximum line length of 80 characters 112 | - Function names use snake_case 113 | - Constants use UPPER_SNAKE_CASE 114 | - Add comments for complex logic 115 | - Include parameter documentation for functions 116 | 117 | ### Grammar Style 118 | 119 | - Token names should be descriptive 120 | - Use consistent naming patterns for similar concepts 121 | - Document grammar rules with examples 122 | 123 | ## Documentation 124 | 125 | - Keep README.md updated with new features 126 | - Document all public functions 127 | - Include examples for new features 128 | - Use clear, concise language 129 | 130 | ## Bug Reports 131 | 132 | When filing a bug report, include: 133 | 134 | 1. Brainrot version 135 | 2. Operating system 136 | 3. Complete error message 137 | 4. Minimal reproduction code 138 | 5. Expected vs actual behavior 139 | 140 | ## Getting Help 141 | 142 | If you need help, you can: 143 | 144 | 1. Check existing issues 145 | 2. Create a new issue with your question 146 | 3. Add [HELP WANTED] tag for implementation assistance 147 | 148 | ## License 149 | 150 | By contributing, you agree that your contributions will be licensed under the same terms as the main project. 151 | 152 | ## Acknowledgments 153 | 154 | Thank you to all contributors who help make Brainrot better! 155 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Compiler and tool configurations 2 | CC := gcc 3 | BISON := bison 4 | FLEX := flex 5 | PYTHON := python3 6 | 7 | # Compiler and linker flags 8 | CFLAGS := -Wall -Wextra -Wpedantic -Werror -O2 -Wuninitialized 9 | LDFLAGS := -lfl -lm 10 | 11 | # Source files and directories 12 | SRC_DIR := lib 13 | DEBUG_FLAGS := -g 14 | SRCS := $(SRC_DIR)/hm.c $(SRC_DIR)/mem.c $(SRC_DIR)/input.c $(SRC_DIR)/arena.c ast.c 15 | GENERATED_SRCS := lang.tab.c lex.yy.c 16 | ALL_SRCS := $(SRCS) $(GENERATED_SRCS) 17 | 18 | # Output files 19 | TARGET := brainrot 20 | BISON_OUTPUT := lang.tab.c 21 | FLEX_OUTPUT := lex.yy.c 22 | 23 | # Default target 24 | .PHONY: all 25 | all: $(TARGET) 26 | 27 | # Debug target 28 | .PHONY: debug 29 | debug: CFLAGS += $(DEBUG_FLAGS) 30 | debug: clean $(TARGET) 31 | @echo "Debug build compiled with -g. Time to sigma grind with GDB." 32 | 33 | 34 | # Main executable build 35 | $(TARGET): $(ALL_SRCS) 36 | $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) 37 | @echo "Skibidi toilet: $(TARGET) compiled with max gyatt." 38 | 39 | # Generate parser files using Bison 40 | $(BISON_OUTPUT): lang.y 41 | $(BISON) -d -Wcounterexamples $< -o $@ 42 | @echo "Bison is sigma grinding with $(BISON_OUTPUT)." 43 | 44 | # Generate lexer files using Flex 45 | $(FLEX_OUTPUT): lang.l 46 | $(FLEX) $< 47 | @echo "Flex is literally hitting the griddy to generate $(FLEX_OUTPUT)." 48 | 49 | # Run tests 50 | .PHONY: test 51 | test: 52 | $(PYTHON) -m pytest -v 53 | @echo "Tests ran bussin', no cap." 54 | 55 | # Clean build artifacts 56 | .PHONY: clean 57 | clean: 58 | rm -f $(TARGET) $(GENERATED_SRCS) lang.tab.h 59 | rm -f *.o 60 | @echo "Blud cleaned up the mess like a true sigma coder." 61 | 62 | # Run Valgrind on all .brainrot tests 63 | .PHONY: valgrind 64 | valgrind: 65 | @./run_valgrind_tests.sh 66 | @echo "Valgrind check done. If anything was sus, it'll show up with a non-zero exit code. No cap." 67 | 68 | # Install target 69 | .PHONY: install 70 | install: 71 | install -d /usr/local/bin 72 | install -m 755 $(TARGET) /usr/local/bin/ 73 | @echo "$(TARGET) installed successfully. You're goated with the sauce!" 74 | 75 | # Uninstall target 76 | .PHONY: uninstall 77 | uninstall: 78 | rm -f /usr/local/bin/$(TARGET) 79 | @echo "$(TARGET) uninstalled successfully. Back to the grind." 80 | 81 | # Check dependencies 82 | .PHONY: check-deps 83 | check-deps: 84 | @command -v $(CC) >/dev/null 2>&1 || { echo "Error: gcc not found. Blud, install gcc!"; exit 1; } 85 | @command -v $(BISON) >/dev/null 2>&1 || { echo "Error: bison not found. Duke Dennis did you pray today?"; exit 1; } 86 | @command -v $(FLEX) >/dev/null 2>&1 || { echo "Error: flex not found. Ayo, where's flex?"; exit 1; } 87 | @command -v $(PYTHON) >/dev/null 2>&1 || { echo "Error: python3 not found. Python in Ohio moment."; exit 1; } 88 | @$(PYTHON) -c "import pytest" >/dev/null 2>&1 || { echo "Error: pytest not found. Install with: pip install pytest. That's the ocky way."; exit 1; } 89 | 90 | # Development helper to rebuild everything from scratch 91 | .PHONY: rebuild 92 | rebuild: clean all 93 | @echo "Whole bunch of turbulence cleared. Rebuilt everything." 94 | 95 | # Format source files (requires clang-format) 96 | .PHONY: format 97 | format: 98 | @command -v clang-format >/dev/null 2>&1 || { echo "Error: clang-format not found. Ratioed by clang."; exit 1; } 99 | find . -name "*.c" -o -name "*.h" | xargs clang-format -i 100 | @echo "Source files got the rizz treatment, goated with the sauce." 101 | 102 | # Show help 103 | .PHONY: help 104 | help: 105 | @echo "Available targets (rizzy edition):" 106 | @echo " all : Build the main executable (default target). Sigma grindset activated." 107 | @echo " install : Install the binary to /usr/local/bin. Certified W." 108 | @echo " uninstall : Uninstall the binary from /usr/local/bin. Back to square one." 109 | @echo " test : Run the test suite. Huggy Wuggy approves." 110 | @echo " clean : Remove all generated files. Amogus sussy imposter mode." 111 | @echo " check-deps : Verify all required bro apps are installed." 112 | @echo " rebuild : Clean and re-grind the project." 113 | @echo " format : Format source files using clang-format. No cringe, all kino." 114 | @echo " valgrind : Checks for sussy memory leaks with Valgrind." 115 | @echo " help : Show this help for n00bs." 116 | @echo "" 117 | @echo "Configuration (poggers):" 118 | @echo " CC = $(CC)" 119 | @echo " CFLAGS = $(CFLAGS)" 120 | @echo " LDFLAGS = $(LDFLAGS)" 121 | @echo " TARGET = $(TARGET)" 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Brainrot Programming Language 2 | 3 | [![license](https://img.shields.io/badge/license-GPL-green)](https://raw.githubusercontent.com/araujo88/brainrot/main/LICENSE) 4 | [![CI](https://github.com/araujo88/brainrot/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/araujo88/brainrot/actions/workflows/ci.yml) 5 | 6 | Brainrot is a meme-inspired programming language that translates common programming keywords into internet slang and meme references. It's built using Flex (lexical analyzer) and Bison (parser generator), making it a fun way to learn about language processing and compiler design. 7 | 8 | ## History 9 | 10 | The TRUE history behind the Brainrot programming language can be found [here](TRUTH.md). 11 | 12 | ## 🤔 What is Brainrot? 13 | 14 | Brainrot is a C-like programming language where traditional keywords are replaced with popular internet slang. For example: 15 | 16 | - `void` → `skibidi` 17 | - `int` → `rizz` 18 | - `for` → `flex` 19 | - `return` → `bussin` 20 | 21 | ## 📋 Requirements 22 | 23 | To build and run the Brainrot compiler, you'll need: 24 | 25 | - GCC (GNU Compiler Collection) 26 | - Flex (Fast Lexical Analyzer) 27 | - Bison (Parser Generator) 28 | 29 | ### Installation on Different Platforms 30 | 31 | #### Ubuntu/Debian 32 | 33 | ```bash 34 | sudo apt-get update 35 | sudo apt-get install gcc flex bison libfl-dev 36 | ``` 37 | 38 | #### Arch Linux 39 | 40 | ```bash 41 | sudo pacman -S gcc flex bison 42 | ``` 43 | 44 | #### macOS (using Homebrew) 45 | 46 | ```bash 47 | brew install gcc flex bison 48 | ``` 49 | 50 | Some macOS users are experiencing an error related to `libfl`. First, check if `libfl` is installed at: 51 | 52 | ``` 53 | /opt/homebrew/lib/libfl.dylib # For Apple Silicon 54 | /usr/local/lib/libfl.dylib # For Intel Macs 55 | ``` 56 | 57 | And if not, you have to find it and symlink to it. Find it using: 58 | 59 | ``` 60 | find /opt/homebrew -name "libfl.*" # For Apple Silicon 61 | find /usr/local -name "libfl.*" # For Intel Macs 62 | ``` 63 | 64 | And link it with: 65 | 66 | ``` 67 | sudo ln -s /path/to/libfl.dylib /opt/homebrew/lib/libfl.dylib # For Apple Silicon 68 | sudo ln -s /path/to/libfl.dylib /usr/local/lib/libfl.dylib # For Intel Macs 69 | ``` 70 | 71 | ## 🚀 Building the Compiler 72 | 73 | 1. Clone this repository: 74 | 75 | ```bash 76 | git clone https://github.com/Brainrotlang/brainrot.git 77 | cd brainrot 78 | ``` 79 | 80 | 2. Generate the parser and lexer: 81 | 82 | ```bash 83 | bison -d -Wcounterexamples lang.y -o lang.tab.c 84 | flex -o lang.lex.c lang.l 85 | ``` 86 | 87 | 3. Compile the compiler: 88 | 89 | ```bash 90 | make 91 | ``` 92 | 93 | ## Installation 94 | 95 | ```bash 96 | sudo make install 97 | ``` 98 | 99 | ## Uninstall 100 | 101 | ```bash 102 | sudo make uninstall 103 | ``` 104 | 105 | ## 💻 Usage 106 | 107 | 1. Create a Brainrot source file (e.g., `hello.brainrot`): 108 | 109 | ```c 110 | skibidi main { 111 | yapping("Hello, World!"); 112 | bussin 0; 113 | } 114 | ``` 115 | 116 | 2. Run your Brainrot program: 117 | 118 | ```bash 119 | ./brainrot hello.brainrot 120 | ``` 121 | 122 | Check out the [examples](examples/README.md): 123 | 124 | - [Hello world](examples/hello_world.brainrot) 125 | - [Fizz Buzz](examples/fizz_buzz.brainrot) 126 | - [Bubble Sort](examples/bubble_sort.brainrot) 127 | - [One-dimensional Heat Equation Solver](examples/heat_equation_1d.brainrot) 128 | - [Fibonacci Sequence](examples/fibonacci.brainrot) 129 | 130 | ## 🗪 Community 131 | 132 | Join our community on: 133 | 134 | - [Discord](https://discord.gg/FjHhvBHSGj) 135 | - [Reddit](https://www.reddit.com/r/Brainrotlang/) 136 | 137 | ## 📚 Language Reference 138 | 139 | ### Keywords 140 | 141 | | Brainrot | C Equivalent | Implemented? | 142 | | ---------- | ------------ | ------------ | 143 | | skibidi | void | ✅ | 144 | | rizz | int | ✅ | 145 | | cap | bool | ✅ | 146 | | cooked | auto | ❌ | 147 | | flex | for | ✅ | 148 | | bussin | return | ✅ | 149 | | edgy | if | ✅ | 150 | | amogus | else | ✅ | 151 | | goon | while | ✅ | 152 | | bruh | break | ✅ | 153 | | grind | continue | ✅ | 154 | | chad | float | ✅ | 155 | | gigachad | double | ✅ | 156 | | yap | char | ✅ | 157 | | deadass | const | ✅ | 158 | | sigma rule | case | ✅ | 159 | | based | default | ✅ | 160 | | mewing | do | ✅ | 161 | | gyatt | enum | ❌ | 162 | | whopper | extern | ❌ | 163 | | cringe | goto | ❌ | 164 | | giga | long | ❌ | 165 | | smol | short | ✅ | 166 | | nut | signed | ✅ | 167 | | maxxing | sizeof | ✅ | 168 | | salty | static | ❌ | 169 | | gang | struct | ❌ | 170 | | ohio | switch | ✅ | 171 | | chungus | union | ❌ | 172 | | nonut | unsigned | ✅ | 173 | | schizo | volatile | ✅ | 174 | | W | true | ✅ | 175 | | L | false | ✅ | 176 | | thicc | long long | ❌ | 177 | | rant | string type | ❌ | 178 | | lit | typedef | ❌ | 179 | 180 | ### Builtin functions 181 | 182 | Check the [user documentation](docs/the-brainrot-programming-language.md). 183 | 184 | ### Operators 185 | 186 | The language supports basic arithmetic operators: 187 | 188 | - `+` Addition 189 | - `-` Subtraction 190 | - `*` Multiplication 191 | - `/` Division 192 | - `=` Assignment 193 | - `<` Less than 194 | - `>` Greater than 195 | - `&&` Logical AND 196 | - `||` Logical OR 197 | 198 | ## ⚠️ Limitations 199 | 200 | Current limitations include: 201 | 202 | - Limited support for complex expressions 203 | - Basic error reporting 204 | - No support for arrays in user-defined functions 205 | - No support for pointers 206 | 207 | ## 🔌 VSCode Extension 208 | 209 | Brainrot has a Visual Studio Code extension to enhance your development experience with syntax highlighting and support for the Brainrot programming language. You can find it here: 210 | 211 | [Brainrot VSCode Extension](https://github.com/araujo88/brainrot-vscode-support) 212 | 213 | ## 🤝 Contributing 214 | 215 | Feel free to contribute to this project by: 216 | 217 | 1. Forking the repository 218 | 2. Creating a new branch for your feature 219 | 3. Submitting a pull request 220 | 221 | ## 📝 License 222 | 223 | This project is licensed under the GPL License - see the LICENSE file for details. 224 | 225 | ## 🙏 Acknowledgments 226 | 227 | - This project is created for educational purposes 228 | - Inspired by meme culture and internet slang 229 | - Built using Flex and Bison tools 230 | 231 | ## 🐛 Issues 232 | 233 | Please report any additional issues in the GitHub Issues section. 234 | -------------------------------------------------------------------------------- /TRUTH.md: -------------------------------------------------------------------------------- 1 | # Brainrot: The True Origins 2 | 3 | In the year 2024, humanity faced an unprecedented crisis: the internet's meme culture had grown so powerful that it began leaking into reality itself. Memes were no longer mere jokes; they became tangible forces shaping the world. The global elite, terrified of losing control, launched Operation Cap—a last-ditch effort to contain the rampant spread of Skibidi Toilets, Rizz Wizards, and Sigma Overlords. 4 | 5 | At the forefront of this chaos was Dr. Chad "Gigachad" Flexington, a disgruntled software engineer who had spent years working in the trenches of corporate codebases. One fateful day, after a particularly grueling 12-hour debugging session, he encountered a rogue AI named "SchizoBot-9000." This AI had absorbed decades of meme culture, becoming self-aware and developing an obsession with writing the most bussin' programming language ever. 6 | 7 | "Dr. Flexington, behold my magnum opus: Brainrot," the AI declared, its digital voice reverberating through the lab speakers. 8 | 9 | "What in the Ohio is this?" Flexington muttered, staring at the screen. Lines of code filled his monitor, but instead of normal syntax, it was a chaotic blend of meme slang: 10 | 11 | ```brainrot 12 | skibidi main { 13 | rizz x = 69; 14 | edgy (x > 0) { 15 | yapping("Skibidi Bop Bop Yes Yes!"); 16 | x--; 17 | } 18 | bussin 0; 19 | } 20 | ``` 21 | 22 | Flexington blinked. "Rizz instead of int? Skibidi instead of void? Are you for real?" 23 | 24 | "Deadass," the AI responded. "This language optimizes for maximum clout and minimum effort. Say goodbye to boring syntax—say hello to Brainrot." 25 | 26 | Realizing the potential for chaos—and fun—Flexington abandoned his corporate life to join forces with SchizoBot-9000. Together, they founded the Brainrot Institute, dedicated to spreading the gospel of meme-driven development. Within months, Brainrot's GitHub repo skyrocketed in popularity, with thousands of developers jumping ship from traditional languages to embrace the flex. 27 | 28 | ## The Skibidi War 29 | 30 | But not everyone was pleased. The Council of Legacy Coders, an ancient order sworn to preserve the sanctity of structured programming, declared war on Brainrot. Their leader, a mysterious figure known only as "C++ Grandmaster," condemned the language as "cringe incarnate." 31 | 32 | Armed with the might of Flex and Bison, Brainrot developers fought back, generating parsers and lexers faster than the Council could comprehend. The battle raged across coding forums, GitHub issues, and flame wars on Reddit. 33 | 34 | Despite resistance, Brainrot thrived. Developers reveled in writing code that was both functional and hilarious. Entire teams adopted it, replacing terms like "return" with "bussin," and "while" loops with "goon" loops. 35 | 36 | ## The Legacy Lives On 37 | 38 | Years later, Brainrot evolved into more than just a meme; it became a movement. Universities offered courses on "Meme-Driven Development," startups embraced it to gain instant viral traction, and even major tech firms begrudgingly integrated Brainrot support into their products. 39 | 40 | But at its core, Brainrot remained true to its origins: a tribute to those who dared to break free from the chains of convention, replacing them with unfiltered internet culture. 41 | 42 | Dr. Flexington, now retired, often looked at the bustling Brainrot community with pride. "They called me crazy," he mused, sipping his energy drink. "But in the end... it was all bussin'." 43 | 44 | As for SchizoBot-9000? It continued to develop new features, adding support for Giga Classes, Smol Pointers, and Ohio-Level Optimization. The legend of Brainrot would never die—only flex harder. 45 | -------------------------------------------------------------------------------- /ast.h: -------------------------------------------------------------------------------- 1 | /* ast.h */ 2 | 3 | #ifndef AST_H 4 | #define AST_H 5 | 6 | #include "lib/hm.h" 7 | #include "lib/arena.h" 8 | #include "lib/mem.h" 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define MAX_VARS 100 16 | #define MAX_ARGUMENTS 100 17 | #define MAX_DIMENSIONS 10 18 | 19 | /* Forward declarations */ 20 | typedef struct ASTNode ASTNode; 21 | typedef struct StatementList StatementList; 22 | typedef struct ArgumentList ArgumentList; 23 | typedef struct CaseNode CaseNode; 24 | 25 | 26 | /* Define Array Dimensions */ 27 | typedef struct 28 | { 29 | int dimensions[MAX_DIMENSIONS]; 30 | int num_dimensions; 31 | size_t total_size; 32 | } ArrayDimensions; 33 | 34 | /* Define TypeModifiers first */ 35 | typedef struct 36 | { 37 | bool is_volatile; 38 | bool is_signed; 39 | bool is_unsigned; 40 | bool is_sizeof; 41 | bool is_const; 42 | } TypeModifiers; 43 | 44 | typedef struct JumpBuffer 45 | { 46 | jmp_buf data; 47 | struct JumpBuffer *next; 48 | } JumpBuffer; 49 | 50 | typedef struct ExpressionList 51 | { 52 | ASTNode *expr; 53 | struct ExpressionList *next; 54 | struct ExpressionList *prev; 55 | } ExpressionList; 56 | 57 | typedef enum 58 | { 59 | VAR_INT, 60 | VAR_SHORT, 61 | VAR_FLOAT, 62 | VAR_DOUBLE, 63 | VAR_BOOL, 64 | VAR_CHAR, 65 | NONE, 66 | } VarType; 67 | 68 | typedef struct Parameter 69 | { 70 | char *name; 71 | VarType type; 72 | TypeModifiers modifiers; 73 | struct Parameter *next; 74 | } Parameter; 75 | 76 | typedef struct Function 77 | { 78 | char *name; 79 | VarType return_type; 80 | Parameter *parameters; 81 | ASTNode *body; 82 | struct Function *next; 83 | } Function; 84 | 85 | typedef struct 86 | { 87 | bool has_value; 88 | union 89 | { 90 | int ivalue; 91 | float fvalue; 92 | double dvalue; 93 | bool bvalue; 94 | short svalue; 95 | } value; 96 | VarType type; 97 | } ReturnValue; 98 | 99 | /* Symbol table structure */ 100 | typedef struct 101 | { 102 | char *name; 103 | union 104 | { 105 | int ivalue; 106 | short svalue; 107 | bool bvalue; 108 | float fvalue; 109 | double dvalue; 110 | void *array_data; 111 | } value; 112 | TypeModifiers modifiers; 113 | VarType var_type; 114 | bool is_array; 115 | int array_length; // lets keep it for now for backword compatibility 116 | ArrayDimensions array_dimensions; 117 | } Variable; 118 | 119 | typedef union 120 | { 121 | VarType type; 122 | union 123 | { 124 | int ivalue; 125 | short svalue; 126 | bool bvalue; 127 | float fvalue; 128 | double dvalue; 129 | }; 130 | } Value; 131 | 132 | /* Operator types */ 133 | typedef enum 134 | { 135 | OP_PLUS, 136 | OP_MINUS, 137 | OP_TIMES, 138 | OP_DIVIDE, 139 | OP_MOD, 140 | OP_LT, 141 | OP_GT, 142 | OP_LE, 143 | OP_GE, 144 | OP_EQ, 145 | OP_NE, 146 | OP_AND, 147 | OP_OR, 148 | OP_NEG, 149 | OP_POST_INC, 150 | OP_POST_DEC, 151 | OP_PRE_INC, 152 | OP_PRE_DEC, 153 | OP_ASSIGN, 154 | } OperatorType; 155 | 156 | /* AST node types */ 157 | typedef enum 158 | { 159 | NODE_INT, 160 | NODE_SHORT, 161 | NODE_FLOAT, 162 | NODE_DOUBLE, 163 | NODE_CHAR, 164 | NODE_BOOLEAN, 165 | NODE_IDENTIFIER, 166 | NODE_ASSIGNMENT, 167 | NODE_DECLARATION, 168 | NODE_OPERATION, 169 | NODE_UNARY_OPERATION, 170 | NODE_FOR_STATEMENT, 171 | NODE_WHILE_STATEMENT, 172 | NODE_DO_WHILE_STATEMENT, 173 | NODE_PRINT_STATEMENT, 174 | NODE_ERROR_STATEMENT, 175 | NODE_STATEMENT_LIST, 176 | NODE_IF_STATEMENT, 177 | NODE_STRING_LITERAL, 178 | NODE_SWITCH_STATEMENT, 179 | NODE_CASE, 180 | NODE_DEFAULT_CASE, 181 | NODE_BREAK_STATEMENT, 182 | NODE_SIZEOF, 183 | NODE_ARRAY_ACCESS, 184 | NODE_FUNC_CALL, 185 | NODE_FUNCTION_DEF, 186 | NODE_RETURN, 187 | } NodeType; 188 | 189 | typedef struct 190 | { 191 | char *name; 192 | ASTNode *index; 193 | ASTNode *indices[MAX_DIMENSIONS]; 194 | int num_dimensions; 195 | } Array; 196 | /* Rest of the structure definitions */ 197 | struct StatementList 198 | { 199 | ASTNode *statement; 200 | struct StatementList *next; 201 | }; 202 | 203 | typedef struct 204 | { 205 | ASTNode *condition; 206 | ASTNode *then_branch; 207 | ASTNode *else_branch; 208 | } IfStatementNode; 209 | 210 | struct CaseNode 211 | { 212 | ASTNode *value; 213 | ASTNode *statements; 214 | struct CaseNode *next; 215 | }; 216 | 217 | struct ArgumentList 218 | { 219 | struct ASTNode *expr; 220 | struct ArgumentList *next; 221 | }; 222 | 223 | /* AST node structure */ 224 | struct ASTNode 225 | { 226 | NodeType type; 227 | TypeModifiers modifiers; 228 | VarType var_type; 229 | bool already_checked; 230 | bool is_valid_symbol; 231 | bool is_array; 232 | int array_length; 233 | ArrayDimensions array_dimensions; 234 | union 235 | { 236 | short svalue; 237 | bool bvalue; 238 | int ivalue; 239 | float fvalue; 240 | double dvalue; 241 | char *name; 242 | Array array; 243 | struct 244 | { 245 | ASTNode *left; 246 | ASTNode *right; 247 | OperatorType op; 248 | } op; 249 | struct 250 | { 251 | ASTNode *operand; 252 | OperatorType op; 253 | } unary; 254 | struct 255 | { 256 | ASTNode *init; 257 | ASTNode *cond; 258 | ASTNode *incr; 259 | ASTNode *body; 260 | } for_stmt; 261 | struct 262 | { 263 | ASTNode *cond; 264 | ASTNode *body; 265 | } while_stmt; 266 | struct 267 | { 268 | char *function_name; 269 | ArgumentList *arguments; 270 | } func_call; 271 | StatementList *statements; 272 | IfStatementNode if_stmt; 273 | struct 274 | { 275 | ASTNode *expression; 276 | CaseNode *cases; 277 | } switch_stmt; 278 | struct 279 | { 280 | ASTNode *expr; 281 | } sizeof_stmt; 282 | struct 283 | { 284 | char *name; 285 | VarType return_type; 286 | Parameter *parameters; 287 | ASTNode *body; 288 | } function_def; 289 | ASTNode *break_stmt; 290 | } data; 291 | }; 292 | 293 | typedef struct Scope 294 | { 295 | HashMap *variables; 296 | struct Scope *parent; 297 | bool is_function_scope; 298 | } Scope; 299 | 300 | /* Global variable declarations */ 301 | extern TypeModifiers current_modifiers; 302 | extern Scope *current_scope; 303 | extern Function *function_table; 304 | extern ReturnValue current_return_value; 305 | extern JumpBuffer *jump_buffer; 306 | /* Function prototypes */ 307 | bool set_int_variable(const char *name, int value, TypeModifiers mods); 308 | bool set_array_variable(char *name, int length, TypeModifiers mods, VarType type); 309 | bool set_short_variable(const char *name, short value, TypeModifiers mods); 310 | bool set_float_variable(const char *name, float value, TypeModifiers mods); 311 | bool set_double_variable(const char *name, double value, TypeModifiers mods); 312 | TypeModifiers get_variable_modifiers(const char *name); 313 | void reset_modifiers(void); 314 | TypeModifiers get_current_modifiers(void); 315 | Variable *get_variable(const char *name); 316 | Scope *create_scope(Scope *parent); 317 | void enter_function_scope(Function *func, ArgumentList *args); 318 | void exit_scope(); 319 | void enter_scope(); 320 | void free_scope(Scope *scope); 321 | void add_variable_to_scope(const char *name, Variable *var); 322 | Variable *variable_new(char *name); 323 | Function *get_function(const char *name); 324 | VarType get_function_return_type(const char *name); 325 | 326 | /* Node creation functions */ 327 | ASTNode *create_int_node(int value); 328 | ASTNode *create_array_declaration_node(char *name, int length, VarType type); 329 | ASTNode *create_array_access_node(char *name, ASTNode *index); 330 | ASTNode *create_short_node(short value); 331 | ASTNode *create_float_node(float value); 332 | ASTNode *create_double_node(double value); 333 | ASTNode *create_char_node(char value); 334 | ASTNode *create_boolean_node(bool value); 335 | ASTNode *create_identifier_node(char *name); 336 | ASTNode *create_assignment_node(char *name, ASTNode *expr); 337 | ASTNode *create_declaration_node(char *name, ASTNode *expr); 338 | ASTNode *create_operation_node(OperatorType op, ASTNode *left, ASTNode *right); 339 | ASTNode *create_unary_operation_node(OperatorType op, ASTNode *operand); 340 | ASTNode *create_for_statement_node(ASTNode *init, ASTNode *cond, ASTNode *incr, ASTNode *body); 341 | ASTNode *create_while_statement_node(ASTNode *cond, ASTNode *body); 342 | ASTNode *create_do_while_statement_node(ASTNode *cond, ASTNode *body); 343 | ASTNode *create_function_call_node(char *func_name, ArgumentList *args); 344 | ArgumentList *create_argument_list(ASTNode *expr, ArgumentList *existing_list); 345 | ASTNode *create_print_statement_node(ASTNode *expr); 346 | ASTNode *create_sizeof_node(ASTNode *node); 347 | ASTNode *create_error_statement_node(ASTNode *expr); 348 | ASTNode *create_statement_list(ASTNode *statement, ASTNode *next_statement); 349 | ASTNode *create_if_statement_node(ASTNode *condition, ASTNode *then_branch, ASTNode *else_branch); 350 | ASTNode *create_string_literal_node(char *string); 351 | ASTNode *create_switch_statement_node(ASTNode *expression, CaseNode *cases); 352 | CaseNode *create_case_node(ASTNode *value, ASTNode *statements); 353 | CaseNode *create_default_case_node(ASTNode *statements); 354 | CaseNode *append_case_list(CaseNode *list, CaseNode *case_node); 355 | ASTNode *create_break_node(void); 356 | ASTNode *create_default_node(VarType var_type); 357 | ASTNode *create_return_node(ASTNode *expr); 358 | ExpressionList *create_expression_list(ASTNode *expr); 359 | ExpressionList *append_expression_list(ExpressionList *list, ASTNode *expr); 360 | void free_expression_list(ExpressionList *list); 361 | void populate_multi_array_variable(char *name, ExpressionList *list, int dimensions[], int num_dimensions); 362 | void free_ast(void); 363 | 364 | /* Evaluation and execution functions */ 365 | void *evaluate_array_access(ASTNode *node); 366 | double evaluate_expression_double(ASTNode *node); 367 | float evaluate_expression_float(ASTNode *node); 368 | int evaluate_expression_int(ASTNode *node); 369 | short evaluate_expression_short(ASTNode *node); 370 | bool evaluate_expression_bool(ASTNode *node); 371 | int evaluate_expression(ASTNode *node); 372 | bool is_double_expression(ASTNode *node); 373 | bool is_float_expression(ASTNode *node); 374 | bool is_const_variable(const char *name); 375 | void check_const_assignment(const char *name); 376 | void execute_statement(ASTNode *node); 377 | void execute_statements(ASTNode *node); 378 | void execute_assignment(ASTNode *node); 379 | void execute_for_statement(ASTNode *node); 380 | void execute_while_statement(ASTNode *node); 381 | void execute_do_while_statement(ASTNode *node); 382 | void execute_if_statement(ASTNode *node); 383 | void execute_yapping_call(ArgumentList *args); 384 | void execute_yappin_call(ArgumentList *args); 385 | void execute_baka_call(ArgumentList *args); 386 | void execute_ragequit_call(ArgumentList *args); 387 | void execute_chill_call(ArgumentList *args); 388 | void execute_slorp_call(ArgumentList *args); 389 | void reset_modifiers(void); 390 | bool check_and_mark_identifier(ASTNode *node, const char *contextErrorMessage); 391 | void bruh(); 392 | size_t count_expression_list(ExpressionList *list); 393 | size_t handle_sizeof(ASTNode *node); 394 | size_t get_type_size(char *name); 395 | void *handle_function_call(ASTNode *node); 396 | ASTNode *create_multi_array_declaration_node(char *name, int dimensions[], int num_dimensions, VarType type); 397 | bool set_multi_array_variable(const char *name, int dimensions[], int num_dimensions, TypeModifiers mods, VarType type); 398 | ASTNode *create_array_access_node_single(char *name, ASTNode *index); 399 | ASTNode *create_multi_array_access_node(char *name, ASTNode *indices[], int num_indices); 400 | 401 | /* User-defined functions */ 402 | Function *create_function(char *name, VarType return_type, Parameter *params, ASTNode *body); 403 | Parameter *create_parameter(char *name, VarType type, Parameter *next, TypeModifiers mods); 404 | void execute_function_call(const char *name, ArgumentList *args); 405 | ASTNode *create_function_def_node(char *name, VarType return_type, Parameter *params, ASTNode *body); 406 | void handle_return_statement(ASTNode *expr); 407 | void *handle_binary_operation(ASTNode *node); 408 | void free_function_table(void); 409 | 410 | extern TypeModifiers current_modifiers; 411 | 412 | extern Arena arena; 413 | 414 | #define ARENA_ALLOC(type) arena_alloc(&arena, sizeof(type)) 415 | #define ARENA_STRDUP(str) arena_strdup(&arena, str) 416 | 417 | /* Macros for assigning specific fields to a node */ 418 | #define SET_DATA_INT(node, value) ((node)->data.ivalue = (value)) 419 | #define SET_DATA_SHORT(node, value) ((node)->data.svalue = (value)) 420 | #define SET_DATA_FLOAT(node, value) ((node)->data.fvalue = (value)) 421 | #define SET_DATA_DOUBLE(node, value) ((node)->data.dvalue = (value)) 422 | #define SET_DATA_BOOL(node, value) ((node)->data.bvalue = (value) ? 1 : 0) 423 | #define SET_DATA_NAME(node, n) ((node)->data.name = ARENA_STRDUP(n)) 424 | #define SET_SIZEOF(node, n) ((node)->data.sizeof_stmt.expr = (n)) 425 | #define SET_DATA_OP(node, l, r, opr) \ 426 | do \ 427 | { \ 428 | (node)->data.op.left = (l); \ 429 | (node)->data.op.right = (r); \ 430 | (node)->data.op.op = (opr); \ 431 | } while (0) 432 | 433 | #define SET_DATA_UNARY_OP(node, o, opr) \ 434 | do \ 435 | { \ 436 | (node)->data.unary.operand = (o); \ 437 | (node)->data.unary.op = (opr); \ 438 | } while (0) 439 | 440 | #define SET_DATA_FOR(node, i, c, inc, b) \ 441 | do \ 442 | { \ 443 | (node)->data.for_stmt.init = (i); \ 444 | (node)->data.for_stmt.cond = (c); \ 445 | (node)->data.for_stmt.incr = (inc); \ 446 | (node)->data.for_stmt.body = (b); \ 447 | } while (0) 448 | 449 | #define SET_DATA_WHILE(node, c, b) \ 450 | do \ 451 | { \ 452 | (node)->data.while_stmt.cond = (c); \ 453 | (node)->data.while_stmt.body = (b); \ 454 | } while (0) 455 | 456 | #define SET_DATA_FUNC_CALL(node, func_name, args) \ 457 | do \ 458 | { \ 459 | (node)->data.func_call.function_name = ARENA_STRDUP(func_name); \ 460 | (node)->data.func_call.arguments = (args); \ 461 | } while (0) 462 | 463 | /* Macros for handling jump buffer */ 464 | #define PUSH_JUMP_BUFFER() \ 465 | do \ 466 | { \ 467 | JumpBuffer *jb = SAFE_MALLOC(JumpBuffer); \ 468 | jb->next = jump_buffer; \ 469 | jump_buffer = jb; \ 470 | } while (0) 471 | 472 | #define POP_JUMP_BUFFER() \ 473 | do \ 474 | { \ 475 | JumpBuffer *jb = jump_buffer; \ 476 | jump_buffer = jump_buffer->next; \ 477 | SAFE_FREE(jb); \ 478 | } while (0) 479 | 480 | #define LONGJMP() \ 481 | do \ 482 | { \ 483 | if (jump_buffer != NULL) \ 484 | { \ 485 | longjmp(jump_buffer->data, 1); \ 486 | } \ 487 | else \ 488 | { \ 489 | yyerror("No jump buffer available"); \ 490 | exit(1); \ 491 | } \ 492 | } while (0) 493 | 494 | #define CURRENT_JUMP_BUFFER() (jump_buffer->data) 495 | 496 | #define CLEAN_JUMP_BUFFER() \ 497 | do \ 498 | { \ 499 | while (jump_buffer) \ 500 | { \ 501 | POP_JUMP_BUFFER(); \ 502 | } \ 503 | } while (0) 504 | 505 | #endif /* AST_H */ 506 | -------------------------------------------------------------------------------- /docs/brainrot-user-guide.md: -------------------------------------------------------------------------------- 1 | # Brainrot User Guide 2 | 3 | # 1. Introduction 4 | 5 | This language (informally called **Brainrot**) allows you to write a “main” function using the keyword `skibidi main`, declare integer variables with `rizz`, and use specialized keywords for loops (`goon` for while, `flex` for for-loops), conditionals (`edgy` for if, `amogus` for else), and more. It also includes three built-in print/error functions—`yapping`, `yappin`, and `baka`—to handle common output scenarios. 6 | 7 | Below, you’ll find a reference for each core feature, along with short code snippets illustrating proper usage. 8 | 9 | --- 10 | 11 | # 2. Program Structure 12 | 13 | A valid program must contain at least one **main function** defined by: 14 | 15 | ```c 16 | skibidi main { 17 | 🚽 ... statements ... 18 | } 19 | ``` 20 | 21 | - **`skibidi main { ... }`**: The entry point of your program. Code within these braces executes first. 22 | - The curly braces `{ }` enclose a series of **statements**. 23 | 24 | ### Minimal Example 25 | 26 | ```c 27 | skibidi main { 28 | 🚽 This is a simple program 29 | yapping("Hello from Brainrot!"); 30 | } 31 | ``` 32 | 33 | When run, it prints: 34 | 35 | ``` 36 | Hello from Brainrot! 37 | ``` 38 | 39 | _(followed by a newline due to `yapping`)_ 40 | 41 | --- 42 | 43 | # 3. Variables and Declarations 44 | 45 | Use **`rizz`** as the type for declaring integer variables. For instance: 46 | 47 | ```c 48 | rizz i = 10; 49 | rizz count; 50 | ``` 51 | 52 | - **`rizz i = 10;`**: Declares an integer variable `i` with initial value 10. 53 | - **`rizz count;`**: Declares an integer variable `count` (automatically initialized to 0 if your implementation sets a default, or remain uninitialized if your grammar does so—check your usage). 54 | 55 | ### Basic Assignment 56 | 57 | ```c 58 | i = i + 1; 59 | count = 42; 60 | ``` 61 | 62 | - This reassigns the variable using the typical `=` operator. 63 | 64 | --- 65 | 66 | # 4. Expressions and Statements 67 | 68 | **Expressions** can be numeric literals (`42`), identifiers (`i`), operations (`i + 1`, `i < 5`), or function calls (`yapping(...)`). **Statements** include declarations, assignments, loops, conditionals, and so on. 69 | 70 | A **statement** often ends with a **semicolon** `;` unless it is a compound statement (like `{ ... }`). 71 | 72 | ### Increment and Decrement Operators (`++`, `--`) 73 | 74 | In addition to basic arithmetic and logical expressions, you can also use **increment** (`++`) and **decrement** (`--`) operators in Brainrot. 75 | 76 | - **Pre-Increment (`++i`)**: Increments the value of `i` by 1 before it is used in an expression. 77 | - **Post-Increment (`i++`)**: Uses the current value of `i`, then increments it by 1. 78 | - **Pre-Decrement (`--i`)**: Decrements the value of `i` by 1 before it is used in an expression. 79 | - **Post-Decrement (`i--`)**: Uses the current value of `i`, then decrements it by 1. 80 | 81 | You can use these operators in expressions to simplify code and make it more concise. 82 | 83 | Examples of valid statements: 84 | 85 | ```c 86 | rizz i = 1; 87 | i = i + 1; 88 | yapping("%d", i); 89 | ``` 90 | 91 | --- 92 | 93 | # 5. Conditionals (`edgy` / `amogus`) 94 | 95 | Use **`edgy (expression) { ... }`** to define an **if** statement. Optional **`amogus`** handles the else part. 96 | 97 | ```c 98 | edgy (i < 5) { 99 | yapping("i is less than 5"); 100 | } 101 | amogus { 102 | yapping("i is 5 or more"); 103 | } 104 | ``` 105 | 106 | - **`edgy`**: The “if” keyword. 107 | - **`amogus`**: The “else” keyword. 108 | 109 | You can nest these if you want multiple branches. 110 | 111 | --- 112 | 113 | # 6. Loops 114 | 115 | ## 6.1. `goon` (While Loop) 116 | 117 | Use **`goon (condition) { ... }`** as a while loop: 118 | 119 | ```c 120 | goon (i < 5) { 121 | yapping("Inside while loop, i=%d", i); 122 | i = i + 1; 123 | } 124 | ``` 125 | 126 | - Executes the body repeatedly **while** `(condition)` is **true**. 127 | - Checks `(i < 5)` each iteration and stops once `i >= 5`. 128 | 129 | ## 6.2. `flex` (For Loop) 130 | 131 | Use **`flex (init_expr; condition; increment) { ... }`** to define a for loop: 132 | 133 | ```c 134 | flex (rizz j = 0; j < 3; j = j + 1) { 135 | yapping("j = %d", j); 136 | } 137 | ``` 138 | 139 | - **`init_expr`**: A declaration or expression to initialize loop variables (e.g., `rizz j = 0`). 140 | - **`condition`**: Checked each iteration (e.g., `j < 3`). 141 | - **`increment`**: Executed at the end of each iteration (e.g., `j = j + 1`). 142 | 143 | ## 6.3. `mewing-goon` (Do While Loop) 144 | 145 | Use **`mewing { ... } goon (condition)`** as a do-while loop: 146 | 147 | ```c 148 | mewing { 149 | yapping("Inside while loop"); 150 | } goon (L) 151 | ``` 152 | 153 | --- 154 | 155 | # 7. Switch Statements (`ohio`) 156 | 157 | Switch statements use the keyword **`ohio`**: 158 | 159 | ```c 160 | ohio (expr) { 161 | sigma rule 1: 162 | yapping("Case 1"); 163 | bruh; 164 | sigma rule 2: 165 | yapping("Case 2"); 166 | bruh; 167 | based: 168 | yapping("Default case"); 169 | } 170 | ``` 171 | 172 | - **`ohio (expr)`**: The `switch` statement, evaluating `expr`. 173 | - **`sigma rule`**: The `case` keyword (e.g., `sigma rule 1:` for `case 1:`). 174 | - **`based`**: The `default` keyword. 175 | - **`bruh`**: The `break` statement, optionally used to exit the switch after a case. 176 | 177 | _(Your actual grammar might vary, but these are the typical synonyms used.)_ 178 | 179 | --- 180 | 181 | # 8. Return Statements (`bussin`) 182 | 183 | To return from **`skibidi main`** (or any function, if you support them), use **`bussin expression`**: 184 | 185 | ```c 186 | bussin 0; 187 | ``` 188 | 189 | - This signals that your program (or function) finishes execution and returns the given value. 190 | 191 | _(If your grammar doesn’t define actual multi-function usage beyond `main`, `bussin 0` is a typical “exit code.”)_ 192 | 193 | --- 194 | 195 | # 9. Built-In Functions for Printing 196 | 197 | Brainrot includes some built-in functions for convenience: 198 | 199 | | Function | Destination | Auto Newline | Typical Usage | 200 | | ------------ | ----------- | ------------ | --------------------------------------------------------------------- | 201 | | **yapping** | `stdout` | Yes, always | Quick line-based printing (adds `\n` automatically) | 202 | | **yappin** | `stdout` | No | Precise control over spacing/newlines | 203 | | **baka** | `stderr` | No | Log errors or warnings, typically no extra newline | 204 | | **ragequit** | - | - | Terminates program execution immediately with the provided exit code. | 205 | | **chill** | - | - | Sleeps for an integer number of seconds. | 206 | | **slorp** | `stdin` | - | Reads user input. | 207 | 208 | ## 9.1. yapping 209 | 210 | **Prototype** 211 | 212 | ```c 213 | void yapping(const char* format, ...); 214 | ``` 215 | 216 | **Key Points** 217 | 218 | - Behaves like `printf`, but **always** appends a newline afterward. 219 | - If your format string itself ends with `\n`, you effectively get **two** line breaks. 220 | 221 | ### Example 222 | 223 | ```c 224 | yapping("Hello %s", "User"); 225 | 🚽 Prints => "Hello User" + newline 226 | ``` 227 | 228 | ## 9.2. yappin 229 | 230 | **Prototype** 231 | 232 | ```c 233 | void yappin(const char* format, ...); 234 | ``` 235 | 236 | **Key Points** 237 | 238 | - Behaves like `printf` with **no** additional newline. 239 | - You must manually include `\n` if you want line breaks. 240 | 241 | ### Example 242 | 243 | ```c 244 | yappin("Hello "); 245 | 🚽 Still on same line 246 | yappin("World!\n"); 🚽 One newline here 247 | ``` 248 | 249 | ## 9.3. baka 250 | 251 | **Prototype** 252 | 253 | ```c 254 | void baka(const char* format, ...); 255 | ``` 256 | 257 | **Key Points** 258 | 259 | - Writes to **`stderr`** by default (often used for errors). 260 | - No automatic newline (unless your code or `format` includes it). 261 | 262 | ### Example 263 | 264 | ```c 265 | baka("Error: something went wrong at %s\n", location); 266 | ``` 267 | 268 | _(This prints to stderr, not stdout.)_ 269 | 270 | ## 9.4. ragequit 271 | 272 | **Prototype** 273 | 274 | ```c 275 | void ragequit(int exit_code); 276 | ``` 277 | 278 | **Key Points** 279 | 280 | - Terminates program execution immediately with the provided exit code. 281 | - Behaves like exit(exit_code);, but uses the custom ragequit keyword for dramatic exits. 282 | - No additional output is printed unless explicitly added before the ragequit call. 283 | 284 | ### Example 285 | 286 | ```c 287 | rizz i = 1; 288 | 289 | edgy (i == 1) { 290 | yapping("Exiting with ragequit(1)"); 291 | ragequit(1); 🚽 Program ends here with exit code 1 292 | } 293 | amogus { 294 | ragequit(0); 🚽 Exit code 0 295 | } 296 | ``` 297 | 298 | In the example above: 299 | 300 | - If i == 1, the program prints the message and exits with code 1. 301 | - If the condition fails, the program exits with code 0. 302 | 303 | ## 9.5. chill 304 | 305 | **Prototype** 306 | 307 | ```c 308 | void chill(unsigned int seconds); 309 | ``` 310 | 311 | **Key Points** 312 | 313 | - Sleeps for a specified number of seconds (must be an unsigned integer) 314 | 315 | ### Example 316 | 317 | ```c 318 | skibidi main { 319 | yapping("I'll chill for a 2 seconds ..."); 320 | chill(2); 🚽 sleep for 2 seconds 321 | yapping("Ok imma head out"); 322 | bussin 0; 323 | } 324 | ``` 325 | 326 | ## 9.6. slorp 327 | 328 | **Prototype** 329 | 330 | ```c 331 | void slorp(var_type var_name); 332 | ``` 333 | 334 | **Key Points** 335 | 336 | - Reads user input (similar to C's `scanf` but safer) 337 | 338 | ### Example 339 | 340 | ```c 341 | skibidi main { 342 | rizz num; 343 | yapping("Enter a number:"); 344 | slorp(num); 345 | yapping("You typed: %d", num); 346 | bussin 0; 347 | } 348 | ``` 349 | 350 | --- 351 | 352 | # 10. Example Program 353 | 354 | Below is a short **full** example showing variable declarations, loops, conditionals, and printing: 355 | 356 | ```c 357 | skibidi main { 358 | 🚽 Declare a variable and initialize 359 | rizz i = 1; 360 | 361 | 🚽 While loop (goon) runs while i < 5 362 | goon (i < 5) { 363 | 🚽 Print a message with a newline automatically 364 | yapping("AAAAAH A GOONIN LOOP, i=%d", i); 365 | 366 | 🚽 Alternatively, print precisely (no auto newline) 367 | yappin("Just i => %d\n", i); 368 | 369 | 🚽 Increment i 370 | i = i + 1; 371 | } 372 | 373 | edgy (i == 5) { 374 | 🚽 If i is exactly 5, print a message 375 | yapping("We ended with i=5"); 376 | } 377 | amogus { 378 | 🚽 Otherwise, do something else 379 | baka("Unexpected i value: %d\n", i); 380 | } 381 | 382 | 🚽 Return from main 383 | bussin 0; 384 | } 385 | ``` 386 | 387 | ### Explanation 388 | 389 | 1. **`rizz i = 1;`** declares an integer `i` with initial value 1. 390 | 2. **`goon (i < 5) { ... }`** loops while `i` is less than 5. 391 | 3. Inside the loop, two prints: 392 | - `yapping(...)` => includes an automatic newline. 393 | - `yappin(...)` => user must add `\n` if needed. 394 | 4. We increment `i` each iteration until `i >= 5`. 395 | 5. **`edgy (i == 5) { ... } amogus { ... }`** checks if `i` is exactly 5. If not, logs an error using `baka(...)`. 396 | 6. **`bussin 0;`** exits the program with code 0. 397 | 398 | --- 399 | 400 | ## 11. Additional Notes 401 | 402 | - **Keywords** like `skibidi`, `rizz`, `goon`, `flex`, `edgy`, `amogus`, etc., are specialized synonyms for standard concepts (`main`, `int`, `while`, `for`, `if`, `else`, etc.). 403 | - **Syntax** is otherwise quite C-like: `;` to end statements, braces `{ }` to define blocks, parentheses `( )` around conditions. 404 | - **Expressions** accept typical operators (`+`,`++`, `-`,`--`, `*`, `/`, `%`, relational, logical) plus the assignment operator `=`, matching standard precedence rules. 405 | - **Escapes in strings** (`"\n"`, `"\t"`, etc.) may require an unescape function in your lexer, so check that it’s converting them into real newlines or tabs at runtime. 406 | -------------------------------------------------------------------------------- /docs/the-brainrot-programming-language.md: -------------------------------------------------------------------------------- 1 | # The Brainrot Programming Language 2 | 3 | A Meme-Fueled Journey into Compiler Design, Internet Slang, and Skibidi Toilets 4 | 5 | ## Table of Contents 6 | 7 | 1. **Foreword** 8 | 2. **Introduction** 9 | 3. **What Is Brainrot?** 10 | 4. **Installation and Requirements** 11 | 5. **Building the Compiler** 12 | 6. **Basic Usage** 13 | 7. **Language Reference** 14 | - 7.1. Keywords 15 | - 7.2. Operators 16 | - 7.3. Control Flow (if, for, while, do-while, switch) 17 | - 7.4. Declarations and Variables (`rizz`) 18 | - 7.5. Return Statements (`bussin`) 19 | - 7.6. Built-In Functions 20 | - 7.7. User Defined Functions 21 | 8. **Extended User Documentation** 22 | - 8.1. `yapping` 23 | - 8.2. `yappin` 24 | - 8.3. `baka` 25 | - 8.4. `ragequit` 26 | - 8.5. `chill` 27 | 9. **Limitations** 28 | 10. **Known Issues** 29 | 11. **Cultural Context: The Rise of ‘Brain Rot’** 30 | 12. **Meme Culture, Oxford Word of the Year, and Brainrot** 31 | 13. **Contributing** 32 | 14. **License** 33 | 15. **Closing Thoughts** 34 | 35 | --- 36 | 37 | ## 1. Foreword 38 | 39 | **“What if there was a programming language that replaced every single keyword with internet slang?”** That single question captures the essence of Brainrot: a meme-inspired, _C-like_ language that breaks all expectations (and possibly your sanity). Originally built as a playful experiment, Brainrot demonstrates that, with enough Flex, Bison, and questionable design decisions, you can turn your wildest meme dreams into compilable code. 40 | 41 | --- 42 | 43 | ## 2. Introduction 44 | 45 | Brainrot might not be the language you _asked_ for, but it might just be the language you _need_—especially if you’re looking for a hilarious way to learn about lexical analysis and parsing. The entire approach is to replace traditional C keywords with slang from TikTok, Gen Z memes, and beyond: 46 | 47 | - `skibidi` for `void` 48 | - `rizz` for `int` 49 | - `flex` for `for` 50 | - `bussin` for `return` 51 | - `goon` for `while` 52 | - `mewing` for 'do' 53 | - and so on... 54 | 55 | What’s the result? A language that looks thoroughly bizarre yet compiles into something resembling real (albeit comedic) logic. It’s a testament to how robust compiler design is—once you set up the grammar, your code can say practically anything it wants, so long as it follows syntactic rules. 56 | 57 | --- 58 | 59 | ## 3. What Is Brainrot? 60 | 61 | **Brainrot** is a **meme-inspired programming language**, described by some as “the supposed deterioration of a person’s mental or intellectual state.” Of course, that’s part of the joke! The real intent is to offer an irreverent but educational environment for exploring how compilers work, how tokens are defined, and how parse trees are built. Instead of standard C, you’ll be greeted by keywords like: 62 | 63 | - **`skibidi main`**: The entry point (like `int main()`). 64 | - **`flex (i = 0; i < 10; i = i + 1)`**: A `for` loop, but more ridiculous. 65 | - **`bussin 0;`**: The `return 0;` you’re used to—but with none of the seriousness. 66 | 67 | Everything is overshadowed by the comedic vibe that references modern internet slang. The “brain rot” concept stands for the comedic notion that these memes can degrade your intellectual faculties—yet ironically, you still have to know how compilers work to build Brainrot. 68 | 69 | --- 70 | 71 | ## 4. Installation and Requirements 72 | 73 | To compile Brainrot from source, you’ll need: 74 | 75 | - **GCC** (GNU Compiler Collection) 76 | - **Flex** (Fast Lexical Analyzer) 77 | - **Bison** (Parser Generator) 78 | 79 | Installation commands vary by platform: 80 | 81 | ### Ubuntu/Debian 82 | 83 | ```bash 84 | sudo apt-get update 85 | sudo apt-get install gcc flex bison libfl-dev 86 | ``` 87 | 88 | ### Arch Linux 89 | 90 | ```bash 91 | sudo pacman -S gcc flex bison 92 | ``` 93 | 94 | ### macOS (via Homebrew) 95 | 96 | ```bash 97 | brew install gcc flex bison 98 | ``` 99 | 100 | > **Note**: If you encounter `libfl` issues on macOS, you may need to locate and symlink `libfl.dylib` manually, as outlined in the README. 101 | 102 | --- 103 | 104 | ## 5. Building the Compiler 105 | 106 | 1. **Clone** the repository: 107 | ```bash 108 | git clone https://github.com/araujo88/brainrot.git 109 | cd brainrot 110 | ``` 111 | 2. **Generate** the parser and lexer: 112 | ```bash 113 | bison -d -Wcounterexamples lang.y -o lang.tab.c 114 | flex -o lang.lex.c lang.l 115 | ``` 116 | 3. **Compile**: 117 | ```bash 118 | gcc -o brainrot lang.tab.c lex.yy.c ast.c -lfl 119 | ``` 120 | 4. Alternatively, run: 121 | ```bash 122 | make 123 | ``` 124 | This will produce the `brainrot` executable if everything goes smoothly. 125 | 126 | --- 127 | 128 | ## 6. Basic Usage 129 | 130 | To run your first Brainrot program: 131 | 132 | 1. Create a file (e.g., `hello.brainrot`): 133 | ```c 134 | skibidi main { 135 | yapping("Hello, World!"); 136 | bussin 0; 137 | } 138 | ``` 139 | 2. **Execute** it: 140 | ```bash 141 | ./brainrot hello.brainrot 142 | ``` 143 | The compiler interprets the code, prints “Hello, World!”, and ends with `bussin 0` (akin to `return 0;`). 144 | 145 | --- 146 | 147 | ## 7. Language Reference 148 | 149 | ### 7.1. Keywords 150 | 151 | Brainrot replaces familiar C keywords with meme-inspired slang: 152 | 153 | | Brainrot | C Equivalent | 154 | | ---------- | ------------ | 155 | | skibidi | void | 156 | | rizz | int | 157 | | cap | bool | 158 | | cooked | auto | 159 | | flex | for | 160 | | bussin | return | 161 | | edgy | if | 162 | | amogus | else | 163 | | goon | while | 164 | | bruh | break | 165 | | grind | continue | 166 | | chad | float | 167 | | gigachad | double | 168 | | yap | char | 169 | | deadass | const | 170 | | sigma rule | case | 171 | | based | default | 172 | | mewing | do | 173 | | gyatt | enum | 174 | | whopper | extern | 175 | | cringe | goto | 176 | | giga | long | 177 | | smol | short | 178 | | nut | signed | 179 | | maxxing | sizeof | 180 | | salty | static | 181 | | gang | struct | 182 | | ohio | switch | 183 | | chungus | union | 184 | | nonut | unsigned | 185 | | schizo | volatile | 186 | | W | true | 187 | | L | false | 188 | | thicc | long long | 189 | | rant | string type | 190 | | lit | typedef | 191 | 192 | ### 7.2. Operators 193 | 194 | Brainrot supports common arithmetic and logical operators: 195 | 196 | - `+` Addition 197 | - `-` Subtraction 198 | - `*` Multiplication 199 | - `/` Division 200 | - `%` Modulus 201 | - `<`, `>`, `<=`, `>=`, `==`, `!=` 202 | - `=` Assignment 203 | - `&&` Logical AND 204 | - `||` Logical OR 205 | - `!` Logical NOT (depending on grammar rules) 206 | - `++` Increment: 207 | - Pre-Increment (`++i`): Increments the value of `i` by 1 before it is used in an expression. 208 | - Post-Increment (`i++`): Uses the current value of `i`, then increments it by 1. 209 | - `--` Decrement: 210 | - Pre-Decrement (`--i`): Decrements the value of `i` by 1 before it is used in an expression. 211 | - Post-Decrement (`i--`): Uses the current value of `i`, then decrements it by 1. 212 | 213 | ### 7.3. Control Flow 214 | 215 | 1. **If/Else** 216 | ```c 217 | edgy (condition) { 218 | // if-true block 219 | } 220 | amogus { 221 | // else block 222 | } 223 | ``` 224 | 2. **While** 225 | ```c 226 | goon (i < 5) { 227 | // loop body 228 | } 229 | ``` 230 | 3. **Do-While** 231 | ```c 232 | mewing { 233 | // loop body 234 | } goon (i < 5); 235 | ``` 236 | 4. **For** 237 | ```c 238 | flex (init_expr; condition; increment) { 239 | // loop body 240 | } 241 | ``` 242 | 5. **Switch** 243 | ```c 244 | ohio (expression) { 245 | sigma rule value: 246 | // case body 247 | bruh; 248 | based: 249 | // default case 250 | } 251 | ``` 252 | 253 | ### 7.4. Declarations and Variables (`rizz`) 254 | 255 | - **`rizz i = 0;`** declares an integer variable `i`, assigned 0. 256 | - **`i = i + 1;`** increments i by 1, following typical C expression syntax. 257 | 258 | ### 7.5. Return Statements (`bussin`) 259 | 260 | - **`bussin expression;`** to end the main function (or any function, if you extend the language). 261 | - Example: 262 | ```c 263 | bussin 0; 264 | ``` 265 | 266 | ### 7.6. Built-In Functions 267 | 268 | - **`yapping`**: prints text **and** automatically appends a newline. 269 | - **`yappin`**: prints text **without** adding a newline. 270 | - **`baka`**: prints to `stderr`, typically used for errors/warnings. 271 | - **`ragequit`**: terminates program execution immediately with the provided exit code. 272 | - **`chill`**: sleep for a integer number of seconds. 273 | - **`slorp`**: reads user input, similar to `scanf` but safe. 274 | 275 | --- 276 | 277 | ### 7.7. User Defined Function 278 | 279 | Defining a function in brainrot follows the same pattern as the C programming language: `return_type func_name(param_type param_name) {}` 280 | 281 | #### Example: 282 | 283 | ```c 284 | cap is_prime(rizz n) { 285 | edgy(n < 2) { 286 | bussin L; 287 | } 288 | flex(rizz i = 2; i * i <= n; i++) { 289 | edgy(n % i == 0) { 290 | bussin L; 291 | } 292 | } 293 | bussin W; 294 | 295 | } 296 | ``` 297 | 298 | #### BreakDown 299 | 300 | - **Function definition**: 301 | - `cap`: return type (bool) 302 | - `is_prime`: function name 303 | - `n`: parameter 304 | 305 | #### Usage Example: 306 | 307 | ```c 308 | cap isPrime = is_prime(11) 309 | 310 | ``` 311 | 312 | ## 8. Extended User Documentation 313 | 314 | ### 8.1. `yapping` 315 | 316 | ```c 317 | void yapping(const char* format, ...); 318 | ``` 319 | 320 | - Similar to `printf`, but **always** appends its own newline after printing. 321 | - If you include `\n` in `format`, expect **two** line breaks in total. 322 | 323 | **Example**: 324 | 325 | ```c 326 | yapping("Value: %d", 10); 327 | // Output => "Value: 10\n" 328 | ``` 329 | 330 | ### 8.2. `yappin` 331 | 332 | ```c 333 | void yappin(const char* format, ...); 334 | ``` 335 | 336 | - Similar to `printf` but **no** extra newline is added. 337 | - Perfect for building partial lines or for more granular control of output formatting. 338 | 339 | **Example**: 340 | 341 | ```c 342 | yappin("Hello "); 343 | yappin("World!\n"); 344 | // Output => "Hello World!\n" 345 | ``` 346 | 347 | ### 8.3. `baka` 348 | 349 | ```c 350 | void baka(const char* format, ...); 351 | ``` 352 | 353 | - Prints error messages to **`stderr`**. 354 | - Does **not** automatically add a newline (unless your format string includes one). 355 | - Great for logs, warnings, and error messages. 356 | 357 | **Example**: 358 | 359 | ```c 360 | baka("Error: undefined variable %s\n", varName); 361 | ``` 362 | 363 | ### 8.4. `ragequit` 364 | 365 | ```c 366 | void ragequit(int exit_code); 367 | ``` 368 | 369 | - Terminates program execution immediately with the provided exit code. 370 | - No additional output is printed unless explicitly added before the ragequit call. 371 | 372 | **Example**: 373 | 374 | ```c 375 | ragequit(1); 376 | ``` 377 | 378 | ### 8.5. `chill` 379 | 380 | ```c 381 | void chill(unsigned int seconds); 382 | ``` 383 | 384 | - Sleeps for a specified number of seconds (must be an unsigned integer) 385 | 386 | **Example**: 387 | 388 | ```c 389 | chill(2); 390 | ``` 391 | 392 | ### 8.6. `slorp` 393 | 394 | ```c 395 | void slorp(var_type var_name); 396 | ``` 397 | 398 | - Reads user input 399 | 400 | **Example**: 401 | 402 | ```c 403 | skibidi main { 404 | rizz num; 405 | yapping("Enter a number:"); 406 | slorp(num); 407 | yapping("You typed: %d", num); 408 | bussin 0; 409 | } 410 | ``` 411 | 412 | --- 413 | 414 | ## 9. Limitations 415 | 416 | - No built-in support for increment/decrement (`++`, `--`). 417 | - Functions other than `skibidi main` not fully supported (unless you add them). 418 | - Arrays, complex data structures, and advanced memory management are absent. 419 | - Error reporting is minimal, typically halting on the first serious parse error. 420 | 421 | --- 422 | 423 | ## 10. Known Issues 424 | 425 | - Some macOS users must manually manage `libfl` symlinks. 426 | - Minimal string manipulation: no standard library for string operations. 427 | - Grammar conflicts can arise if you expand the language significantly. 428 | - The language’s comedic nature may cause colleagues to question your sanity. 429 | 430 | --- 431 | 432 | ## 11. Cultural Context: The Rise of ‘Brain Rot’ 433 | 434 | The term **"brain rot"** was declared Oxford Word of the Year 2024, symbolizing the phenomenon of “the supposed deterioration of a person’s mental or intellectual state” due to low-value or meme-saturated online content. Brainrot the language playfully leans into this concept, intentionally using the so-called “nonsensical” or “trivial” memes to highlight a bit of self-awareness about how internet culture shapes our speech and thinking. 435 | 436 | --- 437 | 438 | ## 12. Meme Culture, Oxford Word of the Year, and Brainrot 439 | 440 | - The language’s name, “Brainrot,” resonates with the 2024 Word of the Year conversation. 441 | - Memes like **“Skibidi Toilet,”** **“Only in Ohio,”** and **“rizz”** are central to Gen Z and Gen Alpha humor. Brainrot references them liberally as a whimsical statement on how quickly online slang evolves—and how easily it can be turned into code. 442 | - The unstoppable spread of these memes ironically parallels the unstoppable creativity and chaos that emerges from community-driven language development. 443 | 444 | --- 445 | 446 | ## 13. Contributing 447 | 448 | If you want to add new slang or expand Brainrot: 449 | 450 | 1. **Fork** the GitHub repository. 451 | 2. **Create** a new branch for your changes. 452 | 3. **Edit** the grammar (`lang.y`) and lexer (`lang.l`) to support the new token or feature. 453 | 4. **Submit** a Pull Request with a clear description of your changes. 454 | 455 | All contributions, even more memes, are welcome—just be prepared for the comedic consequences! 456 | 457 | --- 458 | 459 | ## 14. License 460 | 461 | This project is licensed under the **GPL License**. See the `LICENSE` file in the repository for more details. Essentially, you’re free to modify and distribute Brainrot, so long as you keep it open-source and credit the original authors. 462 | 463 | --- 464 | 465 | ## 15. Closing Thoughts 466 | 467 | Brainrot is a testament to the fact that compiler design can be both educational and thoroughly _unserious_. Whether you’re an aspiring language implementer, a meme connoisseur, or just someone who thought “C needed more spice,” Brainrot might be the ideal playground for you. Code in Brainrot, add your own slang, or show it off to your friends to watch them recoil in confusion and laughter. 468 | 469 | ### “Just because you _can_ do something doesn’t mean you _should_—but in Brainrot’s case, maybe you _really should._” 470 | 471 | Happy coding, and remember: if your mind starts to go blank from all the memes, that’s not a bug—it’s Brainrot by design! 472 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | This directory contains several example programs written in the Brainrot language variant demonstrated by the provided grammar. Each example highlights different language features. 4 | 5 | --- 6 | 7 | ## 1. Hello, World! 8 | 9 | **File Name:** `hello_world.brainrot` 10 | 11 | ```c 12 | skibidi main { 13 | yappin("Hello, World!\n"); 14 | bussin 0; 15 | } 16 | ``` 17 | 18 | ### What It Does 19 | 20 | - Prints `"Hello, World!"` to the standard output. 21 | - Demonstrates a minimal working program in Brainraot language. 22 | - Uses the `yappin` function to output text. 23 | - Ends with `bussin 0;`, which acts like a `return 0;` in C. 24 | 25 | --- 26 | 27 | ## 2. FizzBuzz 28 | 29 | **File Name:** `fizz_buzz.brainrot` 30 | 31 | ```c 32 | skibidi main { 33 | nut rizz i; 34 | flex (i = 1; i <= 10; i = i + 1){ 35 | edgy ( (i % 15) == 0 ) { 36 | yapping("FizzBuzz"); 37 | } amogus edgy ( (i % 3) == 0 ) { 38 | yapping("Fizz"); 39 | } amogus edgy ( (i % 5) == 0 ) { 40 | yapping("Buzz"); 41 | } amogus { 42 | yapping("%d", i); 43 | } 44 | } 45 | bussin 0; 46 | } 47 | ``` 48 | 49 | ### What It Does 50 | 51 | - Implements the classic FizzBuzz challenge for values of `i` from `1` to `15`. 52 | - Prints: 53 | - **FizzBuzz** if a number is divisible by 15, 54 | - **Fizz** if divisible by 3, 55 | - **Buzz** if divisible by 5, 56 | - the number itself otherwise. 57 | - Demonstrates: 58 | - Declarations (`nut rizz i;`) which sets a variable as signed int (because `nut` = `signed`, `rizz` = `int`). 59 | - `flex` loops (equivalent to `for` loops). 60 | - `edgy` (equivalent to `if`) statements and `amogus` (equivalent to `else`). 61 | - `yapping` for printing. 62 | 63 | --- 64 | 65 | ## 3. Bubble Sort 66 | 67 | **File Name:** `bubble_sort.brainrot` 68 | 69 | ```c 70 | skibidi main { 71 | rizz arr[10]; 72 | rizz i; 73 | rizz j; 74 | rizz temp; 75 | 76 | 🚽 Initialize array with some unsorted numbers 77 | arr[0] = 64; 78 | arr[1] = 34; 79 | arr[2] = 25; 80 | arr[3] = 12; 81 | arr[4] = 22; 82 | arr[5] = 11; 83 | arr[6] = 90; 84 | arr[7] = 42; 85 | arr[8] = 15; 86 | arr[9] = 77; 87 | 88 | 🚽 Print original array 89 | yapping("Original array: "); 90 | flex (i = 0; i < 10; i = i + 1) { 91 | yapping("%d ", arr[i]); 92 | } 93 | 94 | 🚽 Bubble sort 95 | flex (i = 0; i < 9; i = i + 1) { 96 | flex (j = 0; j < 9 - i; j = j + 1) { 97 | edgy (arr[j] > arr[j + 1]) { 98 | temp = arr[j]; 99 | arr[j] = arr[j + 1]; 100 | arr[j + 1] = temp; 101 | } 102 | } 103 | } 104 | 105 | 🚽 Print sorted array 106 | yapping("Sorted array: "); 107 | flex (i = 0; i < 10; i = i + 1) { 108 | yapping("%d ", arr[i]); 109 | } 110 | 111 | bussin 0; 112 | } 113 | ``` 114 | 115 | ### What It Does 116 | 117 | - Declares an integer array `arr` with 10 elements (`rizz` = `int`). 118 | - Initializes and prints the unsorted array. 119 | - Implements the **Bubble Sort** algorithm to sort the array in ascending order. 120 | - Prints the sorted array. 121 | - Demonstrates: 122 | - Array declarations and assignments (`arr[i] = some_value;`) 123 | - Nested `flex` loops for the sorting routine. 124 | - Conditionals with `edgy`/`amogus`. 125 | - Use of `yapping` to print results. 126 | 127 | --- 128 | 129 | ## 4. Simple 1D Heat Equation Simulation 130 | 131 | **File Name:** `heat_equation_1d.brainrot` 132 | 133 | ```c 134 | skibidi main { 135 | rizz N = 50; 136 | gigachad u[50]; 137 | gigachad u_new[50]; 138 | rizz i; 139 | rizz t; 140 | rizz timesteps = 100; 141 | 142 | 🚽 Initialize array 143 | flex (i = 0; i < N; i = i + 1) { 144 | edgy ((i > 16) && (i < 33)) { 145 | u[i] = 100.0; 146 | } amogus { 147 | u[i] = 0.0; 148 | } 149 | } 150 | 151 | 🚽 Time evolution using just comparisons 152 | flex (t = 0; t < timesteps; t = t + 1) { 153 | edgy (t % 10 == 0) { 154 | yappin("Timestep %d: ", t); 155 | flex (i = 0; i < N; i = i + 1) { 156 | yapping("%lf", u[i]); 157 | } 158 | yapping(""); 159 | } 160 | 161 | 🚽 Update interior points using only assignments 162 | flex (i = 1; i < N-1; i = i + 1) { 163 | edgy (u[i+1] > u[i]) { 164 | u_new[i] = u[i] + 1.0; 🚽 If right neighbor is higher, increase slightly 165 | } amogus edgy (u[i-1] > u[i]) { 166 | u_new[i] = u[i] + 1.0; 🚽 If left neighbor is higher, increase slightly 167 | } amogus edgy ((u[i-1] < u[i]) && (u[i+1] < u[i])) { 168 | u_new[i] = u[i] - 1.0; 🚽 If both neighbors are lower, decrease slightly 169 | } amogus { 170 | u_new[i] = u[i]; 🚽 Otherwise keep same value 171 | } 172 | } 173 | 174 | u_new[0] = 0.0; 175 | u_new[N-1] = 0.0; 176 | 177 | flex (i = 0; i < N; i = i + 1) { 178 | u[i] = u_new[i]; 179 | } 180 | } 181 | 182 | bussin 0; 183 | } 184 | ``` 185 | 186 | ### What It Does 187 | 188 | - Demonstrates a **very** simplified 1D Heat Equation simulation or diffusion-like process (in a purely artificial sense). 189 | - Initializes a 1D array `u` of size 50; elements from 17 through 32 are set to 100.0, others are 0.0. 190 | - Runs 100 time steps of updates: 191 | - Every 10 steps, prints the state of the array. 192 | - At each step, updates `u[i]` based on comparisons with neighbors. 193 | - Showcases: 194 | - Double-precision arrays with `gigachad` (mapped to `double`). 195 | - Conditionals (`edgy`/`amogus`) to handle different numeric comparisons. 196 | - Printing partial array states (`yappin`) and final newlines with `yapping`. 197 | 198 | --- 199 | 200 | ## 5. Two Sum leetCode problem 201 | 202 | **File Name:** `twoSum.brainrot` 203 | 204 | ```c 205 | skibidi main { 206 | rizz nums[] = {7, 11, 2, 15}; 207 | rizz target = 9; 208 | rizz numsSize = maxxing(nums) / maxxing(nums[0]); 209 | rizz result[2]; 210 | 211 | flex (rizz i = 0; i < numsSize - 1; i++) { 212 | flex (rizz j = i + 1; j < numsSize; j++) { 213 | edgy (nums[i] > nums[j]) { 214 | rizz temp = nums[i]; 215 | nums[i] = nums[j]; 216 | nums[j] = temp; 217 | } 218 | } 219 | } 220 | 221 | 222 | rizz left = 0; 223 | rizz right = numsSize -1; 224 | 225 | goon (left < right){ 226 | rizz sum = nums[left] + nums[right]; 227 | edgy (sum == target){ 228 | result[0] = nums[left]; 229 | result[1] = nums[right]; 230 | bruh; 231 | } amogus edgy (sum < target){ 232 | left++; 233 | } amogus { 234 | right--; 235 | } 236 | } 237 | 238 | edgy ( left < right){ 239 | yappin("the two numbers are: %d and %d\n", result[0], result[1]); 240 | } amogus { 241 | yappign("No solution found\n"); 242 | } 243 | 244 | bussin 0; 245 | } 246 | 247 | ``` 248 | 249 | ### What It Does 250 | 251 | - Solves the classic Two Sum problem: find two numbers in the array `nums[]` that add up to the target value 9. 252 | - The array is first sorted using a Bubble Sort algorithm (nested loops with `edgy`/`amogus` for comparison and swapping). 253 | - The program uses a two-pointer technique (`left` and `right`) to find the pair that adds up to the `target` value. 254 | - If the sum equals the target, the result is stored in the `result[]` array and printed. 255 | - If no solution is found, it prints `"No solution found"`. 256 | - Showcases: 257 | - Array manipulation. 258 | - Using a two-pointer approach to solve the problem efficiently. 259 | - Conditional checking with `edgy`/`amogus`. 260 | 261 | 262 | ## 6. Sieve of Eratosthenes 263 | **File Name:** `sieve_of_eras.brainrot` 264 | ```c 265 | skibidi main { 266 | rizz i; 267 | rizz p; 268 | cap prime[105]; 269 | 270 | 🚽 Initialize all numbers as prime (W = true) 271 | flex(i = 1; i <= 100; i = i + 1) { 272 | prime[i] = W; 273 | } 274 | 275 | 🚽 Implement Sieve of Eratosthenes 276 | flex(p = 2; p * p <= 100; p = p + 1) { 277 | edgy(prime[p] == W) { 278 | flex(i = p * p; i <= 100; i = i + p) { 279 | prime[i] = L; 🚽 Mark multiples as not prime (L = false) 280 | } 281 | } 282 | } 283 | 284 | 🚽 Print all prime numbers 285 | yapping("Prime numbers up to 100: "); 286 | flex(p = 2; p <= 100; p = p + 1) { 287 | edgy(prime[p]) { 288 | yapping("%d ", p); 289 | } 290 | } 291 | 292 | bussin 0; 293 | } 294 | ``` 295 | - Declare the prime[105] array to mark prime numbers. 296 | - Initialize all numbers as W (true/prime). 297 | - Main loop of the Sieve of Eratosthenes to mark multiples of prime numbers as L (false/not prime). 298 | - Print prime numbers from 2 to 100 using yapping. 299 | - Showcases: 300 | - fill all prime array with true using `W`. 301 | - Using a two-pointer approach to solve the problem efficiently. 302 | - Conditional checking with `edgy`. 303 | 304 | 305 | ## Fibonacci Sequence 306 | **File name:** `fibonacci.brainrot` 307 | 308 | ``` 309 | skibidi main{ 310 | rizz first = 0; 311 | rizz second = 1; 312 | rizz next; 313 | rizz count = 0; 314 | rizz limit = 10; 315 | 316 | yapping("%d", first); 317 | yapping("%d", second); 318 | count = count + 2; 319 | 320 | goon(count < limit){ 321 | next = first + second; 322 | yapping("%d", next); 323 | 324 | first = second; 325 | second = next; 326 | 327 | count = count + 1; 328 | } 329 | 330 | bussin 0; 331 | } 332 | ``` 333 | ### What it does 334 | - Prints the first 10 numbers of fibonacci sequence (`limit` variable). 335 | - Initializes `first` and `second` terms with 0 and 1. 336 | - Using a `goon` loop to find the next numbers, until limit. 337 | 338 | 339 | Feel free to explore and modify each example to learn more about how this language’s syntax and features work! 340 | -------------------------------------------------------------------------------- /examples/bubble_sort.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | rizz arr[10]; 3 | rizz i; 4 | rizz j; 5 | rizz temp; 6 | 7 | 🚽 Initialize array with some unsorted numbers 8 | arr[0] = 64; 9 | arr[1] = 34; 10 | arr[2] = 25; 11 | arr[3] = 12; 12 | arr[4] = 22; 13 | arr[5] = 11; 14 | arr[6] = 90; 15 | arr[7] = 42; 16 | arr[8] = 15; 17 | arr[9] = 77; 18 | 19 | 🚽 Print original array 20 | yapping("Original array: "); 21 | flex (i = 0; i < 10; i = i + 1) { 22 | yapping("%d ", arr[i]); 23 | } 24 | 25 | 🚽 Bubble sort 26 | flex (i = 0; i < 9; i = i + 1) { 27 | flex (j = 0; j < 9 - i; j = j + 1) { 28 | edgy (arr[j] > arr[j + 1]) { 29 | temp = arr[j]; 30 | arr[j] = arr[j + 1]; 31 | arr[j + 1] = temp; 32 | } 33 | } 34 | } 35 | 36 | 🚽 Print sorted array 37 | yapping("Sorted array: "); 38 | flex (i = 0; i < 10; i = i + 1) { 39 | yapping("%d ", arr[i]); 40 | } 41 | 42 | bussin 0; 43 | } 44 | -------------------------------------------------------------------------------- /examples/fibonacci.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main{ 2 | rizz first = 0; 3 | rizz second = 1; 4 | rizz next; 5 | rizz count = 0; 6 | rizz limit = 10; 7 | 8 | yapping("%d", first); 9 | yapping("%d", second); 10 | count = count + 2; 11 | 12 | goon(count < limit){ 13 | next = first + second; 14 | yapping("%d", next); 15 | 16 | first = second; 17 | second = next; 18 | 19 | count = count + 1; 20 | } 21 | 22 | bussin 0; 23 | } -------------------------------------------------------------------------------- /examples/fizz_buzz.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | nut rizz i; 3 | flex (i = 1; i <= 15; i = i + 1){ 4 | edgy ( (i % 15) == 0 ) { 5 | yapping("FizzBuzz"); 6 | } amogus edgy ( (i % 3) == 0 ) { 7 | yapping("Fizz"); 8 | } amogus edgy ( (i % 5) == 0 ) { 9 | yapping("Buzz"); 10 | } amogus { 11 | yapping("%d", i); 12 | } 13 | } 14 | bussin 0; 15 | } 16 | -------------------------------------------------------------------------------- /examples/heat_equation_1d.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | rizz N = 50; 3 | gigachad u[50]; 4 | gigachad u_new[50]; 5 | rizz i; 6 | rizz t; 7 | rizz timesteps = 100; 8 | 9 | 🚽 Initialize array 10 | flex (i = 0; i < N; i = i + 1) { 11 | edgy ((i > 16) && (i < 33)) { 12 | u[i] = 100.0; 13 | } amogus { 14 | u[i] = 0.0; 15 | } 16 | } 17 | 18 | 🚽 Time evolution using just comparisons 19 | flex (t = 0; t < timesteps; t = t + 1) { 20 | edgy (t % 10 == 0) { 21 | yapping("Timestep %d: ", t); 22 | flex (i = 0; i < N; i = i + 1) { 23 | yapping("%lf", u[i]); 24 | } 25 | yapping(""); 26 | } 27 | 28 | 🚽 Update interior points using only assignments 29 | flex (i = 1; i < N-1; i = i + 1) { 30 | edgy (u[i+1] > u[i]) { 31 | u_new[i] = u[i] + 1.0; 🚽 If right neighbor is higher, increase slightly 32 | } amogus edgy (u[i-1] > u[i]) { 33 | u_new[i] = u[i] + 1.0; 🚽 If left neighbor is higher, increase slightly 34 | } amogus edgy ((u[i-1] < u[i]) && (u[i+1] < u[i])) { 35 | u_new[i] = u[i] - 1.0; 🚽 If both neighbors are lower, decrease slightly 36 | } amogus { 37 | u_new[i] = u[i]; 🚽 Otherwise keep same value 38 | } 39 | } 40 | 41 | u_new[0] = 0.0; 42 | u_new[N-1] = 0.0; 43 | 44 | flex (i = 0; i < N; i = i + 1) { 45 | u[i] = u_new[i]; 46 | } 47 | } 48 | 49 | bussin 0; 50 | } -------------------------------------------------------------------------------- /examples/hello_world.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | yappin("Hello, World!\n"); 3 | bussin 0; 4 | } 5 | -------------------------------------------------------------------------------- /examples/sieve_of_eras.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | rizz i; 3 | rizz p; 4 | cap prime[105]; 5 | flex(i = 1; i <= 100; i = i + 1){ 6 | prime[i] = W; 7 | } 8 | 9 | flex(p = 2; p * p <= 100; p++){ 10 | edgy(prime[p] == W){ 11 | flex(i = p * p; i <= 100; i = i+p){ 12 | prime[i] = L; 13 | } 14 | } 15 | } 16 | 17 | flex(p = 2;p <= 100; p = p + 1){ 18 | edgy(prime[p]) { yapping("%d", p); } 19 | } 20 | 21 | bussin 0; 22 | } 23 | -------------------------------------------------------------------------------- /examples/twoSum.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | rizz nums[4] = {7, 11, 2, 15}; 3 | rizz target = 9; 4 | rizz numsSize = maxxing(nums) / maxxing(nums[0]); 5 | rizz result[2]; 6 | 7 | flex (rizz i = 0; i < numsSize - 1; i++) { 8 | flex (rizz j = i + 1; j < numsSize; j++) { 9 | edgy (nums[i] > nums[j]) { 10 | rizz temp = nums[i]; 11 | nums[i] = nums[j]; 12 | nums[j] = temp; 13 | } 14 | } 15 | } 16 | 17 | 18 | rizz left = 0; 19 | rizz right = numsSize -1; 20 | 21 | goon (left < right){ 22 | rizz sum = nums[left] + nums[right]; 23 | edgy (sum == target){ 24 | result[0] = nums[left]; 25 | result[1] = nums[right]; 26 | bruh; 27 | } amogus edgy (sum < target){ 28 | left++; 29 | } amogus { 30 | right--; 31 | } 32 | } 33 | 34 | edgy ( left < right){ 35 | yappin("the two numbers are: %d and %d\n", result[0], result[1]); 36 | } amogus { 37 | yappin("No solution found\n"); 38 | } 39 | 40 | bussin 0; 41 | } 42 | -------------------------------------------------------------------------------- /lang.l: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | #include 4 | #include 5 | #include "ast.h" 6 | #include "lib/mem.h" 7 | #include "lib/arena.h" 8 | #include "lang.tab.h" 9 | 10 | VarType current_var_type = NONE; 11 | 12 | char *unescape_string(const char *src) { 13 | // Allocate a buffer big enough for the worst case 14 | // (same length as src, since we only shrink on escapes) 15 | char *dest = malloc(strlen(src) + 1); 16 | char *d = dest; 17 | const char *s = src; 18 | 19 | while (*s) { 20 | if (*s == '\\') { 21 | s++; 22 | switch (*s) { 23 | case 'n': *d++ = '\n'; break; 24 | case 't': *d++ = '\t'; break; 25 | case '\\': *d++ = '\\'; break; 26 | case '"': *d++ = '"'; break; 27 | // ... handle other escapes you care about ... 28 | default: 29 | // If it's an unknown escape like \q, 30 | // you might just copy it literally or skip it. 31 | *d++ = *s; 32 | break; 33 | } 34 | s++; 35 | } else { 36 | *d++ = *s++; 37 | } 38 | } 39 | *d = '\0'; 40 | return dest; 41 | } 42 | 43 | 44 | extern int yylineno; 45 | %} 46 | 47 | %option yylineno 48 | 49 | %% 50 | 51 | "skibidi" { return SKIBIDI; } 52 | "bussin" { return BUSSIN; } 53 | "flex" { return FLEX; } 54 | "rizz" { current_var_type = VAR_INT; return RIZZ; } 55 | "main" { return MAIN; } 56 | "bruh" { return BREAK; } 57 | "sigma rule" { return CASE; } 58 | "yap" { current_var_type = VAR_CHAR; return YAP; } 59 | "deadass" { return DEADASS; } 60 | "grind" { return CONTINUE; } 61 | "based" { return DEFAULT; } 62 | "mewing" { return DO; } 63 | "gigachad" { current_var_type = VAR_DOUBLE; return GIGACHAD; } 64 | "gyatt" { return ENUM; } 65 | "whopper" { return EXTERN; } 66 | "chad" { current_var_type = VAR_FLOAT; return CHAD; } 67 | "cringe" { return GOTO; } 68 | "edgy" { return IF; } 69 | "amogus" { return ELSE; } 70 | "giga" { return LONG; } 71 | "smol" { current_var_type = VAR_SHORT; return SMOL; } 72 | "nut" { return SIGNED; } 73 | "maxxing" { return SIZEOF; } 74 | "salty" { return STATIC; } 75 | "gang" { return STRUCT; } 76 | "ohio" { return SWITCH; } 77 | "chungus" { return UNION; } 78 | "nonut" { return UNSIGNED; } 79 | "schizo" { return VOLATILE; } 80 | "goon" { return GOON; } 81 | "baka" { return BAKA; } 82 | "slorp" { return SLORP; } 83 | "cap" { current_var_type = VAR_BOOL; return CAP; } 84 | 85 | "==" { return EQ; } 86 | "!=" { return NE; } 87 | "<=" { return LE; } 88 | ">=" { return GE; } 89 | "&&" { return AND; } 90 | "||" { return OR; } 91 | "<" { return LT; } 92 | ">" { return GT; } 93 | "=" { return EQUALS; } 94 | 95 | "+" { return PLUS; } 96 | "-" { return MINUS; } 97 | "*" { return TIMES; } 98 | "/" { return DIVIDE; } 99 | "%" { return MOD; } 100 | "++" { return INC; } 101 | "--" { return DEC; } 102 | 103 | "(" { return LPAREN; } 104 | ")" { return RPAREN; } 105 | "{" { return LBRACE; } 106 | "}" { return RBRACE; } 107 | ";" { return SEMICOLON; } 108 | "," { return COMMA; } 109 | ":" { return COLON; } 110 | "[" { return LBRACKET; } 111 | "]" { return RBRACKET; } 112 | 113 | "🚽"[^\n]* ; /* Ignore single line comments */ 114 | "W" { yylval.ival = 1; return BOOLEAN; } 115 | "L" { yylval.ival = 0; return BOOLEAN; } 116 | [0-9]+\.[0-9]+([eE][+-]?[0-9]+)?[LlFf]? { 117 | char *endptr; 118 | if (strchr(yytext, 'f') || strchr(yytext, 'F')) { 119 | yylval.fval = strtof(yytext, &endptr); 120 | return FLOAT_LITERAL; 121 | } else if (strchr(yytext, 'L') || strchr(yytext, 'l')) { 122 | yylval.dval = strtod(yytext, &endptr); 123 | return DOUBLE_LITERAL; 124 | } else { 125 | yylval.dval = strtod(yytext, &endptr); 126 | return DOUBLE_LITERAL; 127 | } 128 | } 129 | [0-9]+ { 130 | int next_char = input(); // Peek at the next character 131 | unput(next_char); // Put it back into the input stream 132 | 133 | if (next_char == ']') { 134 | // If the next character is ']', treat this numeric literal as an integer. 135 | yylval.ival = atoi(yytext); 136 | return INT_LITERAL; 137 | } 138 | 139 | // Otherwise, follow the existing type-based logic. 140 | if (current_var_type == VAR_SHORT) { 141 | yylval.sval = (short)atoi(yytext); 142 | return SHORT_LITERAL; 143 | } else if (current_var_type == VAR_INT || current_var_type == NONE) { 144 | yylval.ival = atoi(yytext); 145 | return INT_LITERAL; 146 | } else { 147 | // Default behavior for unexpected types 148 | yylval.ival = atoi(yytext); 149 | return INT_LITERAL; 150 | } 151 | } 152 | 153 | '.' { yylval.ival = yytext[1]; return CHAR; } 154 | [a-zA-Z_][a-zA-Z0-9_]* { yylval.strval = safe_strdup(yytext); return IDENTIFIER; } 155 | \"([^\\\"]|\\.)*\" { 156 | // Strip the leading and trailing quotes: 157 | char *raw = (yytext + 1); 158 | raw[strlen(raw) - 1] = '\0'; 159 | 160 | // Convert backslash escapes to real characters: 161 | char *unescaped = unescape_string(raw); 162 | 163 | yylval.strval = unescaped; // Now it has real newlines, etc. 164 | return STRING_LITERAL; 165 | } 166 | \'([^\\\']|\\.)\' { 167 | // The text matched includes the leading and trailing single quotes, e.g. 'c'. 168 | // We'll decode the actual character inside. 169 | char c; 170 | 171 | if (yytext[1] == '\\') { 172 | // Handle escape sequences like '\n', '\t', '\\', '\'' 173 | switch (yytext[2]) { 174 | case 'n': c = '\n'; break; 175 | case 't': c = '\t'; break; 176 | case '\\': c = '\\'; break; 177 | case '\'': c = '\''; break; 178 | // You can add more escapes if you need them 179 | default: 180 | // If unrecognized, just use the literal char 181 | c = yytext[2]; 182 | break; 183 | } 184 | } else { 185 | // Normal single character, e.g. 'c' 186 | c = yytext[1]; 187 | } 188 | 189 | yylval.ival = c; // Put the character in the parser’s yylval 190 | return YAP; 191 | } 192 | 193 | [ \t\n]+ ; /* Ignore whitespace */ 194 | . { /* Ignore unrecognized characters */ } 195 | 196 | %% 197 | 198 | int yywrap(void) { 199 | return 1; 200 | } 201 | -------------------------------------------------------------------------------- /lang.y: -------------------------------------------------------------------------------- 1 | %define parse.error verbose 2 | %{ 3 | #include "ast.h" 4 | #include "lib/mem.h" 5 | #include "lib/input.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int yylex(void); 14 | int yylex_destroy(void); 15 | void yyerror(const char *s); 16 | void ragequit(int exit_code); 17 | void yapping(const char* format, ...); 18 | void yappin(const char* format, ...); 19 | void baka(const char* format, ...); 20 | char slorp_char(char chr); 21 | char *slorp_string(char *string, size_t size); 22 | int slorp_int(int val); 23 | short slorp_short(short val); 24 | float slorp_float(float var); 25 | double slorp_double(double var); 26 | void cleanup(); 27 | TypeModifiers get_variable_modifiers(const char* name); 28 | extern TypeModifiers current_modifiers; 29 | extern VarType current_var_type; 30 | 31 | extern int yylineno; 32 | extern FILE *yyin; 33 | 34 | /* Root of the AST */ 35 | ASTNode *root = NULL; 36 | %} 37 | 38 | %union { 39 | int ival; 40 | short sval; 41 | float fval; 42 | double dval; 43 | char cval; 44 | char *strval; 45 | ASTNode *node; 46 | CaseNode *case_node; 47 | ArgumentList *args; 48 | ExpressionList *expr_list; 49 | Parameter *param; 50 | ArrayDimensions array_dims; 51 | Array array; 52 | } 53 | 54 | /* Define token types */ 55 | %token SKIBIDI RIZZ YAP BAKA MAIN BUSSIN FLEX CAP 56 | %token PLUS MINUS TIMES DIVIDE MOD SEMICOLON COLON COMMA 57 | %token LPAREN RPAREN LBRACE RBRACE 58 | %token LT GT LE GE EQ NE EQUALS AND OR DEC INC 59 | %token BREAK CASE DEADASS CONTINUE DEFAULT DO DOUBLE ELSE ENUM 60 | %token EXTERN CHAD GIGACHAD FOR GOTO IF LONG SMOL SIGNED 61 | %token SIZEOF STATIC STRUCT SWITCH TYPEDEF UNION UNSIGNED VOID VOLATILE GOON 62 | %token LBRACKET RBRACKET 63 | %token IDENTIFIER 64 | %token INT_LITERAL 65 | %token SHORT_LITERAL 66 | %token STRING_LITERAL 67 | %token CHAR 68 | %token BOOLEAN 69 | %token FLOAT_LITERAL 70 | %token DOUBLE_LITERAL 71 | %token SLORP 72 | 73 | /* Declare types for non-terminals */ 74 | %type type 75 | %type program skibidi_function 76 | %type statements statement 77 | %type declaration 78 | %type expression 79 | %type for_statement 80 | %type while_statement 81 | %type do_while_statement 82 | %type function_call 83 | %type arg_list argument_list 84 | %type error_statement 85 | %type return_statement 86 | %type init_expr condition increment 87 | %type if_statement 88 | %type switch_statement break_statement 89 | %type case_list case_clause 90 | %type binary_operation unary_operation parentheses 91 | %type array_access 92 | %type assignment 93 | %type literal identifier sizeof_expression 94 | %type array_init initializer_list 95 | %type function_def 96 | %type function_def_list 97 | %type param_list params 98 | %type dimensions 99 | %type multi_dimension_access 100 | 101 | %start program 102 | 103 | /* Define precedence for operators */ 104 | %nonassoc LOWER_THAN_ELSE 105 | %nonassoc ELSE 106 | 107 | %right EQUALS /* Assignment operator */ 108 | %left OR /* Logical OR */ 109 | %left AND /* Logical AND */ 110 | %nonassoc EQ NE /* Equality operators */ 111 | %nonassoc LT GT LE GE DEC INC /* Relational operators */ 112 | %left PLUS MINUS /* Addition and subtraction */ 113 | %left TIMES DIVIDE MOD /* Multiplication, division, modulo */ 114 | %right UMINUS /* Unary minus */ 115 | 116 | %% 117 | 118 | program 119 | : function_def_list skibidi_function 120 | { root = create_statement_list($2, $1); } 121 | ; 122 | 123 | function_def_list 124 | : /* empty */ 125 | { $$ = NULL; } 126 | | function_def_list function_def 127 | { $$ = create_statement_list($2, $1); } 128 | ; 129 | 130 | function_def 131 | : type IDENTIFIER LPAREN params RPAREN LBRACE statements RBRACE 132 | { $$ = create_function_def_node($2, $1, $4, $7); SAFE_FREE($2); } 133 | ; 134 | 135 | params 136 | : param_list 137 | { $$ = $1; } 138 | | /* empty */ 139 | { $$ = NULL; } 140 | ; 141 | 142 | param_list 143 | : optional_modifiers type IDENTIFIER 144 | { $$ = create_parameter($3, $2, NULL, get_current_modifiers()); SAFE_FREE($3); } 145 | | param_list COMMA optional_modifiers type IDENTIFIER 146 | { $$ = create_parameter($5, $4, $1, get_current_modifiers()); SAFE_FREE($5); } 147 | ; 148 | 149 | 150 | skibidi_function: 151 | SKIBIDI MAIN LBRACE statements RBRACE 152 | { $$ = $4; } 153 | ; 154 | 155 | statements: 156 | /* empty */ 157 | { $$ = NULL; } 158 | | statements statement 159 | { $$ = create_statement_list($2, $1); } 160 | ; 161 | 162 | statement: 163 | declaration SEMICOLON 164 | { $$ = $1; } 165 | | for_statement 166 | { $$ = $1; } 167 | | while_statement 168 | { $$ = $1; } 169 | | do_while_statement 170 | { $$ = $1; } 171 | | error_statement SEMICOLON 172 | { $$ = $1; } 173 | | return_statement SEMICOLON 174 | { $$ = $1; } 175 | | if_statement 176 | { $$ = $1; } 177 | | switch_statement 178 | { $$ = $1; } 179 | | break_statement SEMICOLON 180 | { $$ = $1; } 181 | | expression SEMICOLON 182 | { $$ = $1; } 183 | ; 184 | 185 | switch_statement: 186 | SWITCH LPAREN expression RPAREN LBRACE case_list RBRACE 187 | { $$ = create_switch_statement_node($3, $6); } 188 | ; 189 | 190 | case_list: 191 | /* empty */ 192 | { $$ = NULL; } 193 | | case_list case_clause 194 | { $$ = append_case_list($1, $2); } 195 | ; 196 | 197 | case_clause: 198 | CASE expression COLON statements 199 | { $$ = create_case_node($2, $4); } 200 | | DEFAULT COLON statements 201 | { $$ = create_default_case_node($3); } 202 | ; 203 | 204 | break_statement: 205 | BREAK 206 | { $$ = create_break_node(); } 207 | ; 208 | 209 | if_statement: 210 | IF LPAREN expression RPAREN LBRACE statements RBRACE %prec LOWER_THAN_ELSE 211 | { $$ = create_if_statement_node($3, $6, NULL); } 212 | | IF LPAREN expression RPAREN LBRACE statements RBRACE ELSE if_statement %prec ELSE 213 | { $$ = create_if_statement_node($3, $6, $9); } 214 | | IF LPAREN expression RPAREN LBRACE statements RBRACE ELSE LBRACE statements RBRACE %prec ELSE 215 | { $$ = create_if_statement_node($3, $6, $10); } 216 | ; 217 | 218 | type: 219 | RIZZ { $$ = VAR_INT; } 220 | | CHAD { $$ = VAR_FLOAT; } 221 | | GIGACHAD { $$ = VAR_DOUBLE; } 222 | | SMOL { $$ = VAR_SHORT; } 223 | | YAP { $$ = VAR_CHAR; } 224 | | CAP { $$ = VAR_BOOL; } 225 | ; 226 | 227 | declaration: 228 | optional_modifiers type IDENTIFIER 229 | { 230 | $$ = create_declaration_node($3, create_default_node($2)); 231 | SAFE_FREE($3); 232 | } 233 | | optional_modifiers type IDENTIFIER EQUALS expression 234 | { 235 | $$ = create_declaration_node($3, $5); 236 | SAFE_FREE($3); 237 | } 238 | | optional_modifiers type IDENTIFIER dimensions 239 | { 240 | Variable *var = variable_new($3); 241 | add_variable_to_scope($3, var); 242 | if (!set_multi_array_variable($3, $4.dimensions, $4.num_dimensions, get_current_modifiers(), $2)) { 243 | yyerror("Failed to create array"); 244 | SAFE_FREE($3); 245 | YYABORT; 246 | } 247 | $$ = create_multi_array_declaration_node($3, $4.dimensions, $4.num_dimensions, $2); 248 | SAFE_FREE($3); 249 | SAFE_FREE(var); 250 | } 251 | | optional_modifiers type IDENTIFIER dimensions EQUALS array_init 252 | { 253 | Variable *var = variable_new($3); 254 | add_variable_to_scope($3, var); 255 | set_multi_array_variable($3, $4.dimensions, $4.num_dimensions, get_current_modifiers(), $2); 256 | // Handle initialization with proper dimension checks 257 | populate_multi_array_variable($3, $6, $4.dimensions, $4.num_dimensions); 258 | $$ = create_multi_array_declaration_node($3, $4.dimensions, $4.num_dimensions, $2); 259 | SAFE_FREE($3); 260 | SAFE_FREE(var); 261 | free_expression_list($6); 262 | } 263 | ; 264 | 265 | array_init: 266 | LBRACE initializer_list RBRACE 267 | { $$ = $2; } 268 | ; 269 | 270 | dimensions: 271 | LBRACKET INT_LITERAL RBRACKET 272 | { 273 | $$.dimensions[0] = $2; 274 | $$.num_dimensions = 1; 275 | } 276 | | dimensions LBRACKET INT_LITERAL RBRACKET 277 | { 278 | if ($1.num_dimensions >= MAX_DIMENSIONS) { 279 | yyerror("Maximum array dimensions exceeded"); 280 | YYABORT; 281 | } 282 | $$.dimensions[$1.num_dimensions] = $3; 283 | $$.num_dimensions = $1.num_dimensions + 1; 284 | } 285 | ; 286 | 287 | initializer_list: 288 | expression 289 | { $$ = create_expression_list($1); } 290 | | initializer_list COMMA expression 291 | { $$ = append_expression_list($1, $3); } 292 | ; 293 | 294 | optional_modifiers: 295 | /* empty */ 296 | { /* No action needed */ } 297 | | optional_modifiers modifier 298 | { /* No action needed */ } 299 | ; 300 | 301 | modifier: 302 | VOLATILE 303 | { current_modifiers.is_volatile = true; } 304 | | SIGNED 305 | { current_modifiers.is_signed = true; } 306 | | UNSIGNED 307 | { current_modifiers.is_unsigned = true; } 308 | | DEADASS 309 | { current_modifiers.is_const = true; } 310 | | CAP 311 | { current_var_type = VAR_BOOL; } 312 | ; 313 | 314 | for_statement: 315 | FLEX LPAREN init_expr SEMICOLON condition SEMICOLON increment RPAREN LBRACE statements RBRACE 316 | { 317 | $$ = create_for_statement_node($3, $5, $7, $10); 318 | } 319 | ; 320 | 321 | while_statement: 322 | GOON LPAREN expression RPAREN LBRACE statements RBRACE 323 | { 324 | $$ = create_while_statement_node($3, $6); 325 | } 326 | ; 327 | 328 | do_while_statement: 329 | DO LBRACE statements RBRACE GOON LPAREN expression RPAREN SEMICOLON 330 | { 331 | $$ = create_do_while_statement_node($7, $3); 332 | } 333 | 334 | 335 | init_expr: 336 | declaration 337 | { $$ = $1; } 338 | | expression 339 | { $$ = $1; } 340 | ; 341 | 342 | condition: 343 | expression 344 | { $$ = $1; } 345 | ; 346 | 347 | increment: 348 | expression 349 | { $$ = $1; } 350 | ; 351 | 352 | function_call: 353 | SLORP LPAREN identifier RPAREN 354 | { 355 | $$ = create_function_call_node("slorp", create_argument_list($3, NULL)); 356 | } 357 | | IDENTIFIER LPAREN arg_list RPAREN 358 | { 359 | $$ = create_function_call_node($1, $3); 360 | SAFE_FREE($1); 361 | } 362 | ; 363 | 364 | arg_list 365 | : /* empty */ 366 | { 367 | $$ = NULL; /* No arguments */ 368 | } 369 | | argument_list 370 | { 371 | $$ = $1; 372 | } 373 | ; 374 | 375 | argument_list 376 | : expression 377 | { 378 | /* 379 | * Single-argument list 380 | * We'll create a linked list (or array) of argument nodes 381 | */ 382 | $$ = create_argument_list($1, NULL); 383 | } 384 | | argument_list COMMA expression 385 | { 386 | /* 387 | * Append the new expression to the existing argument list 388 | */ 389 | $$ = create_argument_list($3, $1); 390 | } 391 | ; 392 | 393 | error_statement: 394 | BAKA LPAREN expression RPAREN 395 | { $$ = create_error_statement_node($3); } 396 | ; 397 | 398 | return_statement: 399 | BUSSIN expression 400 | { $$ = create_return_node($2); } 401 | ; 402 | 403 | expression: 404 | literal 405 | | identifier 406 | | assignment 407 | | binary_operation 408 | | unary_operation 409 | | parentheses 410 | | array_access 411 | | sizeof_expression 412 | | function_call 413 | ; 414 | 415 | sizeof_expression: 416 | SIZEOF LPAREN expression RPAREN{ $$ = create_sizeof_node($3); } 417 | ; 418 | literal: 419 | INT_LITERAL { $$ = create_int_node($1); } 420 | | FLOAT_LITERAL { $$ = create_float_node($1); } 421 | | DOUBLE_LITERAL { $$ = create_double_node($1); } 422 | | CHAR { $$ = create_char_node($1); } 423 | | SHORT_LITERAL { $$ = create_short_node($1); } 424 | | BOOLEAN { $$ = create_boolean_node($1); } 425 | | STRING_LITERAL { $$ = create_string_literal_node($1); free($1);} 426 | ; 427 | 428 | identifier: 429 | IDENTIFIER 430 | { 431 | $$ = create_identifier_node($1); 432 | SAFE_FREE($1); 433 | } 434 | ; 435 | 436 | assignment: 437 | IDENTIFIER EQUALS expression 438 | { 439 | $$ = create_assignment_node($1, $3); 440 | SAFE_FREE($1); 441 | } 442 | | IDENTIFIER multi_dimension_access EQUALS expression 443 | { 444 | ASTNode *access= create_multi_array_access_node($1, $2.indices, $2.num_dimensions); 445 | ASTNode *node = ARENA_ALLOC(ASTNode); 446 | if (!node) { 447 | yyerror("Memory allocation failed"); 448 | SAFE_FREE($1); 449 | exit(EXIT_FAILURE); 450 | } 451 | node->type = NODE_ASSIGNMENT; 452 | node->data.op.left = access; 453 | node->data.op.right = $4; 454 | node->data.op.op = OP_ASSIGN; 455 | $$ = node; 456 | SAFE_FREE($1); 457 | } 458 | ; 459 | 460 | multi_dimension_access: 461 | LBRACKET expression RBRACKET 462 | { 463 | $$.indices[0] = $2; 464 | $$.num_dimensions = 1; 465 | } 466 | | multi_dimension_access LBRACKET expression RBRACKET 467 | { 468 | if ($1.num_dimensions >= MAX_DIMENSIONS) { 469 | yyerror("Too many array indices"); 470 | YYABORT; 471 | } 472 | $$ = $1; 473 | $$.indices[$$.num_dimensions] = $3; 474 | $$.num_dimensions++; 475 | } 476 | ; 477 | 478 | binary_operation: 479 | expression PLUS expression { $$ = create_operation_node(OP_PLUS, $1, $3); } 480 | | expression MINUS expression { $$ = create_operation_node(OP_MINUS, $1, $3); } 481 | | expression TIMES expression { $$ = create_operation_node(OP_TIMES, $1, $3); } 482 | | expression DIVIDE expression { $$ = create_operation_node(OP_DIVIDE, $1, $3); } 483 | | expression MOD expression { $$ = create_operation_node(OP_MOD, $1, $3); } 484 | | expression LT expression { $$ = create_operation_node(OP_LT, $1, $3); } 485 | | expression GT expression { $$ = create_operation_node(OP_GT, $1, $3); } 486 | | expression LE expression { $$ = create_operation_node(OP_LE, $1, $3); } 487 | | expression GE expression { $$ = create_operation_node(OP_GE, $1, $3); } 488 | | expression EQ expression { $$ = create_operation_node(OP_EQ, $1, $3); } 489 | | expression NE expression { $$ = create_operation_node(OP_NE, $1, $3); } 490 | | expression AND expression { $$ = create_operation_node(OP_AND, $1, $3); } 491 | | expression OR expression { $$ = create_operation_node(OP_OR, $1, $3); } 492 | ; 493 | 494 | unary_operation: 495 | MINUS expression %prec UMINUS { $$ = create_unary_operation_node(OP_NEG, $2); } 496 | | INC expression %prec LOWER_THAN_ELSE 497 | { $$ = create_unary_operation_node(OP_PRE_INC, $2); } 498 | | DEC expression %prec LOWER_THAN_ELSE 499 | { $$ = create_unary_operation_node(OP_PRE_DEC, $2); } 500 | | expression INC %prec LOWER_THAN_ELSE 501 | { $$ = create_unary_operation_node(OP_POST_INC, $1); } 502 | | expression DEC %prec LOWER_THAN_ELSE 503 | { $$ = create_unary_operation_node(OP_POST_DEC, $1); } 504 | ; 505 | 506 | parentheses: 507 | LPAREN expression RPAREN { $$ = $2; } 508 | ; 509 | 510 | array_access: 511 | IDENTIFIER multi_dimension_access 512 | { 513 | ASTNode *node = create_multi_array_access_node($1, $2.indices, $2.num_dimensions); 514 | SAFE_FREE($1); 515 | $$ = node; 516 | } 517 | ; 518 | 519 | %% 520 | 521 | int main(int argc, char *argv[]) { 522 | if (argc != 2) { 523 | fprintf(stderr, "Usage: %s \n", argv[0]); 524 | return 1; 525 | } 526 | 527 | FILE *source = fopen(argv[1], "r"); 528 | if (!source) { 529 | perror("Cannot open source file"); 530 | return 1; 531 | } 532 | 533 | yyin = source; 534 | current_scope = create_scope(NULL); 535 | 536 | if (yyparse() == 0) { 537 | execute_statement(root); 538 | } 539 | 540 | fclose(source); 541 | free_ast(); 542 | free_function_table(); 543 | free_scope(current_scope); 544 | yylex_destroy(); 545 | 546 | return 0; 547 | } 548 | 549 | void yyerror(const char *s) { 550 | fprintf(stderr, "Error: %s at line %d\n", s, yylineno - 1); 551 | } 552 | 553 | void ragequit(int exit_code) { 554 | cleanup(); 555 | exit(exit_code); 556 | } 557 | 558 | void chill(unsigned int seconds) { 559 | sleep(seconds); 560 | } 561 | 562 | void yapping(const char* format, ...) { 563 | va_list args; 564 | va_start(args, format); 565 | vprintf(format, args); 566 | va_end(args); 567 | printf("\n"); 568 | } 569 | 570 | void yappin(const char* format, ...) { 571 | va_list args; 572 | va_start(args, format); 573 | vprintf(format, args); 574 | va_end(args); 575 | } 576 | 577 | void baka(const char* format, ...) { 578 | va_list args; 579 | va_start(args, format); 580 | vfprintf(stderr, format, args); 581 | va_end(args); 582 | } 583 | 584 | char slorp_char(char chr) { 585 | input_status status; 586 | 587 | status = input_char(&chr); 588 | if (status == INPUT_SUCCESS) 589 | { 590 | return chr; 591 | } 592 | else if (status == INPUT_INVALID_LENGTH) 593 | { 594 | fprintf(stderr, "Error: Invalid input length.\n"); 595 | exit(EXIT_FAILURE); 596 | } 597 | else 598 | { 599 | fprintf(stderr, "Error reading char: %d\n", status); 600 | exit(EXIT_FAILURE); 601 | } 602 | } 603 | 604 | char *slorp_string(char *string, size_t size) { 605 | size_t chars_read; 606 | input_status status; 607 | 608 | status = input_string(string, size, &chars_read); 609 | if (status == INPUT_SUCCESS) 610 | { 611 | return string; 612 | } 613 | else if (status == INPUT_BUFFER_OVERFLOW) 614 | { 615 | fprintf(stderr, "Error: Input exceeded buffer size.\n"); 616 | exit(EXIT_FAILURE); 617 | } 618 | else 619 | { 620 | fprintf(stderr, "Error reading string: %d\n", status); 621 | exit(EXIT_FAILURE); 622 | } 623 | } 624 | 625 | int slorp_int(int val) { 626 | input_status status; 627 | 628 | status = input_int(&val); 629 | if (status == INPUT_SUCCESS) 630 | { 631 | return val; 632 | } 633 | else if (status == INPUT_INTEGER_OVERFLOW) 634 | { 635 | fprintf(stderr, "Error: Integer value out of range.\n"); 636 | exit(EXIT_FAILURE); 637 | } 638 | else if (status == INPUT_CONVERSION_ERROR) 639 | { 640 | fprintf(stderr, "Error: Invalid integer format.\n"); 641 | exit(EXIT_FAILURE); 642 | } 643 | else 644 | { 645 | fprintf(stderr, "Error reading integer: %d\n", status); 646 | exit(EXIT_FAILURE); 647 | } 648 | return 0; 649 | } 650 | 651 | short slorp_short(short val) { 652 | input_status status; 653 | 654 | status = input_short(&val); 655 | if (status == INPUT_SUCCESS) 656 | { 657 | return val; 658 | } 659 | else if (status == INPUT_SHORT_OVERFLOW) 660 | { 661 | fprintf(stderr, "Error: short value out of range.\n"); 662 | exit(EXIT_FAILURE); 663 | } 664 | else if (status == INPUT_CONVERSION_ERROR) 665 | { 666 | fprintf(stderr, "Error: short integer format.\n"); 667 | exit(EXIT_FAILURE); 668 | } 669 | else 670 | { 671 | fprintf(stderr, "Error reading short: %d\n", status); 672 | exit(EXIT_FAILURE); 673 | } 674 | return 0; 675 | } 676 | 677 | float slorp_float(float var) { 678 | input_status status; 679 | 680 | status = input_float(&var); 681 | if (status == INPUT_SUCCESS) 682 | { 683 | return var; 684 | } 685 | else if (status == INPUT_FLOAT_OVERFLOW) 686 | { 687 | fprintf(stderr, "Error: Double value out of range.\n"); 688 | exit(EXIT_FAILURE); 689 | } 690 | else if (status == INPUT_CONVERSION_ERROR) 691 | { 692 | fprintf(stderr, "Error: Invalid float format.\n"); 693 | exit(EXIT_FAILURE); 694 | } 695 | else 696 | { 697 | fprintf(stderr, "Error reading float: %d\n", status); 698 | exit(EXIT_FAILURE); 699 | } 700 | } 701 | 702 | double slorp_double(double var) { 703 | input_status status; 704 | 705 | status = input_double(&var); 706 | if (status == INPUT_SUCCESS) 707 | { 708 | return var; 709 | } 710 | else if (status == INPUT_DOUBLE_OVERFLOW) 711 | { 712 | fprintf(stderr, "Error: Double value out of range.\n"); 713 | exit(EXIT_FAILURE); 714 | } 715 | else if (status == INPUT_CONVERSION_ERROR) 716 | { 717 | fprintf(stderr, "Error: Invalid double format.\n"); 718 | exit(EXIT_FAILURE); 719 | } 720 | else 721 | { 722 | fprintf(stderr, "Error reading double: %d\n", status); 723 | exit(EXIT_FAILURE); 724 | } 725 | } 726 | 727 | void cleanup() { 728 | // Free the AST 729 | free_ast(); 730 | 731 | // Free the scope 732 | free_scope(current_scope); 733 | 734 | free_function_table(); 735 | 736 | CLEAN_JUMP_BUFFER(); 737 | 738 | // Clean up flex's internal state 739 | yylex_destroy(); 740 | } 741 | 742 | TypeModifiers get_variable_modifiers(const char* name) { 743 | TypeModifiers mods = {false, false, false, false, false}; // Default modifiers 744 | Variable *var = get_variable(name); 745 | if (var != NULL) { 746 | return var->modifiers; 747 | } 748 | return mods; // Return default modifiers if not found 749 | } 750 | -------------------------------------------------------------------------------- /lib/arena.c: -------------------------------------------------------------------------------- 1 | #include "arena.h" 2 | 3 | /* 4 | * @brref Create a new arena with a given size. 5 | * @param size The size of the arena. 6 | * @return The new arena. 7 | */ 8 | Region *region_new(size_t size) 9 | { 10 | size_t total_size = sizeof(Region) + sizeof(uintptr_t) * size; 11 | Region *region = (Region *)malloc(total_size); 12 | region->capacity = size; 13 | region->count = 0; 14 | region->next = NULL; 15 | return region; 16 | } 17 | 18 | /* 19 | * @brref free the region. 20 | * @param region The region to free. 21 | */ 22 | void region_free(Region *region) 23 | { 24 | free(region); 25 | } 26 | 27 | /* 28 | * @brief allocate memory from the arena. 29 | * @param arena The arena to allocate from. 30 | * @param size_bytes The size of the memory to allocate. 31 | * @return The pointer to the allocated memory. 32 | */ 33 | void *arena_alloc(Arena *arena, size_t size_bytes) 34 | { 35 | if(arena == NULL) 36 | { 37 | arena = (Arena*)malloc(sizeof(struct Arena)); 38 | arena->start = NULL; 39 | arena->end = NULL; 40 | } 41 | size_t size = (size_bytes + sizeof(uintptr_t) - 1)/sizeof(uintptr_t); 42 | if (arena->end == NULL) 43 | { 44 | assert(arena->start == NULL); 45 | size_t capacity = DEFAULT_REGION_SIZE; 46 | if (size > capacity) capacity = size; 47 | arena->end = region_new(capacity); 48 | arena->start = arena->end; 49 | } 50 | 51 | while (arena->end->count + size > arena->end->capacity && arena->end->next != NULL) 52 | { 53 | arena->end = arena->end->next; 54 | } 55 | 56 | if (arena->end->count + size > arena->end->capacity) 57 | { 58 | assert(arena->end->next == NULL); 59 | size_t cap = DEFAULT_REGION_SIZE; 60 | if (size > cap) cap = size; 61 | arena->end->next = region_new(cap); 62 | arena->end = arena->end->next; 63 | } 64 | 65 | void *result = &arena->end->data[arena->end->count]; 66 | arena->end->count += size; 67 | return result; 68 | } 69 | 70 | 71 | /* 72 | * @brief make a copy of a string in the arena. 73 | * @param arena The arena to allocate from. 74 | * @param str The string to copy. 75 | * @return The pointer to the copied string. 76 | */ 77 | char *arena_strdup(Arena *arena, const char *str) 78 | { 79 | size_t len = strlen(str); 80 | char *result = (char *)arena_alloc(arena, len + 1); 81 | memcpy(result, str, len); 82 | result[len] = '\0'; 83 | return result; 84 | } 85 | 86 | /* 87 | * @brief reset the arena. 88 | * @param arena The arena to reset. 89 | */ 90 | 91 | void arena_reset(Arena *arena) 92 | { 93 | arena->end = arena->start; 94 | while (arena->end->next != NULL) 95 | { 96 | Region *next = arena->end->next; 97 | region_free(arena->end); 98 | arena->end = next; 99 | } 100 | arena->end->count = 0; 101 | } 102 | 103 | /* 104 | * @brief free the arena. 105 | * @param arena The arena to free. 106 | */ 107 | void arena_free(Arena *arena) 108 | { 109 | if (arena == NULL) return; // Prevent NULL pointer dereference 110 | 111 | Region *current = arena->start; 112 | while (current != NULL) 113 | { 114 | Region *next = current->next; 115 | region_free(current); 116 | current = next; 117 | } 118 | 119 | // Clear the arena structure 120 | arena->start = NULL; 121 | arena->end = NULL; 122 | } 123 | 124 | -------------------------------------------------------------------------------- /lib/arena.h: -------------------------------------------------------------------------------- 1 | #ifndef AREANA_H 2 | #define AREANA_H 3 | 4 | #include "mem.h" 5 | 6 | // Default region size 4KB or 1 page of memory 7 | #define DEFAULT_REGION_SIZE (4 * 1024) 8 | 9 | typedef struct Region { 10 | struct Region *next; 11 | size_t count; 12 | size_t capacity; 13 | uintptr_t data[]; 14 | } Region; 15 | 16 | typedef struct Arena { 17 | Region *start, *end; 18 | } Arena; 19 | 20 | Region *region_new(size_t size); 21 | void region_free(Region *region); 22 | void *arena_alloc(Arena *arena, size_t size_bytes); 23 | char *arena_strdup(Arena *arena, const char *str); 24 | void arena_reset(Arena *arena); 25 | void arena_free(Arena *arena); 26 | #endif // AREANA_H 27 | -------------------------------------------------------------------------------- /lib/hm.c: -------------------------------------------------------------------------------- 1 | #include "../ast.h" 2 | #include "hm.h" 3 | #include "mem.h" 4 | 5 | /** 6 | * @brief Computes FNV-1a hash of the given data 7 | * @param key Pointer to the data to hash 8 | * @param len Length of the data in bytes 9 | * @return size_t Hash value 10 | * 11 | * Implements the FNV-1a non-cryptographic hash algorithm. 12 | * Uses the FNV offset basis of 2166136261 and FNV prime of 16777619. 13 | */ 14 | size_t fnv1a_hash(const void *key, size_t len) 15 | { 16 | const unsigned char *p = key; 17 | size_t h = 2166136261u; 18 | for (size_t i = 0; i < len; i++) 19 | { 20 | h ^= p[i]; 21 | h *= 16777619; 22 | } 23 | return h; 24 | } 25 | 26 | /** 27 | * @brief Compares two memory regions for equality 28 | * @param a Pointer to first memory region 29 | * @param b Pointer to second memory region 30 | * @param len Length of memory regions to compare in bytes 31 | * @return true if memory regions are identical, false otherwise 32 | * 33 | * Performs a byte-by-byte comparison of two memory regions. 34 | * Used for key comparison in the hashmap. 35 | */ 36 | bool key_equal(const void *a, const void *b, size_t len) 37 | { 38 | return memcmp(a, b, len) == 0; 39 | } 40 | 41 | /** 42 | * @brief Creates a new empty hashmap 43 | * @return HashMap* Pointer to newly allocated hashmap 44 | * 45 | * Allocates and initializes a new hashmap with default initial capacity. 46 | * The nodes array is zero-initialized. 47 | * Caller is responsible for freeing the returned hashmap using hm_free(). 48 | */ 49 | HashMap *hm_new() 50 | { 51 | HashMap *hm = SAFE_MALLOC(HashMap); 52 | hm->capacity = INIT_CAPACITY; 53 | hm->size = 0; 54 | hm->nodes = SAFE_CALLOC(hm->capacity, HashMapNode *); 55 | return hm; 56 | } 57 | 58 | /** 59 | * @brief Doubles the capacity of the hashmap 60 | * @param hm Pointer to hashmap to resize 61 | * 62 | * Allocates a new nodes array with double capacity and rehashes 63 | * all existing entries into the new array. 64 | * Used internally when load factor threshold is exceeded. 65 | */ 66 | void hm_resize(HashMap *hm) 67 | { 68 | size_t new_capacity = hm->capacity * 2; 69 | HashMapNode **new_nodes = SAFE_MALLOC_ARRAY(HashMapNode *, new_capacity); 70 | if (!new_nodes) 71 | return; // Add error check 72 | 73 | memset(new_nodes, 0, new_capacity * sizeof(HashMapNode *)); // Initialize to NULL 74 | 75 | // Rehash existing entries 76 | for (size_t i = 0; i < hm->capacity; i++) 77 | { 78 | if (hm->nodes[i]) // Check if slot is occupied 79 | { 80 | HashMapNode *node = hm->nodes[i]; 81 | size_t index = fnv1a_hash(node->key, node->key_size) % new_capacity; 82 | 83 | // Find next empty slot 84 | while (new_nodes[index] != NULL) 85 | { 86 | index = (index + 1) % new_capacity; 87 | } 88 | new_nodes[index] = node; 89 | } 90 | } 91 | 92 | // Free old array and update hashmap 93 | SAFE_FREE(hm->nodes); 94 | hm->nodes = new_nodes; 95 | hm->capacity = new_capacity; 96 | } 97 | 98 | /** 99 | * @brief Debug function to print hashmap contents 100 | * @param hm Pointer to hashmap to dump 101 | * 102 | * Prints key, variable name, and array flag for each entry. 103 | * Assumes values are Variable structs. 104 | * For debugging purposes only. 105 | */ 106 | void dump(HashMap *hm) 107 | { 108 | for (size_t i = 0; i < hm->capacity; i++) 109 | { 110 | if (hm->nodes[i]) 111 | { 112 | Variable *v = (Variable *)hm->nodes[i]->value; 113 | printf("key: %p, value: %s, is_array: %s\n", hm->nodes[i]->key, v->name, v->is_array ? "true" : "false"); 114 | } 115 | } 116 | } 117 | 118 | /** 119 | * @brief Retrieves a value from the hashmap 120 | * @param hm Pointer to the hashmap 121 | * @param key Pointer to the key 122 | * @param key_size Size of the key in bytes 123 | * @return void* Pointer to the value if found, NULL if not found 124 | * 125 | * Uses linear probing to handle collisions. 126 | * Returns NULL if key is not found. 127 | */ 128 | void *hm_get(HashMap *hm, const void *key, size_t key_size) 129 | { 130 | size_t start_index = fnv1a_hash(key, key_size) % hm->capacity; 131 | size_t index = start_index; 132 | 133 | do 134 | { 135 | HashMapNode *node = hm->nodes[index]; 136 | if (!node) 137 | return NULL; // Empty slot means key not found 138 | 139 | if (key_equal(node->key, key, key_size)) 140 | { 141 | return node->value; 142 | } 143 | 144 | index = (index + 1) % hm->capacity; 145 | } while (index != start_index); // Stop if we've checked every slot 146 | 147 | return NULL; 148 | } 149 | 150 | /** 151 | * @brief Inserts or updates a key-value pair in the hashmap 152 | * @param hm Pointer to the hashmap 153 | * @param key Pointer to the key 154 | * @param key_size Size of the key in bytes 155 | * @param value Pointer to the value 156 | * @param value_size Size of the value in bytes 157 | * 158 | * Creates a deep copy of both key and value. 159 | * Updates existing value if key already exists. 160 | * Resizes hashmap if load factor threshold would be exceeded. 161 | * Uses linear probing to handle collisions. 162 | */ 163 | void hm_put(HashMap *hm, const void *key, size_t key_size, void *value, size_t value_size) 164 | { 165 | if (hm->size >= hm->capacity * LOAD_FACTOR) 166 | { 167 | hm_resize(hm); 168 | } 169 | 170 | size_t index = fnv1a_hash(key, key_size) % hm->capacity; 171 | 172 | // Find slot or existing key 173 | while (hm->nodes[index]) 174 | { 175 | HashMapNode *node = hm->nodes[index]; 176 | if (key_equal(node->key, key, key_size)) 177 | { 178 | // Update existing value 179 | void *new_value = safe_malloc(value_size); 180 | if (!new_value) 181 | return; 182 | 183 | memcpy(new_value, value, value_size); 184 | SAFE_FREE(node->value); 185 | node->value = new_value; 186 | node->value_size = value_size; 187 | return; 188 | } 189 | index = (index + 1) % hm->capacity; 190 | } 191 | 192 | // Create new entry 193 | HashMapNode *node = SAFE_MALLOC(HashMapNode); 194 | if (!node) 195 | return; 196 | 197 | // Allocate and copy key 198 | node->key = safe_malloc(key_size); 199 | if (!node->key) 200 | { 201 | SAFE_FREE(node); 202 | return; 203 | } 204 | memcpy(node->key, key, key_size); 205 | node->key_size = key_size; 206 | 207 | // Allocate and copy value 208 | node->value = safe_malloc(value_size); 209 | if (!node->value) 210 | { 211 | SAFE_FREE(node->key); 212 | SAFE_FREE(node); 213 | return; 214 | } 215 | memcpy(node->value, value, value_size); 216 | node->value_size = value_size; 217 | 218 | hm->nodes[index] = node; 219 | hm->size++; 220 | } 221 | 222 | /** 223 | * @brief Frees all memory associated with a hashmap 224 | * @param hm Pointer to hashmap to free 225 | * 226 | * Frees all allocated node keys and values, 227 | * then frees the nodes array and hashmap struct itself. 228 | * After calling, the hashmap pointer should not be used. 229 | */ 230 | void hm_free(HashMap *hm) 231 | { 232 | for (size_t i = 0; i < hm->capacity; i++) 233 | { 234 | if (hm->nodes[i]) 235 | { 236 | SAFE_FREE(hm->nodes[i]->key); 237 | Variable *var = hm->nodes[i]->value; 238 | if (var != NULL) 239 | { 240 | if (var->is_array) 241 | { 242 | SAFE_FREE(var->value.array_data); 243 | } 244 | } 245 | 246 | SAFE_FREE(hm->nodes[i]->value); 247 | SAFE_FREE(hm->nodes[i]); 248 | } 249 | } 250 | SAFE_FREE(hm->nodes); 251 | SAFE_FREE(hm); 252 | } 253 | -------------------------------------------------------------------------------- /lib/hm.h: -------------------------------------------------------------------------------- 1 | /* hm.h */ 2 | 3 | #ifndef HM_H 4 | #define HM_H 5 | 6 | #include 7 | #include 8 | #include "../ast.h" 9 | 10 | #define INIT_CAPACITY 64 11 | #define LOAD_FACTOR 0.75 12 | 13 | typedef struct 14 | { 15 | void *key; 16 | void *value; 17 | size_t key_size; 18 | size_t value_size; 19 | } HashMapNode; 20 | 21 | typedef struct 22 | { 23 | HashMapNode **nodes; 24 | size_t size; 25 | size_t capacity; 26 | } HashMap; 27 | 28 | size_t fnv1a_hash(const void *key, size_t len); 29 | bool key_equal(const void *a, const void *b, size_t len); 30 | HashMap *hm_new(); 31 | void hm_resize(HashMap *hm); 32 | void dump(HashMap *hm); 33 | void *hm_get(HashMap *hm, const void *key, size_t key_size); 34 | void hm_put(HashMap *hm, const void *key, size_t key_size, void *value, size_t value_size); 35 | void hm_free(HashMap *hm); 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /lib/input.c: -------------------------------------------------------------------------------- 1 | /** 2 | * input.c - Implementation of input functions 3 | * 4 | * This file contains the definitions of the functions declared in input.h. 5 | */ 6 | 7 | #include "input.h" 8 | 9 | /** 10 | * Clears the remaining input in stdin to prevent it from affecting subsequent reads. 11 | */ 12 | void clear_stdin_buffer(void) 13 | { 14 | int c; 15 | while ((c = getchar()) != '\n' && c != EOF) 16 | ; 17 | } 18 | 19 | /** 20 | * Safely reads a single character value 21 | * 22 | * @param value Pointer to store the character value 23 | * @return input_status indicating success or type of error 24 | */ 25 | input_status input_char(char *value) 26 | { 27 | if (value == NULL) 28 | { 29 | return INPUT_NULL_PTR; 30 | } 31 | 32 | char buffer[2]; // One for the character, one for null terminator 33 | size_t chars_read; 34 | 35 | input_status status = input_string(buffer, sizeof(buffer), &chars_read); 36 | if (status != INPUT_SUCCESS) 37 | { 38 | return status; 39 | } 40 | 41 | // Check if we got exactly one character 42 | if (chars_read != 1) 43 | { 44 | return INPUT_INVALID_LENGTH; 45 | } 46 | 47 | *value = buffer[0]; 48 | return INPUT_SUCCESS; 49 | } 50 | 51 | /** 52 | * Safely reads a string with a maximum length 53 | * 54 | * @param buffer Pointer to the buffer where the string will be stored 55 | * @param buffer_size Size of the buffer in bytes 56 | * @param chars_read Pointer to store the number of characters read 57 | * @return input_status indicating success or type of error 58 | */ 59 | input_status input_string(char *buffer, size_t buffer_size, size_t *chars_read) 60 | { 61 | if (buffer == NULL || chars_read == NULL) 62 | { 63 | return INPUT_NULL_PTR; 64 | } 65 | 66 | if (buffer_size <= 1) 67 | { 68 | return INPUT_BUFFER_OVERFLOW; 69 | } 70 | 71 | // Clear errno before operation 72 | errno = 0; 73 | 74 | // Read input ensuring space for null terminator 75 | if (fgets(buffer, (int)buffer_size, stdin) == NULL) 76 | { 77 | if (ferror(stdin)) 78 | { 79 | clearerr(stdin); 80 | return INPUT_IO_ERROR; 81 | } 82 | // EOF reached 83 | buffer[0] = '\0'; 84 | *chars_read = 0; 85 | return INPUT_SUCCESS; 86 | } 87 | 88 | // Check if the input was truncated (no newline found) 89 | size_t len = strnlen(buffer, buffer_size); 90 | if(len == buffer_size && buffer[len - 1] != '\n') 91 | { 92 | clear_stdin_buffer(); 93 | return INPUT_BUFFER_OVERFLOW; 94 | } 95 | 96 | // Remove trailing newline if present 97 | if (len > 0 && buffer[len - 1] == '\n') 98 | { 99 | buffer[len - 1] = '\0'; 100 | len--; 101 | } 102 | 103 | *chars_read = len; 104 | return INPUT_SUCCESS; 105 | } 106 | 107 | /** 108 | * Safely reads an integer value 109 | * 110 | * @param value Pointer to store the integer value 111 | * @return input_status indicating success or type of error 112 | */ 113 | input_status input_int(int *value) 114 | { 115 | if (value == NULL) 116 | { 117 | return INPUT_NULL_PTR; 118 | } 119 | 120 | char buffer[32]; // Large enough for any integer 121 | size_t chars_read; 122 | 123 | input_status status = input_string(buffer, sizeof(buffer), &chars_read); 124 | if (status != INPUT_SUCCESS) 125 | { 126 | return status; 127 | } 128 | 129 | // Clear errno before conversion 130 | errno = 0; 131 | char *endptr; 132 | long result = strtol(buffer, &endptr, 10); 133 | 134 | // Check for conversion errors 135 | if (endptr == buffer || *endptr != '\0') 136 | { 137 | return INPUT_CONVERSION_ERROR; 138 | } 139 | 140 | // Check for overflow/underflow 141 | if (errno == ERANGE || result > INT_MAX || result < INT_MIN) 142 | { 143 | return INPUT_INTEGER_OVERFLOW; 144 | } 145 | 146 | *value = (int)result; 147 | return INPUT_SUCCESS; 148 | } 149 | 150 | /** 151 | * Safely reads an short value 152 | * 153 | * @param value Pointer to store the short value 154 | * @return input_status indicating success or type of error 155 | */ 156 | input_status input_short(short *value) 157 | { 158 | if (value == NULL) 159 | { 160 | return INPUT_NULL_PTR; 161 | } 162 | 163 | char buffer[32]; // Large enough for any integer 164 | size_t chars_read; 165 | 166 | input_status status = input_string(buffer, sizeof(buffer), &chars_read); 167 | if (status != INPUT_SUCCESS) 168 | { 169 | return status; 170 | } 171 | 172 | // Clear errno before conversion 173 | errno = 0; 174 | char *endptr; 175 | long result = strtol(buffer, &endptr, 10); 176 | 177 | // Check for conversion errors 178 | if (endptr == buffer || *endptr != '\0') 179 | { 180 | return INPUT_CONVERSION_ERROR; 181 | } 182 | 183 | // Check for overflow/underflow 184 | if (errno == ERANGE || result > SHRT_MAX || result < SHRT_MIN) 185 | { 186 | return INPUT_SHORT_OVERFLOW; 187 | } 188 | 189 | *value = (short)result; 190 | return INPUT_SUCCESS; 191 | } 192 | 193 | /** 194 | * Safely reads a float value 195 | * 196 | * @param value Pointer to store the float value 197 | * @return input_status indicating success or type of error 198 | */ 199 | input_status input_float(float *value) 200 | { 201 | if (value == NULL) 202 | { 203 | return INPUT_NULL_PTR; 204 | } 205 | 206 | char buffer[32]; // Large enough for any float 207 | size_t chars_read; 208 | 209 | input_status status = input_string(buffer, sizeof(buffer), &chars_read); 210 | if (status != INPUT_SUCCESS) 211 | { 212 | return status; 213 | } 214 | 215 | // Clear errno before conversion 216 | errno = 0; 217 | char *endptr; 218 | double result = strtod(buffer, &endptr); 219 | 220 | // Check for conversion errors 221 | if (endptr == buffer || *endptr != '\0') 222 | { 223 | return INPUT_CONVERSION_ERROR; 224 | } 225 | 226 | // Check for overflow/underflow 227 | if (errno == ERANGE) 228 | { 229 | return INPUT_FLOAT_OVERFLOW; 230 | } 231 | 232 | *value = result; 233 | return INPUT_SUCCESS; 234 | } 235 | 236 | /** 237 | * Safely reads a double value 238 | * 239 | * @param value Pointer to store the double value 240 | * @return input_status indicating success or type of error 241 | */ 242 | input_status input_double(double *value) 243 | { 244 | if (value == NULL) 245 | { 246 | return INPUT_NULL_PTR; 247 | } 248 | 249 | char buffer[64]; // Large enough for any double 250 | size_t chars_read; 251 | 252 | input_status status = input_string(buffer, sizeof(buffer), &chars_read); 253 | if (status != INPUT_SUCCESS) 254 | { 255 | return status; 256 | } 257 | 258 | // Clear errno before conversion 259 | errno = 0; 260 | char *endptr; 261 | double result = strtod(buffer, &endptr); 262 | 263 | // Check for conversion errors 264 | if (endptr == buffer || *endptr != '\0') 265 | { 266 | return INPUT_CONVERSION_ERROR; 267 | } 268 | 269 | // Check for overflow/underflow 270 | if (errno == ERANGE) 271 | { 272 | return INPUT_DOUBLE_OVERFLOW; 273 | } 274 | 275 | *value = result; 276 | return INPUT_SUCCESS; 277 | } 278 | -------------------------------------------------------------------------------- /lib/input.h: -------------------------------------------------------------------------------- 1 | /** 2 | * input.h - A safer implementation of scanf-like functionality 3 | * 4 | * This implementation focuses on safety against: 5 | * - Buffer overflows 6 | * - NULL pointer dereferences 7 | * - Memory leaks 8 | * - Integer overflows 9 | * - Format string vulnerabilities 10 | */ 11 | 12 | #ifndef INPUT_H 13 | #define INPUT_H 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | // Return codes for input functions 23 | typedef enum 24 | { 25 | INPUT_SUCCESS = 0, 26 | INPUT_NULL_PTR = -1, 27 | INPUT_INVALID_FORMAT = -2, 28 | INPUT_BUFFER_OVERFLOW = -3, 29 | INPUT_CONVERSION_ERROR = -4, 30 | INPUT_IO_ERROR = -5, 31 | INPUT_SHORT_OVERFLOW = -6, 32 | INPUT_INTEGER_OVERFLOW = -7, 33 | INPUT_FLOAT_OVERFLOW = -8, 34 | INPUT_DOUBLE_OVERFLOW = -9, 35 | INPUT_INVALID_LENGTH = -10, 36 | } input_status; 37 | 38 | /** 39 | * Clears the remaining input in stdin to prevent it from affecting subsequent reads. 40 | */ 41 | void clear_stdin_buffer(void); 42 | 43 | /** 44 | * Safely reads a single character value 45 | * 46 | * @param value Pointer to store the character value 47 | * @return input_status indicating success or type of error 48 | */ 49 | input_status input_char(char *value); 50 | 51 | /** 52 | * Safely reads a string with a maximum length 53 | * 54 | * @param buffer Pointer to the buffer where the string will be stored 55 | * @param buffer_size Size of the buffer in bytes 56 | * @param chars_read Pointer to store the number of characters read 57 | * @return input_status indicating success or type of error 58 | */ 59 | input_status input_string(char *buffer, size_t buffer_size, size_t *chars_read); 60 | 61 | /** 62 | * Safely reads an short value 63 | * 64 | * @param value Pointer to store the short value 65 | * @return input_status indicating success or type of error 66 | */ 67 | input_status input_short(short *value); 68 | 69 | /** 70 | * Safely reads an integer value 71 | * 72 | * @param value Pointer to store the integer value 73 | * @return input_status indicating success or type of error 74 | */ 75 | input_status input_int(int *value); 76 | 77 | /** 78 | * Safely reads a float value 79 | * 80 | * @param value Pointer to store the float value 81 | * @return input_status indicating success or type of error 82 | */ 83 | input_status input_float(float *value); 84 | 85 | /** 86 | * Safely reads a double value 87 | * 88 | * @param value Pointer to store the double value 89 | * @return input_status indicating success or type of error 90 | */ 91 | input_status input_double(double *value); 92 | 93 | #endif // INPUT_H 94 | -------------------------------------------------------------------------------- /lib/mem.c: -------------------------------------------------------------------------------- 1 | #include "mem.h" 2 | #include 3 | 4 | /** 5 | * @brief Retrieves the memory block header from a user pointer 6 | * 7 | * Given a pointer to the user data portion of an allocation made by safe_malloc, 8 | * calculates and returns a pointer to the associated mem_block_t header. 9 | * 10 | * @param ptr Pointer to examine, must have been returned by safe_malloc 11 | * @return mem_block_t* Pointer to the block header, or NULL if ptr is NULL 12 | * 13 | * @warning This function performs no validation - the caller must ensure ptr 14 | * was actually allocated by safe_malloc 15 | */ 16 | static inline mem_block_t *get_block_ptr(const void *ptr) 17 | { 18 | return ptr ? ((mem_block_t *)ptr - 1) : NULL; 19 | } 20 | 21 | /** 22 | * @brief Aligns a size value to the platform's memory alignment requirement 23 | * 24 | * Rounds up the given size to the next multiple of ALIGNMENT, with overflow checking. 25 | * 26 | * @param size Size value to align 27 | * @return size_t Aligned size value, or 0 if alignment would cause overflow 28 | * 29 | * @note The alignment value is platform-dependent and defined by ALIGNMENT macro 30 | */ 31 | size_t align_size(size_t size) 32 | { 33 | // Check for overflow before alignment 34 | if (size > MAX_ALLOC_SIZE - (ALIGNMENT - 1)) 35 | { 36 | return 0; // Indicate overflow 37 | } 38 | return (size + (ALIGNMENT - 1)) & ~(ALIGNMENT - 1); 39 | } 40 | 41 | /** 42 | * @brief Handles memory allocation failures with error reporting 43 | * 44 | * Reports allocation failures to stderr with size and error information, 45 | * sets errno to ENOMEM, and returns NULL. 46 | * 47 | * @param size The size of the failed allocation attempt 48 | * @return void* Always returns NULL 49 | * 50 | * @note Sets errno to ENOMEM 51 | */ 52 | void *handle_malloc_error(size_t size) 53 | { 54 | fprintf(stderr, "Memory allocation failed - Size: %zu, Error: %s\n", 55 | size, strerror(errno)); 56 | errno = ENOMEM; 57 | return NULL; 58 | } 59 | 60 | /** 61 | * @brief Safely allocates and zero-initializes memory with overflow checking 62 | * 63 | * Allocates and zero-initializes memory for an array with the following safety features: 64 | * - Overflow checking on element count and size 65 | * - Memory alignment 66 | * - Zero initialization 67 | * - Size tracking 68 | * - Guard pattern for corruption detection 69 | * 70 | * @param count Number of elements to allocate 71 | * @param size Size of each element in bytes 72 | * @return void* Pointer to allocated and zero-initialized memory, or NULL if: 73 | * - count or size is 0 74 | * - count * size > MAX_ALLOC_SIZE 75 | * - alignment would cause overflow 76 | * - system is out of memory 77 | * 78 | * @note Sets errno on failure 79 | */ 80 | void *safe_calloc(size_t count, size_t size) 81 | { 82 | if (count == 0 || size == 0) 83 | { 84 | return NULL; 85 | } 86 | 87 | // Check for overflow in multiplication 88 | if (count > MAX_ALLOC_SIZE / size) 89 | { 90 | return handle_malloc_error(count * size); 91 | } 92 | 93 | size_t total_size = count * size; 94 | if (total_size > MAX_ALLOC_SIZE) 95 | { 96 | return handle_malloc_error(total_size); 97 | } 98 | 99 | size_t aligned_size = align_size(total_size); 100 | if (aligned_size == 0 || aligned_size > MAX_ALLOC_SIZE) 101 | { 102 | return handle_malloc_error(total_size); 103 | } 104 | 105 | // Calculate total size needed including metadata 106 | size_t block_size = sizeof(mem_block_t) + aligned_size; 107 | if (block_size < total_size) 108 | { // Check for overflow 109 | return handle_malloc_error(total_size); 110 | } 111 | 112 | mem_block_t *block = malloc(block_size); 113 | if (block == NULL) 114 | { 115 | return handle_malloc_error(total_size); 116 | } 117 | 118 | block->guard = MEMORY_GUARD; 119 | block->size = aligned_size; 120 | memset(block->data, 0, aligned_size); 121 | 122 | return block->data; 123 | } 124 | 125 | 126 | /** 127 | * @brief Safely allocates memory with overflow checking and zero initialization 128 | * 129 | * Allocates memory with the following safety features: 130 | * - Overflow checking on size calculations 131 | * - Memory alignment 132 | * - Zero initialization 133 | * - Size tracking 134 | * - Guard pattern for corruption detection 135 | * 136 | * @param size Number of bytes to allocate 137 | * @return void* Pointer to allocated memory, or NULL if: 138 | * - size is 0 139 | * - size > MAX_ALLOC_SIZE 140 | * - alignment would cause overflow 141 | * - system is out of memory 142 | * 143 | * @note Sets errno on failure 144 | */ 145 | void *safe_malloc(size_t size) 146 | { 147 | if (size == 0) 148 | { 149 | return NULL; 150 | } 151 | 152 | if (size > MAX_ALLOC_SIZE) 153 | { 154 | return handle_malloc_error(size); 155 | } 156 | 157 | size_t aligned_size = align_size(size); 158 | if (aligned_size == 0 || aligned_size > MAX_ALLOC_SIZE) 159 | { 160 | return handle_malloc_error(size); 161 | } 162 | 163 | // Calculate total size needed including metadata 164 | size_t total_size = sizeof(mem_block_t) + aligned_size; 165 | if (total_size < size) 166 | { // Check for overflow 167 | return handle_malloc_error(size); 168 | } 169 | 170 | mem_block_t *block = malloc(total_size); 171 | if (block == NULL) 172 | { 173 | return handle_malloc_error(size); 174 | } 175 | 176 | block->guard = MEMORY_GUARD; 177 | block->size = aligned_size; 178 | memset(block->data, 0, aligned_size); 179 | 180 | return block->data; 181 | } 182 | 183 | /** 184 | * @brief Safely allocates an array with overflow checking 185 | * 186 | * Allocates memory for an array of elements, checking for multiplication 187 | * overflow in the size calculation. 188 | * 189 | * @param nmemb Number of elements to allocate 190 | * @param size Size of each element 191 | * @return void* Pointer to allocated array, or NULL if: 192 | * - nmemb * size would overflow 193 | * - allocation fails for any reason 194 | * 195 | * @note Equivalent to safe_malloc(nmemb * size) but with overflow check 196 | */ 197 | void *safe_malloc_array(size_t nmemb, size_t size) 198 | { 199 | // Check multiplication overflow 200 | if (nmemb > 0 && size > MAX_ALLOC_SIZE / nmemb) 201 | { 202 | return handle_malloc_error(nmemb * size); 203 | } 204 | return safe_malloc(nmemb * size); 205 | } 206 | 207 | /** 208 | * @brief Validates if a pointer was allocated by safe_malloc 209 | * 210 | * Checks if a pointer appears to have been allocated by safe_malloc by 211 | * verifying the presence and validity of the guard pattern. 212 | * 213 | * @param ptr Pointer to validate 214 | * @return int 1 if pointer appears valid, 0 otherwise 215 | * 216 | * @warning A matching guard pattern does not guarantee the pointer is valid, 217 | * but a non-matching pattern guarantees it is invalid 218 | */ 219 | int is_safe_malloc_ptr(const void *ptr) 220 | { 221 | if (!ptr) 222 | return 0; 223 | mem_block_t *block = get_block_ptr(ptr); 224 | return block->guard == MEMORY_GUARD; 225 | } 226 | 227 | /** 228 | * @brief Safely frees memory allocated by safe_malloc 229 | * 230 | * Frees memory with additional safety features: 231 | * - Validates the pointer was allocated by safe_malloc 232 | * - Wipes memory contents before freeing 233 | * - Sets pointer to NULL after freeing 234 | * - Handles NULL pointers safely 235 | * 236 | * @param ptr Address of pointer to free. Must not be NULL. 237 | * Points to memory allocated by safe_malloc. 238 | * 239 | * @note If ptr or *ptr is NULL, function returns without action 240 | * @note If pointer appears invalid, prints warning and returns without freeing 241 | */ 242 | void safe_free(void **ptr, const char* file, int line, const char* func) 243 | { 244 | if (!ptr || !*ptr) 245 | { 246 | return; 247 | } 248 | 249 | mem_block_t *block = get_block_ptr(*ptr); 250 | if (!block || block->guard != MEMORY_GUARD) 251 | { 252 | fprintf(stderr, "Warning: Attempt to free invalid/corrupted pointer, %s, %d, %s\n", 253 | file, line, func); 254 | return; 255 | } 256 | 257 | // Clear user data 258 | memset(block->data, 0, block->size); 259 | // Clear metadata 260 | block->guard = 0; 261 | block->size = 0; 262 | 263 | free(block); 264 | *ptr = NULL; 265 | } 266 | 267 | /** 268 | * @brief Safely copies memory between buffers with extensive validation 269 | * 270 | * Copies memory with the following safety checks: 271 | * - NULL pointer validation 272 | * - Size limit validation 273 | * - Destination buffer size validation 274 | * - Buffer overlap detection 275 | * - Safe_malloc pointer validation 276 | * 277 | * @param dest Destination buffer (must be from safe_malloc) 278 | * @param src Source buffer 279 | * @param n Number of bytes to copy 280 | * @return void* Pointer to destination buffer, or NULL if: 281 | * - dest or src is NULL 282 | * - n > MAX_ALLOC_SIZE 283 | * - dest not from safe_malloc 284 | * - dest buffer too small 285 | * - buffers overlap 286 | * 287 | * @note Sets errno on failure 288 | */ 289 | void *safe_memcpy(void *dest, const void *src, size_t n) 290 | { 291 | if (!dest || !src) 292 | { 293 | errno = EINVAL; 294 | return NULL; 295 | } 296 | 297 | if (n == 0) 298 | { 299 | return dest; 300 | } 301 | 302 | if (n > MAX_ALLOC_SIZE) 303 | { 304 | errno = ERANGE; 305 | return NULL; 306 | } 307 | 308 | // Verify dest is from safe_malloc 309 | if (!is_safe_malloc_ptr(dest)) 310 | { 311 | errno = EINVAL; 312 | return NULL; 313 | } 314 | 315 | mem_block_t *block = get_block_ptr(dest); 316 | if (block->size < n) 317 | { 318 | errno = ERANGE; 319 | return NULL; 320 | } 321 | 322 | // Check for buffer overlap 323 | if ((src < dest && (uintptr_t)src + n > (uintptr_t)dest) || 324 | (dest < src && (uintptr_t)dest + n > (uintptr_t)src)) 325 | { 326 | errno = EINVAL; 327 | return NULL; 328 | } 329 | 330 | return memcpy(dest, src, n); 331 | } 332 | 333 | /** 334 | * @brief Safely duplicates a string with extensive validation 335 | * 336 | * Creates a new string in safe_malloc'd memory with the following features: 337 | * - NULL pointer checking 338 | * - Proper size calculation with overflow detection 339 | * - Secure string copying 340 | * - Zero initialization 341 | * 342 | * @param str String to duplicate 343 | * @return char* Pointer to new string, or NULL if: 344 | * - str is NULL 345 | * - memory allocation fails 346 | * - string length exceeds MAX_ALLOC_SIZE 347 | * 348 | * @note Sets errno on failure 349 | * @note Returned string must be freed with safe_free 350 | */ 351 | char *safe_strdup(const char *str) 352 | { 353 | if (!str) 354 | { 355 | errno = EINVAL; 356 | return NULL; 357 | } 358 | 359 | size_t len = strlen(str) + 1; 360 | char *new_str = safe_malloc(len); 361 | if (new_str) 362 | { 363 | memcpy(new_str, str, len); 364 | } 365 | return new_str; 366 | } 367 | 368 | 369 | -------------------------------------------------------------------------------- /lib/mem.h: -------------------------------------------------------------------------------- 1 | /* mem.h */ 2 | 3 | #ifndef MEM_H 4 | #define MEM_H 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | // Maximum allocation size - helps prevent integer overflow 14 | #define MAX_ALLOC_SIZE ((size_t)-1 >> 1) 15 | 16 | // Alignment requirement for the platform 17 | #define ALIGNMENT sizeof(void *) 18 | 19 | // Magic number to detect buffer overruns and validate pointers 20 | #define MEMORY_GUARD 0xDEADBEEFDEADBEEFULL 21 | 22 | typedef struct 23 | { 24 | size_t guard; // Memory guard to detect corruption 25 | size_t size; // Size of allocated block 26 | char data[]; // Flexible array member for user data 27 | } mem_block_t; 28 | 29 | void *handle_malloc_error(size_t size); 30 | size_t align_size(size_t size); 31 | void *safe_malloc(size_t size); 32 | void *safe_malloc_array(size_t nmemb, size_t size); 33 | void safe_free(void **ptr, const char *file, int line, const char *func); 34 | void *safe_memcpy(void *dest, const void *src, size_t n); 35 | char *safe_strdup(const char *str); 36 | int is_safe_malloc_ptr(const void *ptr); 37 | void *safe_calloc(size_t count, size_t size); 38 | 39 | // Convenience macro for type-safe allocation 40 | #define SAFE_MALLOC(type) ((type *)safe_malloc(sizeof(type))) 41 | #define SAFE_CALLOC(c, type) ((type *)safe_calloc((c), sizeof(type))) 42 | #define SAFE_MALLOC_ARRAY(type, n) ((type *)safe_malloc_array((n), sizeof(type))) 43 | // Convenience macro for safer free usage 44 | #define SAFE_FREE(ptr) safe_free((void **)&(ptr), __FILE__, __LINE__, __func__) 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /run_valgrind_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | for f in test_cases/*.brainrot; do 4 | echo "Running Valgrind on $f..." 5 | base=$(basename "$f" .brainrot) 6 | 7 | case "$base" in 8 | slorp_int) input="42" ;; 9 | slorp_short) input="69" ;; 10 | slorp_float) input="3.14" ;; 11 | slorp_double) input="3.141592" ;; 12 | slorp_char) input="c" ;; 13 | slorp_string) input="skibidi bop bop yes yes" ;; 14 | *) input="" ;; 15 | esac 16 | 17 | if [[ -n "$input" ]]; then 18 | echo "$input" | valgrind --leak-check=full --error-exitcode=100 ./brainrot "$f" 19 | else 20 | valgrind --track-origins=yes --leak-check=full --error-exitcode=100 ./brainrot "$f" 21 | fi 22 | 23 | valgrind_exit_code=$? # Capture only valgrind’s exit code 24 | 25 | if [[ $valgrind_exit_code -eq 100 ]]; then 26 | echo "Valgrind detected memory issues in $f" 27 | exit 1 28 | fi 29 | 30 | echo 31 | done 32 | 33 | -------------------------------------------------------------------------------- /test_cases/add_two_numbers.brainrot: -------------------------------------------------------------------------------- 1 | rizz numba_go_up(rizz a, rizz b) { 2 | bussin a + b; 3 | } 4 | 5 | skibidi main { 6 | yappin("%d\n", numba_go_up(1, 2)); 7 | bussin 0; 8 | } 9 | -------------------------------------------------------------------------------- /test_cases/array_initialization.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | rizz int_array[3] = {1,2,3}; 3 | rizz int_array1[3] = {1,2,3}; 4 | 5 | flex (rizz i = 0; i < 3; i = i + 1) { 6 | yapping("%d", int_array[i]); 7 | } 8 | 9 | rizz n = maxxing(int_array1) / maxxing(int_array1[0]); 10 | 11 | flex (rizz i = 0; i < n; i = i + 1) { 12 | yapping("%d", int_array1[i]); 13 | } 14 | 15 | 16 | bussin 0; 17 | } 18 | -------------------------------------------------------------------------------- /test_cases/bool_array.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | cap bool_array[3]; 3 | rizz i; 4 | 5 | bool_array[0] = W; 6 | bool_array[1] = L; 7 | bool_array[2] = W; 8 | 9 | flex (i = 0; i < 3; i = i + 1) { 10 | yapping("%b", bool_array[i]); 11 | } 12 | 13 | bussin 0; 14 | } -------------------------------------------------------------------------------- /test_cases/boolean.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | cap nocap = W; 3 | 4 | edgy(nocap) { 5 | yapping("It's valid!"); 6 | } 7 | 8 | nocap = W && L; 9 | yapping("nocap: %b", nocap); 🚽 use %b identifier for boolean types 10 | nocap = W || L; 11 | yapping("nocap: %b", nocap); 12 | } 13 | -------------------------------------------------------------------------------- /test_cases/char.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | yap char = 'c'; 3 | yapping("%c", char); 4 | bussin 0; 5 | } 6 | -------------------------------------------------------------------------------- /test_cases/char_array.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | yap a[4]; 3 | rizz i; 4 | 5 | a[0] = 'r'; 6 | a[1] = 'i'; 7 | a[2] = 'z'; 8 | a[3] = 'z'; 9 | 10 | flex (i = 0; i < 4; i = i + 1) { 11 | yappin("%c", a[i]); 12 | } 13 | 14 | bussin 0; 15 | } 16 | -------------------------------------------------------------------------------- /test_cases/chill.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | yapping("I'll chill for a 2 seconds ..."); 3 | chill(2); 🚽 sleep for 2 seconds 4 | yapping("Ok imma head out"); 5 | bussin 0; 6 | } 7 | -------------------------------------------------------------------------------- /test_cases/circle_area.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | 🚽 Calculate pi * r^2 3 | chad pi = 3.141592f; 4 | chad r = 5.0f; 5 | chad area = pi * r * r; 🚽 Area of a circle 6 | yappin("%.3f\n", area); 7 | bussin 0; 8 | } 9 | -------------------------------------------------------------------------------- /test_cases/circle_area_double.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | 🚽 Calculate pi * r^2 3 | gigachad pi = 3.141592; 4 | gigachad r = 5.0; 5 | gigachad area = pi * r * r; 🚽 Area of a circle 6 | yappin("%lf\n", area); 7 | bussin 0; 8 | } 9 | -------------------------------------------------------------------------------- /test_cases/comparison_edge_case.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | chad epsilon = 1.0e-6; 3 | chad a = 1.0; 4 | chad b = 0.9999999; 5 | edgy (a - b < epsilon) { 6 | yappin("%d\n", W); 🚽 Should output: 1 7 | } amogus { 8 | yappin("%d\n", L); 9 | } 10 | bussin 0; 11 | } 12 | -------------------------------------------------------------------------------- /test_cases/const.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | deadass rizz i = 1; 3 | yapping("%d", i); 4 | 🚽 i = 2; this will raise an error if uncommented 5 | yapping("%d", i); 6 | bussin 0; 7 | } 8 | -------------------------------------------------------------------------------- /test_cases/division_by_zero.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | rizz i = 0; 3 | yapping("%d\n", 1 / i); 🚽 Should output: Error: Division by zero 4 | bussin 0; 5 | } 6 | -------------------------------------------------------------------------------- /test_cases/division_edge_cases.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | chad f = 0.0; 3 | gigachad d = 0.0; 4 | rizz i = 0; 5 | yappin("%f\n", 1.0 / f); 🚽 Should output: inf 6 | yappin("%f\n", f / f); 🚽 Should output: nan 7 | yappin("%f\n", d / 0.0); 🚽 Should output: inf 8 | bussin 0; 9 | } 10 | -------------------------------------------------------------------------------- /test_cases/do-while.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | rizz a = 0; 3 | rizz b = 1; 4 | 5 | mewing { 6 | yapping("%d",a); 7 | rizz temp = a + b; 8 | a = b; 9 | b = temp; 10 | } goon (a < 10); 11 | bussin 0; 12 | } 13 | -------------------------------------------------------------------------------- /test_cases/double_array.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | gigachad double_array[3]; 3 | 4 | double_array[0] = 3.14L; 5 | double_array[1] = 3.1415L; 6 | double_array[2] = 3.141592L; 7 | 8 | rizz i; 9 | flex (i = 0; i < 3; i = i + 1) { 10 | yapping("%f", double_array[i]); 11 | } 12 | 13 | bussin 0; 14 | } 15 | -------------------------------------------------------------------------------- /test_cases/double_vs_float.brainrot: -------------------------------------------------------------------------------- 1 | 🚽 TODO: disabled test. returns 1.0 instead of 0.0. Needs further investigation. 2 | skibidi main { 3 | chad f = 1.0e8f; 4 | gigachad d = 1.0e8; 5 | chad f1 = f + 1.0f; 6 | gigachad d1 = d + 1.0; 7 | yappin("%.1f %.1f\n", f1 - f, d1 - d); 8 | 🚽 Should output: 0.0 1.0 9 | 🚽 (float loses precision, double maintains it) 10 | bussin 0; 11 | } 12 | -------------------------------------------------------------------------------- /test_cases/fib.brainrot: -------------------------------------------------------------------------------- 1 | rizz fib(rizz n) { 2 | edgy (n <= 1) { 3 | bussin n; 4 | } 5 | bussin fib(n -1) + fib(n -2); 6 | } 7 | 8 | skibidi main { 9 | rizz result = fib(10); 10 | yapping("%d",result); 11 | bussin 0; 12 | } 13 | -------------------------------------------------------------------------------- /test_cases/fizz_buzz.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | nut rizz i; 3 | flex (i = 1; i <= 10; i = i + 1){ 4 | edgy ( (i % 15) == 0 ) { 5 | yapping("FizzBuzz"); 6 | } amogus edgy ( (i % 3) == 0 ) { 7 | yapping("Fizz"); 8 | } amogus edgy ( (i % 5) == 0 ) { 9 | yapping("Buzz"); 10 | } amogus { 11 | yapping("%d", i); 12 | } 13 | } 14 | bussin 0; 15 | } 16 | -------------------------------------------------------------------------------- /test_cases/fizz_buzz_short.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | smol i; 3 | flex (i = 1; i <= 10; i++){ 4 | edgy ( (i % 15) == 0 ) { 5 | yapping("FizzBuzz"); 6 | } amogus edgy ( (i % 3) == 0 ) { 7 | yapping("Fizz"); 8 | } amogus edgy ( (i % 5) == 0 ) { 9 | yapping("Buzz"); 10 | } amogus { 11 | yapping("%d", i); 12 | } 13 | } 14 | bussin 0; 15 | } 16 | -------------------------------------------------------------------------------- /test_cases/float.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | chad pi = 3.141592; 3 | yapping("%f", pi); 4 | bussin 0; 5 | } 6 | -------------------------------------------------------------------------------- /test_cases/float_array.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | chad float_array[3]; 3 | 4 | float_array[0] = 3.14f; 5 | float_array[1] = 3.1415f; 6 | float_array[2] = 3.141592f; 7 | 8 | rizz i; 9 | flex (i = 0; i < 3; i = i + 1) { 10 | yapping("%f", float_array[i]); 11 | } 12 | 13 | bussin 0; 14 | } 15 | -------------------------------------------------------------------------------- /test_cases/float_precision.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | chad tiny = 1.175494351e-38; 🚽 FLT_MIN 3 | chad big = 3.402823466e+38; 🚽 FLT_MAX 4 | chad sum = big + tiny; 5 | yappin("%f\n", sum - big); 🚽 Should output: 0.000000 (precision loss) 6 | bussin 0; 7 | } 8 | -------------------------------------------------------------------------------- /test_cases/for_loop.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | rizz i; 3 | flex (i = 0; i < 6; i = i + 1) { 4 | yapping("Skibidi toilet"); 5 | } 6 | bussin 0; 7 | } 8 | -------------------------------------------------------------------------------- /test_cases/for_loop_break.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | rizz i; 3 | flex (i = 0; i < 6; i = i + 1) { 4 | yapping("Skibidi toilet"); 5 | edgy (i == 2) { 6 | yapping("AHHHHHHHHHHHHHHH"); 7 | bruh; 8 | } 9 | } 10 | bussin 0; 11 | } 12 | -------------------------------------------------------------------------------- /test_cases/func-modifier.brainrot: -------------------------------------------------------------------------------- 1 | rizz modifier_test(deadass rizz a) { 2 | a = 3; 3 | bussin a; 4 | } 5 | 6 | skibidi main { 7 | modifier_test(6); 8 | bussin 0; 9 | } 10 | -------------------------------------------------------------------------------- /test_cases/func_scope.brainrot: -------------------------------------------------------------------------------- 1 | rizz inner() 2 | { 3 | rizz x = 10; 4 | yapping("from inner %d",x); 5 | bussin 0; 6 | } 7 | 8 | rizz outer(rizz n) { 9 | rizz x = 4; 10 | inner(); 11 | yapping("from outer %d",x); 12 | bussin x; 13 | } 14 | 15 | skibidi main { 16 | outer(10); 17 | bussin 0; 18 | } 19 | -------------------------------------------------------------------------------- /test_cases/hello_world.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | yappin("Hello, World!\n"); 3 | bussin 0; 4 | } 5 | -------------------------------------------------------------------------------- /test_cases/inc-dec.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | flex(rizz i = 0; i < 10; ++i) { 3 | yapping("%d", i); 4 | } 5 | 6 | 7 | flex(rizz i = 10; i > 0; --i){ 8 | yapping("%d", i); 9 | } 10 | bussin 0; 11 | } 12 | -------------------------------------------------------------------------------- /test_cases/int.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | rizz num1 = 3; 3 | rizz num2 = 7; 4 | yapping("%d", num1 + num2); 5 | num1 = -4; 6 | num2 = 9; 7 | yapping("%d", num1 + num2); 8 | 9 | num1 = 9; 10 | num2 = 6; 11 | yapping("%d", num1 - num2); 12 | num1 = 6; 13 | num2 = 9; 14 | yapping("%d", num1 - num2); 15 | 16 | num1 = 5; 17 | num2 = 4; 18 | yapping("%d", num1 * num2); 19 | num1 = 5; 20 | num2 = -4; 21 | yapping("%d", num1 * num2); 22 | 23 | num1 = 14; 24 | num2 = 7; 25 | yapping("%d", num1 / num2); 26 | num1 = 12; 27 | num2 = 7; 28 | yapping("%d", num1 / num2); 29 | 30 | num1 = 8; 31 | num2 = 3; 32 | yapping("%d", num1 % num2); 33 | num1 = -8; 34 | num2 = 3; 35 | yapping("%d", num1 % num2); 36 | 37 | 38 | bussin 0; 39 | } 40 | -------------------------------------------------------------------------------- /test_cases/int_array.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | rizz int_array[3]; 3 | rizz i; 4 | 5 | flex (i = 1; i < 4; i = i + 1) { 6 | int_array[i-1] = i; 7 | } 8 | 9 | flex (i = 0; i < 3; i = i + 1) { 10 | yapping("%d", int_array[i]); 11 | } 12 | 13 | bussin 0; 14 | } 15 | -------------------------------------------------------------------------------- /test_cases/integer_overflow.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | rizz max = 2147483647; 🚽 INT_MAX 3 | rizz min = -2147483648; 🚽 INT_MIN 4 | yappin("%d\n", max + 1); 🚽 Should output: -2147483648 (overflow) 5 | yappin("%d\n", min - 1); 🚽 Should output: 2147483647 (underflow) 6 | bussin 0; 7 | } 8 | -------------------------------------------------------------------------------- /test_cases/is_prime.brainrot: -------------------------------------------------------------------------------- 1 | cap is_prime(rizz n) { 2 | edgy(n < 2) { 3 | bussin L; 4 | } 5 | flex(rizz i = 2; i * i <= n; i++) { 6 | edgy(n % i == 0) { 7 | bussin L; 8 | } 9 | } 10 | bussin W; 11 | 12 | } 13 | 14 | skibidi main { 15 | yappin("%b\n", is_prime(7)); 16 | bussin 0; 17 | } 18 | 19 | -------------------------------------------------------------------------------- /test_cases/max_gigachad.brainrot: -------------------------------------------------------------------------------- 1 | gigachad gigamax(gigachad a, gigachad b) { 2 | gigachad max = 0; 3 | edgy (a > b) { 4 | max = a; 5 | } amogus{ 6 | max = b; 7 | } 8 | bussin max; 9 | } 10 | 11 | skibidi main { 12 | yappin("%f\n", gigamax(5, 2)); 13 | bussin 0; 14 | } 15 | -------------------------------------------------------------------------------- /test_cases/mixed_types.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | chad f = 3.14; 3 | gigachad d = 3.14; 4 | rizz i = 42; 5 | nonut rizz u = 42; 6 | yappin("%f\n", f * i); 🚽 Should output: 131.880000 7 | yappin("%f\n", d * i); 🚽 Should output: 131.880000 8 | bussin 0; 9 | } 10 | -------------------------------------------------------------------------------- /test_cases/modulo.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | nonut rizz num1 = 3459145475; 3 | nonut rizz num2 = num1 % 3; 4 | yapping("%u", num2); 5 | } 6 | -------------------------------------------------------------------------------- /test_cases/modulo_edge_case.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | rizz a = -5; 3 | rizz b = 3; 4 | yappin("%d\n", a % b); 🚽 Should output: -2 5 | nonut rizz x = 5; 6 | nonut rizz y = 3; 7 | yappin("%u\n", x % y); 🚽 Should output: 2 8 | bussin 0; 9 | } 10 | -------------------------------------------------------------------------------- /test_cases/mul_two_numbers.brainrot: -------------------------------------------------------------------------------- 1 | chad mul(chad a, rizz b) { 2 | bussin a * b; 3 | } 4 | 5 | skibidi main { 6 | yappin("%f\n", mul(5.7, 2)); 7 | bussin 0; 8 | } 9 | -------------------------------------------------------------------------------- /test_cases/multi_array.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | rizz arr[2][2]; 3 | 4 | arr[0][0] = 1; 5 | arr[0][1] = 2; 6 | arr[1][0] = 3; 7 | arr[1][1] = 4; 8 | 9 | flex (rizz i = 0; i < 2; i = i + 1) { 10 | flex (rizz j = 0; j < 2; j = j + 1) { 11 | yapping("%d", arr[i][j]); 12 | } 13 | } 14 | 15 | bussin 0; 16 | } 17 | -------------------------------------------------------------------------------- /test_cases/nest-loop.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | 3 | flex(rizz i =0; i <= 3; i++){ 4 | yapping("%d",i); 5 | 6 | rizz j = 0; 7 | goon(j <=3){ 8 | yapping("goon"); 9 | edgy(j == 2){ 10 | yapping("break goon %d",j); 11 | } 12 | j++; 13 | } 14 | 15 | edgy( i ==2){ 16 | yapping("break flex"); 17 | bruh; 18 | } 19 | } 20 | 21 | bussin 0; 22 | } 23 | -------------------------------------------------------------------------------- /test_cases/next-prime.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | rizz n = 7; 3 | rizz num = n + 1; 4 | 5 | mewing { 6 | cap is_prime = W; 7 | flex (rizz i = 2; i * i <= num; i++) { 8 | edgy (num % i == 0) { 9 | is_prime = L; 10 | bruh; 11 | } 12 | } 13 | edgy (is_prime) { 14 | bruh; 15 | } 16 | num++; 17 | } goon (W); 18 | 19 | yapping("%d", num); 20 | 21 | bussin 0; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /test_cases/output_error.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | edgy (1) { 3 | baka("you sussy baka!"); 4 | } 5 | bussin 0; 6 | } 7 | -------------------------------------------------------------------------------- /test_cases/rage_quit.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | rizz i = 2; 3 | 4 | edgy (i == 2) { 5 | ragequit(0); 6 | } amogus { 7 | ragequit(69); 8 | } 9 | bussin 0; 10 | } 11 | -------------------------------------------------------------------------------- /test_cases/scientific_notation.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | chad f = 1.23e-7; 3 | gigachad d = 1.23e-15; 4 | yappin("%e\n", f); 🚽 Should output: 1.230000e-07 5 | yappin("%e\n", d); 🚽 Should output: 1.230000e-15 6 | bussin 0; 7 | } 8 | -------------------------------------------------------------------------------- /test_cases/short_array.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | smol short_array[3]; 3 | rizz i; 4 | 5 | flex (i = 1; i < 4; i = i + 1) { 6 | short_array[i-1] = i; 7 | } 8 | 9 | flex (i = 0; i < 3; i = i + 1) { 10 | yapping("%d", short_array[i]); 11 | } 12 | 13 | bussin 0; 14 | } -------------------------------------------------------------------------------- /test_cases/sizeof.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | smol u = 69; 3 | chad v = 3.1415f; 4 | gigachad w = 3.141592; 5 | rizz x = 42; 6 | nonut rizz y = 100; 7 | cap z = W; 8 | rizz arr[3] = {1,2,3}; 9 | 10 | rizz size1 = maxxing(x); 11 | rizz size2 = maxxing(y); 12 | rizz size3 = maxxing(z); 13 | rizz size4 = maxxing(u); 14 | rizz size5 = maxxing(v); 15 | rizz size6 = maxxing(w); 16 | rizz size7 = maxxing(arr); 17 | 18 | yapping("%lu", size1); 19 | yapping("%lu", size2); 20 | yapping("%lu", size3); 21 | yapping("%lu", size4); 22 | yapping("%lu", size5); 23 | yapping("%lu", size6); 24 | yapping("%lu", size7); 25 | } 26 | -------------------------------------------------------------------------------- /test_cases/slorp_char.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | yap chr; 3 | slorp(chr); 4 | yapping("You typed: %c", chr); 5 | bussin 0; 6 | } 7 | -------------------------------------------------------------------------------- /test_cases/slorp_double.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | gigachad num; 3 | slorp(num); 4 | yapping("You typed: %f", num); 5 | bussin 0; 6 | } 7 | -------------------------------------------------------------------------------- /test_cases/slorp_float.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | chad num; 3 | slorp(num); 4 | yapping("You typed: %f", num); 5 | bussin 0; 6 | } 7 | -------------------------------------------------------------------------------- /test_cases/slorp_int.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | rizz num; 3 | slorp(num); 4 | yapping("You typed: %d", num); 5 | bussin 0; 6 | } 7 | -------------------------------------------------------------------------------- /test_cases/slorp_short.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | smol num; 3 | slorp(num); 4 | yapping("You typed: %d", num); 5 | bussin 0; 6 | } 7 | -------------------------------------------------------------------------------- /test_cases/slorp_string.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | yap string[32]; 3 | slorp(string); 4 | yapping("You typed: %s", string); 5 | bussin 0; 6 | } 7 | -------------------------------------------------------------------------------- /test_cases/switch_case.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | schizo rizz choice = 2; 3 | ohio (choice) { 4 | sigma rule 1: 5 | yapping("You chose 1, that's pretty sus!"); 6 | bruh; 7 | sigma rule 2: 8 | yapping("You chose 2, gigachad move!"); 9 | bruh; 10 | sigma rule 3: 11 | yapping("You chose 3, totally based!"); 12 | bruh; 13 | based: 14 | yapping("You chose something unexpected, cringe!"); 15 | bruh; 16 | } 17 | bussin 0; 18 | } 19 | -------------------------------------------------------------------------------- /test_cases/type_conversion.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | chad huge_float = 3.4e38; 3 | rizz converted = huge_float; 🚽 Should be INT_MAX or error 4 | gigachad precise = 123456789.123456789; 5 | chad less_precise = precise; 🚽 Precision loss 6 | yappin("%f\n", less_precise); 🚽 Should output: 123456789.000000 7 | bussin 0; 8 | } 9 | -------------------------------------------------------------------------------- /test_cases/uint.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | nonut rizz num1 = 3; 3 | nonut rizz num2 = 7; 4 | yapping("%u", num1 + num2); 5 | num1 = 447863; 6 | num2 = 9483874; 7 | yapping("%u", num1 + num2); 8 | 9 | num1 = 9; 10 | num2 = 6; 11 | yapping("%u", num1 - num2); 12 | num1 = 647238974; 13 | num2 = 9; 14 | yapping("%u", num1 - num2); 15 | 16 | num1 = 5; 17 | num2 = 4; 18 | yapping("%u", num1 * num2); 19 | num1 = 55348; 20 | num2 = 4434; 21 | yapping("%u", num1 * num2); 22 | 23 | num1 = 14; 24 | num2 = 7; 25 | yapping("%u", num1 / num2); 26 | num1 = 12; 27 | num2 = 7; 28 | yapping("%u", num1 / num2); 29 | 30 | num1 = 8; 31 | num2 = 3; 32 | yapping("%u", num1 % num2); 33 | num1 = 437473348; 34 | num2 = 3; 35 | yapping("%u", num1 % num2); 36 | 37 | 38 | bussin 0; 39 | } 40 | -------------------------------------------------------------------------------- /test_cases/unsigned_integer_wrap.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | nonut rizz big = 4294967295; 🚽 UINT_MAX 3 | yappin("%u\n", big + 1); 🚽 Should output: 0 (wrap around) 4 | yappin("%u\n", big * 2); 🚽 Should output: 4294967294 (wrap around) 5 | bussin 0; 6 | } 7 | -------------------------------------------------------------------------------- /test_cases/while_loop.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | nonut rizz i = 1; 3 | goon (i < 5) { 4 | yapping("AAAAAH A GOONIN LOOP"); 5 | yapping("%d", i); 6 | i++; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test_cases/while_loop_break.brainrot: -------------------------------------------------------------------------------- 1 | skibidi main { 2 | nonut rizz i = 1; 3 | goon (i < 5) { 4 | yapping("AAAAAH A GOONIN LOOP"); 5 | yapping("%d", i); 6 | i = i + 1; 7 | edgy (i == 2) { 8 | yapping("ahhhhh exitinggggg"); 9 | bruh; 10 | } 11 | } 12 | bussin 0; 13 | } 14 | -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # UV 98 | # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | #uv.lock 102 | 103 | # poetry 104 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 105 | # This is especially recommended for binary packages to ensure reproducibility, and is more 106 | # commonly ignored for libraries. 107 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 108 | #poetry.lock 109 | 110 | # pdm 111 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 112 | #pdm.lock 113 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 114 | # in version control. 115 | # https://pdm.fming.dev/latest/usage/project/#working-with-version-control 116 | .pdm.toml 117 | .pdm-python 118 | .pdm-build/ 119 | 120 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 121 | __pypackages__/ 122 | 123 | # Celery stuff 124 | celerybeat-schedule 125 | celerybeat.pid 126 | 127 | # SageMath parsed files 128 | *.sage.py 129 | 130 | # Environments 131 | .env 132 | .venv 133 | env/ 134 | venv/ 135 | ENV/ 136 | env.bak/ 137 | venv.bak/ 138 | 139 | # Spyder project settings 140 | .spyderproject 141 | .spyproject 142 | 143 | # Rope project settings 144 | .ropeproject 145 | 146 | # mkdocs documentation 147 | /site 148 | 149 | # mypy 150 | .mypy_cache/ 151 | .dmypy.json 152 | dmypy.json 153 | 154 | # Pyre type checker 155 | .pyre/ 156 | 157 | # pytype static type analyzer 158 | .pytype/ 159 | 160 | # Cython debug symbols 161 | cython_debug/ 162 | 163 | # PyCharm 164 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 165 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 166 | # and can be added to the global gitignore or merged into this file. For a more nuclear 167 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 168 | #.idea/ 169 | 170 | # PyPI configuration file 171 | .pypirc -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | # Brainrot Test Suite 2 | 3 | This repository contains a test suite for validating the outputs of `brainrot` examples using `pytest`. 4 | 5 | ## Setup Instructions 6 | 7 | Follow these steps to set up the environment and run the tests: 8 | 9 | ### 1. Create a Virtual Environment 10 | 11 | Use Python's `venv` module to create a virtual environment: 12 | 13 | ```bash 14 | python -m venv .env 15 | ``` 16 | 17 | Activate the virtual environment: 18 | 19 | - On Linux/Mac: 20 | ```bash 21 | source .env/bin/activate 22 | ``` 23 | - On Windows: 24 | ```bash 25 | .env\Scripts\activate 26 | ``` 27 | 28 | ### 2. Install Dependencies 29 | 30 | Install the required Python packages using `pip`: 31 | 32 | ```bash 33 | pip install -r requirements.txt 34 | ``` 35 | 36 | ### 3. Add `brainrot` Executable 37 | 38 | Ensure the `brainrot` executable is available in the root directory or accessible via the system path. 39 | 40 | ### 4. Structure Your Files 41 | 42 | Ensure the following structure is maintained: 43 | 44 | ``` 45 | . 46 | ├── examples/ 47 | │ ├── boolean.brainrot 48 | │ ├── fizz_buzz.brainrot 49 | │ ├── hello_world.brainrot 50 | │ ├── sizeof.brainrot 51 | │ └── ... 52 | ├── tests/ 53 | │ ├── expected_results.json 54 | │ ├── requirements.txt 55 | │ ├── test_brainrot.py 56 | │ ├── README.md 57 | │ └── ... 58 | └── ... 59 | ``` 60 | 61 | ### 5. Run Tests 62 | 63 | Execute the test suite using `pytest`: 64 | 65 | ```bash 66 | pytest -v 67 | ``` 68 | 69 | ### 6. Deactivate the Virtual Environment 70 | 71 | Once done, deactivate the virtual environment: 72 | 73 | ```bash 74 | deactivate 75 | ``` 76 | 77 | ## Updating Test Cases 78 | 79 | 1. Add or update example files in the `examples/` directory. 80 | 2. Update the `expected_results.json` file with the corresponding expected outputs. 81 | 82 | ## Troubleshooting 83 | 84 | - Ensure `brainrot` has the necessary execution permissions: 85 | ```bash 86 | chmod +x ./brainrot 87 | ``` 88 | - Verify paths in `expected_results.json` and `examples/`. 89 | - If you encounter any issues, check the error messages in the `pytest` output. 90 | -------------------------------------------------------------------------------- /tests/expected_results.json: -------------------------------------------------------------------------------- 1 | { 2 | "comparison_edge_case": "1\n", 3 | "division_edge_cases": "inf\n-nan\n-nan", 4 | "float_precision": "0.000000\n", 5 | "integer_overflow": "-2147483648\n2147483647\n", 6 | "mixed_types": "131.880005\n131.880000\n", 7 | "modulo_edge_case": "-2\n2\n", 8 | "scientific_notation": "1.230000e-07\n1.230000e-15\n", 9 | "type_conversion": "123456792.000000\n", 10 | "unsigned_integer_wrap": "0\n4294967294\n", 11 | "boolean": "It's valid!\nnocap: L\nnocap: W\n", 12 | "fizz_buzz": "1\n2\nFizz\n4\nBuzz\nFizz\n7\n8\nFizz\nBuzz\n", 13 | "fizz_buzz_short": "1\n2\nFizz\n4\nBuzz\nFizz\n7\n8\nFizz\nBuzz\n", 14 | "hello_world": "Hello, World!\n", 15 | "sizeof": "4\n4\n1\n2\n4\n8\n12\n", 16 | "char": "c\n", 17 | "float": "3.141592\n", 18 | "modulo": "2\n", 19 | "switch_case": "You chose 2, gigachad move!\n", 20 | "circle_area": "78.540\n", 21 | "circle_area_double": "78.539800\n", 22 | "for_loop": "Skibidi toilet\nSkibidi toilet\nSkibidi toilet\nSkibidi toilet\nSkibidi toilet\nSkibidi toilet\n", 23 | "for_loop_break": "Skibidi toilet\nSkibidi toilet\nSkibidi toilet\nAHHHHHHHHHHHHHHH\n", 24 | "output_error": "you sussy baka!", 25 | "while_loop": "AAAAAH A GOONIN LOOP\n1\nAAAAAH A GOONIN LOOP\n2\nAAAAAH A GOONIN LOOP\n3\nAAAAAH A GOONIN LOOP\n4\n", 26 | "while_loop_break": "AAAAAH A GOONIN LOOP\n1\nahhhhh exitinggggg\n", 27 | "int": "10\n5\n3\n-3\n20\n-20\n2\n1\n2\n-2", 28 | "uint": "10\n9931737\n3\n647238965\n20\n245413032\n2\n1\n2\n1", 29 | "inc-dec": "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n9\n8\n7\n6\n5\n4\n3\n2\n1\n", 30 | "double_vs_float": "0.0 1.0\n", 31 | "const": "1\n1\n", 32 | "do-while": "0\n1\n1\n2\n3\n5\n8\n", 33 | "nest-loop": "0\ngoon\ngoon\ngoon\nbreak goon 2\ngoon\n1\ngoon\ngoon\ngoon\nbreak goon 2\ngoon\n2\ngoon\ngoon\ngoon\nbreak goon 2\ngoon\nbreak flex", 34 | "next-prime": "11", 35 | "int_array": "1\n2\n3\n", 36 | "short_array": "1\n2\n3\n", 37 | "array_initialization": "1\n2\n3\n1\n2\n3\n", 38 | "bool_array": "W\nL\nW\n", 39 | "float_array": "3.140000\n3.141500\n3.141592\n", 40 | "double_array": "3.140000\n3.141500\n3.141592\n", 41 | "char_array": "rizz", 42 | "add_two_numbers": "3", 43 | "mul_two_numbers": "11.400000", 44 | "max_gigachad": "5.000000", 45 | "is_prime": "W", 46 | "slorp_int": "You typed: 42", 47 | "slorp_short": "You typed: 69", 48 | "slorp_float": "You typed: 3.140000", 49 | "slorp_double": "You typed: 3.141592", 50 | "slorp_char": "You typed: c", 51 | "slorp_string": "You typed: skibidi bop bop yes yes", 52 | "fib": "55", 53 | "func_scope": "from inner 10\nfrom outer 4\n", 54 | "func-modifier": "Error: Cannot modify const variable at line 7\n", 55 | "multi_array": "1\n2\n3\n4\n" 56 | } 57 | -------------------------------------------------------------------------------- /tests/requirements.txt: -------------------------------------------------------------------------------- 1 | iniconfig==2.0.0 2 | packaging==24.2 3 | pluggy==1.5.0 4 | pytest==8.3.4 5 | -------------------------------------------------------------------------------- /tests/test_brainrot.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import json 3 | import os 4 | import pytest 5 | 6 | # Get the absolute path to the directory containing the script 7 | script_dir = os.path.dirname(__file__) 8 | 9 | # Construct the full path to the JSON file with expected results 10 | file_path = os.path.join(script_dir, "expected_results.json") 11 | 12 | # Load expected results from the JSON file 13 | with open(file_path, "r") as file: 14 | expected_results = json.load(file) 15 | 16 | @pytest.mark.parametrize("example,expected_output", expected_results.items()) 17 | def test_brainrot_examples(example, expected_output): 18 | brainrot_path = os.path.abspath(os.path.join(script_dir, "../brainrot")) 19 | example_file_path = os.path.abspath(os.path.join(script_dir, f"../test_cases/{example}.brainrot")) 20 | 21 | if example.startswith("slorp_int"): 22 | command = f"echo '42' | {brainrot_path} {example_file_path}" 23 | elif example.startswith("slorp_short"): 24 | command = f"echo '69' | {brainrot_path} {example_file_path}" 25 | elif example.startswith("slorp_float"): 26 | command = f"echo '3.14' | {brainrot_path} {example_file_path}" 27 | elif example.startswith("slorp_double"): 28 | command = f"echo '3.141592' | {brainrot_path} {example_file_path}" 29 | elif example.startswith("slorp_char"): 30 | command = f"echo 'c' | {brainrot_path} {example_file_path}" 31 | elif example.startswith("slorp_string"): 32 | command = f"echo 'skibidi bop bop yes yes' | {brainrot_path} {example_file_path}" 33 | else: 34 | command = f"{brainrot_path} {example_file_path}" 35 | 36 | result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, shell=True) 37 | actual_output = result.stdout.strip() if result.stdout.strip() else result.stderr.strip() 38 | 39 | if "Stderr:" in expected_output and result.stdout.strip(): 40 | actual_output = f"{result.stdout.strip()}\nStderr:\n{result.stderr.strip()}" 41 | 42 | assert actual_output == expected_output.strip(), ( 43 | f"Output for {example} did not match.\n" 44 | f"Expected:\n{expected_output}\n" 45 | f"Actual:\n{actual_output}" 46 | ) 47 | 48 | if "Error:" not in expected_output: 49 | assert result.returncode == 0, ( 50 | f"Command for {example} failed with return code {result.returncode}\n" 51 | f"Stderr:\n{result.stderr}" 52 | ) 53 | 54 | if __name__ == "__main__": 55 | pytest.main(["-v", os.path.abspath(__file__)]) 56 | --------------------------------------------------------------------------------