├── .tito
├── packages
│ ├── memeasm
│ └── .readme
└── tito.props
├── nfpm
├── postinstall.sh
├── postremove.sh
├── generateInstallers.sh
└── nfpm.yaml
├── images
├── logo.png
├── logo_square.png
├── logo.svg
└── logo_square.svg
├── examples
├── Makefile
├── rot13
│ ├── rot13_test.c
│ ├── Makefile
│ └── rot13.memeasm
├── toupper
│ ├── Makefile
│ ├── toupper_test.c
│ └── toupper.memeasm
├── Stalinsort
│ ├── Makefile
│ ├── stalinsort_test.c
│ └── stalin-sort.memeasm
├── alphabet.memeasm
├── HelloWorld.memeasm
├── reverse-string.memeasm
├── is_nice.memeasm
├── the-link.memeasm
└── brainfuck.memeasm
├── .github
├── dependabot.yml
├── workflows
│ ├── runnable_example.memeasm
│ ├── multiple_files
│ │ ├── Makefile
│ │ ├── main.memeasm
│ │ └── function.memeasm
│ ├── example.memeasm
│ ├── create_installers.yml
│ ├── build_test.yml
│ ├── compile_and_run_test.yml
│ ├── codeql-analysis.yml
│ ├── publish-aur.yml
│ └── compilation_test.yml
└── ISSUE_TEMPLATE
│ ├── new-command-suggestion.md
│ └── bug_report.md
├── .gitignore
├── PKGBUILD
├── memeasm.spec
├── AUTHORS.md
├── compiler
├── compiler.h
├── translator
│ ├── translator.h
│ └── translator.c
├── analyser
│ ├── parameters.h
│ ├── analyser.h
│ ├── jumpMarkers.h
│ ├── randomCommands.h
│ ├── comparisons.h
│ ├── functions.h
│ ├── analysisHelper.h
│ ├── jumpMarkers.c
│ ├── comparisons.c
│ ├── functions.c
│ ├── analyser.c
│ ├── randomCommands.c
│ └── analysisHelper.c
├── parser
│ ├── functionParser.h
│ ├── parser.h
│ ├── fileParser.h
│ ├── parser.c
│ ├── functionParser.c
│ └── fileParser.c
├── logger
│ ├── log.h
│ └── log.c
├── commands.h
├── memeasm.c
└── compiler.c
├── install_windows.bat
├── Makefile
└── README.md
/.tito/packages/memeasm:
--------------------------------------------------------------------------------
1 | 1.6-1 ./
2 |
--------------------------------------------------------------------------------
/nfpm/postinstall.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | sudo make install
--------------------------------------------------------------------------------
/nfpm/postremove.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | sudo make uninstall
3 |
--------------------------------------------------------------------------------
/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kammt/MemeAssembly/HEAD/images/logo.png
--------------------------------------------------------------------------------
/images/logo_square.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kammt/MemeAssembly/HEAD/images/logo_square.png
--------------------------------------------------------------------------------
/nfpm/generateInstallers.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | nfpm package -p deb -t "../"
3 | nfpm package -p rpm -t "../"
--------------------------------------------------------------------------------
/.tito/tito.props:
--------------------------------------------------------------------------------
1 | [buildconfig]
2 | builder = tito.builder.Builder
3 | tagger = tito.tagger.VersionTagger
4 | changelog_do_not_remove_cherrypick = 0
5 | changelog_format = %s (%ae)
6 |
--------------------------------------------------------------------------------
/.tito/packages/.readme:
--------------------------------------------------------------------------------
1 | the .tito/packages directory contains metadata files
2 | named after their packages. Each file has the latest tagged
3 | version and the project's relative directory.
4 |
--------------------------------------------------------------------------------
/examples/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: all
2 |
3 | all:
4 | for file in *.memeasm ; do memeasm -o $$(basename $$file .memeasm) $$file ; done
5 | for dir in */ ; do cd $$dir && make && cd .. ; done
6 |
7 |
--------------------------------------------------------------------------------
/examples/rot13/rot13_test.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | extern void rot13(char *str);
4 |
5 | int main() {
6 | char str[] = "Nu, V frr lbh'er n zna bs phygher nf jryy.";
7 | printf("Before rot13: %s\n", str);
8 | rot13(str);
9 | printf("After rot13: %s\n", str);
10 | }
11 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # Set update schedule for GitHub Actions
2 |
3 | version: 2
4 | updates:
5 |
6 | - package-ecosystem: "github-actions"
7 | directory: "/"
8 | schedule:
9 | # Check for updates to GitHub Actions every week
10 | interval: "weekly"
11 |
--------------------------------------------------------------------------------
/examples/rot13/Makefile:
--------------------------------------------------------------------------------
1 | CC=gcc
2 | CFLAGS=
3 |
4 | ifeq ($(shell uname -s),Linux)
5 | CFLAGS+=-gstabs -no-pie
6 | endif
7 |
8 | .PHONY: all clean
9 |
10 | all: rot13_test.c
11 | memeasm -g -O -o rot13.o rot13.memeasm
12 | $(CC) -o rot13 $^ rot13.o $(CFLAGS)
13 |
14 | clean:
15 | rm rot13
16 |
--------------------------------------------------------------------------------
/examples/toupper/Makefile:
--------------------------------------------------------------------------------
1 | CC=gcc
2 | CFLAGS=
3 |
4 | ifeq ($(shell uname -s),Linux)
5 | CFLAGS += -gstabs -no-pie
6 | endif
7 |
8 | .PHONY: all clean
9 |
10 | all: toupper_test.c
11 | memeasm -g -O -o toupper.o toupper.memeasm
12 | $(CC) -o toupper $^ toupper.o $(CFLAGS)
13 |
14 | clean:
15 | rm toupper
16 |
--------------------------------------------------------------------------------
/examples/Stalinsort/Makefile:
--------------------------------------------------------------------------------
1 | CC=gcc
2 | CFLAGS=
3 |
4 | ifeq ($(shell uname -s),Linux)
5 | CFLAGS += -gstabs -no-pie
6 | endif
7 |
8 | .PHONY: all clean
9 |
10 | all: stalinsort_test.c
11 | memeasm -O -o stalinsort.o stalin-sort.memeasm -g
12 | $(CC) -o stalinsort $^ stalinsort.o $(CFLAGS)
13 |
14 | clean:
15 | rm stalinsort
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #Executable
2 | ./memeasm
3 | memeasm.exe
4 |
5 | #Temporary files for local testing
6 | tmp.asm
7 | example.S
8 | example.memeasm
9 | example.exe
10 | tmp
11 | tmp.o
12 | /examples/Stalinsort/stalinsort.S
13 | test
14 | test.S
15 |
16 | #IDE files
17 | **/.idea/
18 | **/.vscode/
19 |
20 | #compiledb used by clang tooling
21 | compile_commands.json
22 |
--------------------------------------------------------------------------------
/.github/workflows/runnable_example.memeasm:
--------------------------------------------------------------------------------
1 | I like to have fun, fun, fun, fun, fun, fun, fun, fun, fun, fun main
2 | ebx is brilliant, but I like 64
3 | sneak 100 eax
4 |
5 | upgrade
6 | upvote ebx
7 | upvote eax
8 | corporate needs you to find the difference between eax and 25
9 | fuck go back
10 |
11 | they're the same picture
12 | I see this as an absolute win
13 |
--------------------------------------------------------------------------------
/examples/alphabet.memeasm:
--------------------------------------------------------------------------------
1 | I like to have fun, fun, fun, fun, fun, fun, fun, fun, fun, fun main
2 | eax is brilliant, but I like 65
3 |
4 | upgrade
5 | what can I say except al
6 | what can I say except \s
7 | upvote eax
8 | corporate needs you to find the difference between eax and 91
9 | fuck go back
10 |
11 | they're the same picture
12 | what can I say except \n
13 |
14 | I see this as an absolute win
15 |
--------------------------------------------------------------------------------
/PKGBUILD:
--------------------------------------------------------------------------------
1 | # Maintainer: Tobias Kamm
2 | pkgname=memeassembly
3 | pkgver=VERSION_STRING
4 | pkgrel=PKGREL
5 | pkgdesc="A Meme-based programming language"
6 | arch=('x86_64')
7 | url="https://kammt.github.io/MemeAssembly/#/"
8 | license=('GPL3')
9 | depends=('gcc')
10 | source=(https://github.com/kammt/MemeAssembly/archive/refs/tags/v$pkgver.tar.gz)
11 | sha256sums=('256SUM')
12 |
13 | package() {
14 | cd "MemeAssembly-$pkgver"
15 |
16 | make DESTDIR="$pkgdir" install
17 | }
18 |
--------------------------------------------------------------------------------
/.github/workflows/multiple_files/Makefile:
--------------------------------------------------------------------------------
1 | # This should work just fine
2 | main: main.memeasm function.memeasm
3 | memeasm -o $@ $^
4 |
5 | .PHONY: fail_undefined fail_no_main clean
6 |
7 | # This should fail as the function referenced in main.memeasm is defined in a file that is not given as input file
8 | fail_undefined: main.memeasm
9 | memeasm -o $@ $^
10 |
11 | # This should fail as we don't have a main function
12 | fail_no_main: function.memeasm
13 | memeasm -o $@ $^
14 |
15 | clean:
16 | rm -f main fail_undefined fail_no_main
17 |
--------------------------------------------------------------------------------
/examples/HelloWorld.memeasm:
--------------------------------------------------------------------------------
1 | I like to have fun, fun, fun, fun, fun, fun, fun, fun, fun, fun main
2 | what can I say except H
3 | what can I say except e
4 | what can I say except l
5 | what can I say except l
6 | what can I say except o
7 | what can I say except \s
8 | what can I say except W
9 | what can I say except o
10 | what can I say except r
11 | what can I say except l
12 | what can I say except d
13 | what can I say except !
14 | what can I say except \n
15 |
16 | I see this as an absolute win
17 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/new-command-suggestion.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: New Command Suggestion
3 | about: Propose a new command
4 | title: "[Command suggestion]"
5 | labels: enhancement, new command
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Command Syntax:** (e.g. `stonks [register]`)
11 |
12 |
13 | **Command Description:**
14 |
15 |
16 | Which x86_64 Assembly instruction(s) would be used to translate this command?
17 |
18 |
19 | What could this command be useful for?
20 |
21 |
22 | What Meme is your command based on? (You can also provide a link to e.g. its KnowYourMeme page)
23 |
--------------------------------------------------------------------------------
/.github/workflows/example.memeasm:
--------------------------------------------------------------------------------
1 | I like to have fun, fun, fun, fun, fun, fun, fun, fun, fun, fun function
2 | ebx is brilliant, but I like 64
3 | parry 20 you filthy casual ebx
4 | sneak 100 dx
5 | guess I'll die or draw 25
6 | guess I'll die
7 | upgrade
8 | stonks rax
9 | not stonks rax
10 | upvote edx
11 | they're the same picture
12 | corporate needs you to find the difference between eax and 48
13 | fuck go back
14 | downvote ecx
15 | eax units are ready, with 69 more well on the way
16 | confused stonks
17 | bitconneeeeeeect eax 155
18 | I see this as an absolute win
19 |
--------------------------------------------------------------------------------
/nfpm/nfpm.yaml:
--------------------------------------------------------------------------------
1 | #
2 | # check https://nfpm.goreleaser.com/configuration for detailed usage
3 | #
4 | name: "memeasm"
5 | arch: "amd64"
6 | platform: "linux"
7 | version: VERSION_STRING
8 | section: "default"
9 | priority: "extra"
10 | depends:
11 | - gcc
12 | - make
13 | maintainer: "Tobias Kamm "
14 | description: |
15 | A Meme-based programming language
16 | homepage: "https://kammt.github.io/MemeAssembly"
17 | license: "GPLv3"
18 | # Contents to add to the package
19 | # This can be binaries or any other files.
20 | contents:
21 | - src: ../compiler
22 | dst: /compiler
23 | - src: ../Makefile
24 | dst: Makefile
25 | scripts:
26 | postinstall: ./postinstall.sh
27 | postremove: ./postremove.sh
28 |
--------------------------------------------------------------------------------
/memeasm.spec:
--------------------------------------------------------------------------------
1 | Name: memeasm
2 | Version: 1.6
3 | Release: 1%{?dist}
4 | Summary: A Meme-based programming language
5 |
6 | License: GPLv3
7 | URL: https://github.com/kammt/MemeAssembly
8 | Source0: %{name}-%{version}.tar.gz
9 |
10 | BuildRequires: gcc
11 | BuildRequires: make
12 | Requires: gcc
13 |
14 | %description
15 | The compiler for MemeAssembly, a Meme-based programming language.
16 | Learn more at https://kammt.github.io/MemeAssembly.
17 |
18 | %prep
19 | %autosetup
20 |
21 |
22 | %build
23 | %global debug_package %{nil}
24 | %make_build
25 |
26 |
27 | %install
28 | %make_install
29 |
30 |
31 | %files
32 | %license LICENSE
33 | /usr/local/bin/memeasm
34 |
35 |
36 | %changelog
37 | * Sun May 07 2023 tobias 1.6-1
38 | - new package built with tito
39 |
40 |
--------------------------------------------------------------------------------
/AUTHORS.md:
--------------------------------------------------------------------------------
1 | # Project Authors
2 | ## Main Contributor
3 | - Tobias Kamm
4 |
5 | ## Other contributors
6 | - [xarantolus](https://github.com/xarantolus)
7 | - Implementation of the "what can I say except [...]" command in v0.1
8 | - Suggested the idea of Monke Jump Markers
9 | - Bug reporting
10 | - [aengelke](https://github.com/aengelke)
11 | - Fixed some buffer overruns
12 | - Adapted the compilation to no longer use temporary files
13 | - Implementation of toupper_str in MemeASM
14 | - [M3L73D](https://github.com/M3L73D)
15 | - Implementation of rot13 in MemeASM
16 | - Added a "Nice"-message that is printed by the compiler whenever 69 or 420 are used in the code
17 | - [RobinMarchart](https://github.com/RobinMarchart)
18 | - Implementation of the "it's a trap" command
19 |
20 | ## Special thanks
21 | - [xarantolus](https://github.com/xarantolus) for creating the [VSCode Extension for MemeAssembly](https://github.com/xarantolus/MemeAssembly-vscode)
22 |
--------------------------------------------------------------------------------
/.github/workflows/multiple_files/main.memeasm:
--------------------------------------------------------------------------------
1 | I like to have fun, fun, fun, fun, fun, fun, fun, fun, fun, fun main
2 | what can I say except T
3 | what can I say except h
4 | what can I say except i
5 | what can I say except s
6 | what can I say except space
7 | what can I say except i
8 | what can I say except s
9 | what can I say except space
10 | what can I say except i
11 | what can I say except n
12 | what can I say except space
13 | what can I say except m
14 | what can I say except a
15 | what can I say except i
16 | what can I say except n
17 | what can I say except .
18 | what can I say except m
19 | what can I say except e
20 | what can I say except m
21 | what can I say except e
22 | what can I say except a
23 | what can I say except s
24 | what can I say except m
25 | what can I say except \n
26 |
27 | function: whomst has summoned the almighty one
28 | return to monke uaaua
29 |
30 | I see this as an absolute win
31 |
--------------------------------------------------------------------------------
/compiler/compiler.h:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the MemeAssembly compiler.
3 |
4 | Copyright © 2021-2023 Tobias Kamm
5 |
6 | MemeAssembly is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | MemeAssembly is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with MemeAssembly. If not, see .
18 | */
19 |
20 | #ifndef COMPILER_H
21 | #define COMPILER_H
22 |
23 | #include
24 | #include
25 | #include "commands.h"
26 |
27 | _Noreturn void compile(struct compileState compileState, char* outputFileName);
28 |
29 | #endif
30 |
--------------------------------------------------------------------------------
/compiler/translator/translator.h:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the MemeAssembly compiler.
3 |
4 | Copyright © 2021-2023 Tobias Kamm
5 |
6 | MemeAssembly is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | MemeAssembly is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with MemeAssembly. If not, see .
18 | */
19 |
20 | #ifndef MEMEASSEMBLY_TRANSLATOR_H
21 | #define MEMEASSEMBLY_TRANSLATOR_H
22 |
23 | #include "../commands.h"
24 |
25 | #include
26 |
27 | void writeToFile(struct compileState* compileState, FILE *outputFile);
28 |
29 | #endif //MEMEASSEMBLY_TRANSLATOR_H
30 |
--------------------------------------------------------------------------------
/compiler/analyser/parameters.h:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the MemeAssembly compiler.
3 |
4 | Copyright © 2021-2023 Tobias Kamm
5 |
6 | MemeAssembly is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | MemeAssembly is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with MemeAssembly. If not, see .
18 | */
19 |
20 | #ifndef MEMEASSEMBLY_PARAMETERS_H
21 | #define MEMEASSEMBLY_PARAMETERS_H
22 |
23 | #include "../commands.h"
24 |
25 | void checkParameters(struct parsedCommand *parsedCommand, char* inputFileName, struct compileState* compileState);
26 |
27 | #endif //MEMEASSEMBLY_PARAMETERS_H
28 |
--------------------------------------------------------------------------------
/compiler/parser/functionParser.h:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the MemeAssembly compiler.
3 |
4 | Copyright © 2021-2023 Tobias Kamm
5 |
6 | MemeAssembly is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | MemeAssembly is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with MemeAssembly. If not, see .
18 | */
19 |
20 | #ifndef MEMEASSEMBLY_FUNCTIONPARSER_H
21 | #define MEMEASSEMBLY_FUNCTIONPARSER_H
22 |
23 | #include "parser.h"
24 | #include "fileParser.h"
25 |
26 | void parseFunctions(struct file* fileStruct, struct commandsArray commandsArray, struct compileState* compileState);
27 |
28 | #endif
29 |
--------------------------------------------------------------------------------
/compiler/parser/parser.h:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the MemeAssembly compiler.
3 |
4 | Copyright © 2021-2023 Tobias Kamm
5 |
6 | MemeAssembly is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | MemeAssembly is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with MemeAssembly. If not, see .
18 | */
19 |
20 | #include
21 | #include
22 | #include
23 | #include "../commands.h"
24 |
25 | #ifndef MEMEASSEMBLY_PARSER_H
26 | #define MEMEASSEMBLY_PARSER_H
27 |
28 | void parseFile(struct file* fileStruct, FILE* inputFile, struct compileState* compileState);
29 |
30 | #endif
31 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve the MemeASM compiler
4 | title: "[Bug]"
5 | labels: bug
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 |
15 | Code example or used MemeASM code
16 |
17 |
18 |
19 |
20 | Used compiler flags[e.g. -O-1 -S]:
21 |
22 |
23 | **Debug Output**
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | **Screenshots**
32 | If applicable, add screenshots to help explain your problem.
33 |
34 | **System Info (please complete the following information):**
35 | - Linux Distribution: [e.g. Arch Linux]
36 | - GCC Version: [e.g. 11.1.0]
37 | - MemeASM Compiler Version: [e.g. 1.0.1]
38 | - Installation method: [e.g. Makefile, deb-package etc.]
39 |
--------------------------------------------------------------------------------
/examples/toupper/toupper_test.c:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the MemeAssembly compiler.
3 |
4 | Copyright © 2021-2023 Tobias Kamm and contributors
5 |
6 | MemeAssembly is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | MemeAssembly is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with MemeAssembly. If not, see .
18 | */
19 | #include
20 |
21 | extern void toupper_str(char* str);
22 |
23 | int main() {
24 | char str[] = "The qu1ck BR0wN FoX juMpZ ov3r ThE l4zY dog. Hel1, Y3aH!";
25 | printf("Before toupper_str: %s\n", str);
26 | toupper_str(str);
27 | printf("After toupper_str: %s\n", str);
28 | }
29 |
--------------------------------------------------------------------------------
/compiler/analyser/analyser.h:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the MemeAssembly compiler.
3 |
4 | Copyright © 2021-2023 Tobias Kamm
5 |
6 | MemeAssembly is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | MemeAssembly is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with MemeAssembly. If not, see .
18 | */
19 |
20 | #ifndef MEMEASSEMBLY_ANALYSER_H
21 | #define MEMEASSEMBLY_ANALYSER_H
22 |
23 | #include "../commands.h"
24 | #include "../compiler.h"
25 |
26 | #include "comparisons.h"
27 | #include "functions.h"
28 | #include "jumpMarkers.h"
29 | #include "parameters.h"
30 | #include "randomCommands.h"
31 |
32 | void analyseCommands(struct compileState* compileState);
33 |
34 | #endif
35 |
--------------------------------------------------------------------------------
/compiler/analyser/jumpMarkers.h:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the MemeAssembly compiler.
3 |
4 | Copyright © 2021-2023 Tobias Kamm
5 |
6 | MemeAssembly is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | MemeAssembly is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with MemeAssembly. If not, see .
18 | */
19 |
20 | #ifndef MEMEASSEMBLY_JUMPMARKERS_H
21 | #define MEMEASSEMBLY_JUMPMARKERS_H
22 |
23 | #include "../commands.h"
24 |
25 | void analyseMonkeMarkers(struct commandLinkedList** commandLinkedList, unsigned opcode, struct compileState* compileState);
26 | void analyseJumpMarkers(struct commandLinkedList** commandLinkedList, unsigned opcode, struct compileState* compileState);
27 |
28 | #endif //MEMEASSEMBLY_JUMPMARKERS_H
29 |
--------------------------------------------------------------------------------
/compiler/analyser/randomCommands.h:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the MemeAssembly compiler.
3 |
4 | Copyright © 2021-2023 Tobias Kamm
5 |
6 | MemeAssembly is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | MemeAssembly is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with MemeAssembly. If not, see .
18 | */
19 |
20 | #ifndef MEMEASSEMBLY_RANDOMCOMMANDS_H
21 | #define MEMEASSEMBLY_RANDOMCOMMANDS_H
22 |
23 | #include "../commands.h"
24 |
25 | void setConfusedStonksJumpLabel(struct commandLinkedList** commandLinkedList, unsigned opcode, struct compileState* compileState) ;
26 | void chooseLinesToBeDeleted(struct commandLinkedList** commandLinkedList, unsigned opcode, struct compileState* compileState);
27 |
28 | #endif //MEMEASSEMBLY_RANDOMCOMMANDS_H
29 |
--------------------------------------------------------------------------------
/compiler/parser/fileParser.h:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the MemeAssembly compiler.
3 |
4 | Copyright © 2021-2023 Tobias Kamm
5 |
6 | MemeAssembly is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | MemeAssembly is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with MemeAssembly. If not, see .
18 | */
19 |
20 | #ifndef MEMEASSEMBLY_FILEPARSER_H
21 | #define MEMEASSEMBLY_FILEPARSER_H
22 |
23 | #include "parser.h"
24 |
25 | struct commandsArray {
26 | struct parsedCommand* arrayPointer;
27 | size_t size;
28 | };
29 |
30 | /**
31 | * Parses an input file line by line and fills a provided struct commandsArray
32 | */
33 | void parseCommands(FILE *inputFile, char* inputFileName, struct compileState* compileState, struct commandsArray* commandsArray);
34 | #endif
35 |
--------------------------------------------------------------------------------
/compiler/analyser/comparisons.h:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the MemeAssembly compiler.
3 |
4 | Copyright © 2021-2023 Tobias Kamm
5 |
6 | MemeAssembly is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | MemeAssembly is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with MemeAssembly. If not, see .
18 | */
19 |
20 | #ifndef MEMEASSEMBLY_COMPARISONS_H
21 | #define MEMEASSEMBLY_COMPARISONS_H
22 |
23 | #include "../commands.h"
24 | #include
25 |
26 | void analyseWhoWouldWinCommands(struct commandLinkedList** commandLinkedList, unsigned opcode, struct compileState* compileState);
27 | void analyseTheyreTheSamePictureCommands(struct commandLinkedList** commandLinkedList, unsigned opcode, struct compileState* compileState);
28 |
29 | #endif //MEMEASSEMBLY_COMPARISONS_H
30 |
--------------------------------------------------------------------------------
/compiler/analyser/functions.h:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the MemeAssembly compiler.
3 |
4 | Copyright © 2021-2023 Tobias Kamm
5 |
6 | MemeAssembly is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | MemeAssembly is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with MemeAssembly. If not, see .
18 | */
19 |
20 | #ifndef MEMEASSEMBLY_FUNCTIONS_H
21 | #define MEMEASSEMBLY_FUNCTIONS_H
22 |
23 | #include "../commands.h"
24 | #include
25 |
26 | void analyseFunctions(struct commandLinkedList** commandLinkedList, unsigned opcode, struct compileState* compileState);
27 | void analyseCall(struct commandLinkedList** commandLinkedList, unsigned opcode, struct compileState* compileState);
28 | bool mainFunctionExists(struct compileState* compileState);
29 |
30 | #endif //MEMEASSEMBLY_FUNCTIONS_H
31 |
--------------------------------------------------------------------------------
/compiler/parser/parser.c:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the MemeAssembly compiler.
3 |
4 | Copyright © 2021-2023 Tobias Kamm
5 |
6 | MemeAssembly is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | MemeAssembly is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with MemeAssembly. If not, see .
18 | */
19 |
20 | #include "parser.h"
21 | #include "functionParser.h"
22 | #include
23 |
24 | void parseFile(struct file* fileStruct, FILE* inputFile, struct compileState* compileState) {
25 | struct commandsArray commandsArray;
26 | parseCommands(inputFile, fileStruct->fileName, compileState, &commandsArray);
27 |
28 | parseFunctions(fileStruct, commandsArray, compileState);
29 | fileStruct->loc = commandsArray.size;
30 | fileStruct->parsedCommands = commandsArray.arrayPointer;
31 | }
32 |
--------------------------------------------------------------------------------
/compiler/analyser/analysisHelper.h:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the MemeAssembly compiler.
3 |
4 | Copyright © 2021-2023 Tobias Kamm
5 |
6 | MemeAssembly is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | MemeAssembly is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with MemeAssembly. If not, see .
18 | */
19 |
20 | #ifndef MEMEASSEMBLY_ANALYSISHELPER_H
21 | #define MEMEASSEMBLY_ANALYSISHELPER_H
22 |
23 | #include "analyser.h"
24 |
25 | void checkDuplicateDefinition(struct commandLinkedList* commandLinkedList, struct compileState* compileState, bool oncePerFile, uint8_t parametersToCheck, char* itemName);
26 | void checkCompanionCommandExistence(struct commandLinkedList* parentCommands, struct commandLinkedList* childCommands, struct compileState* compileState, uint8_t parametersToCheck, bool sameFile, char* itemName);
27 |
28 | #endif //MEMEASSEMBLY_ANALYSISHELPER_H
29 |
--------------------------------------------------------------------------------
/examples/Stalinsort/stalinsort_test.c:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the MemeAssembly compiler.
3 |
4 | Copyright © 2021-2023 Tobias Kamm and contributors
5 |
6 | MemeAssembly is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | MemeAssembly is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with MemeAssembly. If not, see .
18 | */
19 | #include
20 |
21 | int array[] = {1, 5, 2, 8, 9, 3, 4, 12, 14, 69, 420, 0};
22 | size_t arraySize = sizeof array / sizeof(int);
23 |
24 | extern void stalinSort(int array[], size_t *arraySize);
25 |
26 | int main() {
27 | printf("Before sorting:\n");
28 | for(size_t i = 0; i < arraySize; i++) {
29 | printf("%d,", array[i]);
30 | }
31 |
32 | stalinSort(array, &arraySize);
33 |
34 | printf("\nAfter sorting:\n");
35 | for(size_t i = 0; i < arraySize; i++) {
36 | printf("%d,", array[i]);
37 | }
38 | printf("\n");
39 | }
40 |
--------------------------------------------------------------------------------
/.github/workflows/multiple_files/function.memeasm:
--------------------------------------------------------------------------------
1 | I like to have fun, fun, fun, fun, fun, fun, fun, fun, fun, fun function
2 | what can I say except T
3 | what can I say except h
4 | what can I say except i
5 | what can I say except s
6 | what can I say except space
7 | what can I say except i
8 | what can I say except s
9 | what can I say except space
10 | what can I say except i
11 | what can I say except n
12 | what can I say except space
13 | what can I say except f
14 | what can I say except u
15 | what can I say except n
16 | what can I say except c
17 | what can I say except t
18 | what can I say except i
19 | what can I say except o
20 | what can I say except n
21 | what can I say except .
22 | what can I say except m
23 | what can I say except e
24 | what can I say except m
25 | what can I say except e
26 | what can I say except a
27 | what can I say except s
28 | what can I say except m
29 | what can I say except \n
30 |
31 | monke uaaua
32 |
33 | I see this as an absolute win
34 |
35 | I like to have fun, fun, fun, fun, fun, fun, fun, fun, fun, fun emptyFunctionTest
36 | I see this as an absolute win
37 |
38 | I like to have fun, fun, fun, fun, fun, fun, fun, fun, fun, fun functionReturnTest
39 | who would win? eax or 7
40 | no, I don't think I will
41 | eax wins
42 | right back at ya, buckaroo
43 | 7 wins
44 | I see this as an absolute win
45 |
46 |
--------------------------------------------------------------------------------
/examples/reverse-string.memeasm:
--------------------------------------------------------------------------------
1 | I like to have fun, fun, fun, fun, fun, fun, fun, fun, fun, fun main
2 |
3 | sneak 100 rax
4 |
5 | What the hell happened here? rcx counts how many characters have been read
6 | sneak 100 rcx
7 |
8 | upgrade
9 |
10 | What the hell happened here? Read one character from stdin
11 | let me in. LET ME IIIIIIIIN al
12 |
13 | What the hell happened here? Check if it's the end of a line
14 | corporate needs you to find the difference between al and \n
15 |
16 | What the hell happened here? If not, we just push it to the stack (very efficient lol)
17 | stonks rax
18 | upvote rcx
19 |
20 | fuck go back
21 |
22 | they're the same picture
23 |
24 |
25 | What the hell happened here? Now write what we've seen
26 | banana
27 |
28 | What the hell happened here? Check if we have reached the end of the input
29 | who would win? rcx or 0
30 |
31 | 0 wins
32 | What the hell happened here? rcx is <= 0, jump to end of program
33 | return to monke uaaaaaua
34 |
35 | rcx wins
36 | What the hell happened here? rcx > 0, get the character and print it to stdout
37 |
38 | not stonks rax
39 | what can I say except al
40 |
41 | downvote rcx
42 |
43 | where banana
44 |
45 | monke uaaaaaua
46 |
47 | what can I say except \n
48 |
49 | I see this as an absolute win
50 |
--------------------------------------------------------------------------------
/examples/toupper/toupper.memeasm:
--------------------------------------------------------------------------------
1 | What the hell happened here? This program takes a pointer to a string in rdi, the string is modified in-place
2 | I like to have fun, fun, fun, fun, fun, fun, fun, fun, fun, fun toupper_str
3 |
4 | eax is brilliant, but I like 97
5 |
6 | What the hell happened here? Loop over all lower case chars between 97 and 123
7 | upgrade
8 | stonks rdi
9 |
10 | What the hell happened here? We search for the current char in the string
11 | banana
12 | sneak 100 edx
13 | dl is brilliant, but I like rdi do you know de wey
14 | who would win? edx or 1
15 |
16 | What the hell happened here? We get here if edx is greater than 1 => not zero
17 | edx wins
18 | who would win? dl or al
19 | What the hell happened here? Jump below if al is not equal to dl
20 |
21 | What the hell happened here? Clear one bit to make it UPPER CASE
22 | bitconneeeeeeect dl 223
23 | rdi do you know de wey is brilliant, but I like dl
24 |
25 | dl wins
26 | al wins
27 |
28 | upvote rdi
29 | where banana
30 |
31 | What the hell happened here? edx contained 0, meaning this is the end of the string
32 | 1 wins
33 | not stonks rdi
34 |
35 | upvote eax
36 | corporate needs you to find the difference between eax and 123
37 |
38 | fuck go back
39 |
40 | they're the same picture
41 | right back at ya, buckaroo
42 |
--------------------------------------------------------------------------------
/.github/workflows/create_installers.yml:
--------------------------------------------------------------------------------
1 | name: Create Installers
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | version:
7 | description: 'Version String'
8 | required: true
9 |
10 | jobs:
11 | create-installers:
12 | runs-on: ubuntu-latest
13 |
14 | steps:
15 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
16 | - uses: actions/checkout@v4
17 |
18 | - name: Install nfpm
19 | run: |
20 | echo 'deb [trusted=yes] https://repo.goreleaser.com/apt/ /' | sudo tee /etc/apt/sources.list.d/goreleaser.list
21 | sudo apt update
22 | sudo apt install nfpm
23 |
24 | - name: Replace VERSION_STRING in nfpm configuration file with parameter
25 | run: |
26 | cd nfpm
27 | sed -i 's/VERSION_STRING/${{ github.event.inputs.version }}/g' nfpm.yaml
28 | cd ..
29 |
30 | - name: Generate *.deb/*.rmp installer files
31 | run: |
32 | cd nfpm
33 | ./generateInstallers.sh
34 | cd ..
35 |
36 | - name: Archive debian installer
37 | uses: actions/upload-artifact@v4
38 | with:
39 | name: memeasm_${{ github.event.inputs.version }}_amd64.deb
40 | path: memeasm_${{ github.event.inputs.version }}_amd64.deb
41 |
42 | - name: Archive rpm installer
43 | uses: actions/upload-artifact@v4
44 | with:
45 | name: memeasm-${{ github.event.inputs.version }}.x86_64.rpm
46 | path: memeasm-${{ github.event.inputs.version }}.x86_64.rpm
47 |
--------------------------------------------------------------------------------
/.github/workflows/build_test.yml:
--------------------------------------------------------------------------------
1 | # This is a basic workflow to help you get started with Actions
2 |
3 | name: Build Test
4 |
5 | # Controls when the action will run.
6 | on:
7 | # Triggers the workflow on push or pull request events but only for the main branch
8 | push:
9 | branches: [ main, develop ]
10 | pull_request:
11 | branches: [ main, develop ]
12 |
13 | # Allows you to run this workflow manually from the Actions tab
14 | workflow_dispatch:
15 |
16 | jobs:
17 |
18 | build_linux:
19 | # The type of runner that the job will run on
20 | runs-on: ubuntu-latest
21 |
22 | # Steps represent a sequence of tasks that will be executed as part of the job
23 | steps:
24 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
25 | - uses: actions/checkout@v4
26 |
27 | - name: Build Linux
28 | run: make CFLAGS+=-Werror debug
29 |
30 | build_windows:
31 | # The type of runner that the job will run on
32 | runs-on: windows-2019
33 |
34 | # Steps represent a sequence of tasks that will be executed as part of the job
35 | steps:
36 | - uses: actions/checkout@v4
37 |
38 | - name: Run Makefile
39 | shell: powershell
40 | run: |
41 | $env:Path += ";C:\msys64\mingw64\bin"
42 | mingw32-make.exe debug
43 |
44 | build_macos:
45 | # The type of runner that the job will run on
46 | runs-on: macos-latest
47 |
48 | steps:
49 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
50 | - uses: actions/checkout@v4
51 |
52 | - name: Build MacOS
53 | run: make CFLAGS+=-Werror debug
54 |
--------------------------------------------------------------------------------
/.github/workflows/compile_and_run_test.yml:
--------------------------------------------------------------------------------
1 |
2 | name: Compile and Run Test
3 |
4 | on:
5 | # Triggers the workflow on push or pull request events but only for the main/develop branch
6 | push:
7 | branches: [ main, develop ]
8 | pull_request:
9 | branches: [ main, develop ]
10 |
11 | workflow_dispatch:
12 |
13 | jobs:
14 | run_linux:
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - uses: actions/checkout@v4
19 |
20 | - name: Compile the project
21 | run: make debug
22 |
23 | - name: Run the compiler on runnable_example.memeasm
24 | run: ./memeasm -d -o tmp .github/workflows/runnable_example.memeasm
25 |
26 | - name: Run the executable
27 | run: ./tmp
28 |
29 | run_windows:
30 | runs-on: windows-2019
31 |
32 | steps:
33 | - uses: actions/checkout@v4
34 |
35 | - name: Compile memeasm
36 | shell: powershell
37 | run: |
38 | $env:Path += ";C:\msys64\mingw64\bin"
39 | mingw32-make.exe debug
40 |
41 | - name: Run compiler on runnable_example.memeasm
42 | shell: powershell
43 | run: ./memeasm.exe -d -o tmp.exe .github\workflows\runnable_example.memeasm
44 |
45 | - name: Run the executable
46 | shell: powershell
47 | run: ./tmp.exe
48 |
49 | run_macos:
50 | runs-on: macos-11
51 |
52 | steps:
53 | - uses: actions/checkout@v4
54 |
55 | - name: Compile the project
56 | run: make debug
57 |
58 | - name: Run the compiler on runnable_example.memeasm
59 | run: ./memeasm -d -o tmp .github/workflows/runnable_example.memeasm
60 | - name: Run the executable
61 | run: ./tmp
62 |
--------------------------------------------------------------------------------
/install_windows.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | ECHO Checking for correct installation of mingw64
3 |
4 | WHERE gcc
5 | IF %ERRORLEVEL% == 0 goto :checkMake
6 | ECHO Error! Could not find gcc in your PATH. Check https://kammt.github.io/MemeAssembly/#/getting-started for more information
7 | ECHO Installation failed
8 | PAUSE
9 | EXIT 1
10 |
11 | :checkMake
12 | WHERE mingw32-make
13 | IF %ERRORLEVEL% == 0 goto :downloadMemeasm
14 | ECHO Error! Could not find mingw32-make in your PATH. Check https://kammt.github.io/MemeAssembly/#/getting-started for more information
15 | ECHO Installation failed
16 | PAUSE
17 | EXIT 1
18 |
19 | :downloadMemeasm
20 | ECHO All dependencies satisfied
21 | ECHO Downloading latest release of MemeAssembly...
22 | powershell -Command "(New-Object Net.WebClient).DownloadFile('https://github.com/kammt/MemeAssembly/zipball/master', '%temp%\MemeAssembly.zip')
23 | ECHO Extracting...
24 | powershell Expand-Archive %temp%\MemeAssembly.zip -DestinationPath %temp%\MemeAssembly-latest
25 | cd %temp%\MemeAssembly-latest\kammt-*
26 |
27 | :runMakefile
28 | set /p installDir="Enter the desired installation directory. Make sure that you have the required priviledges (Default: C:\Program Files\MemeAssembly): "
29 | IF NOT DEFINED installDir SET "installDir=C:\Program Files\MemeAssembly"
30 | ECHO Compiling...
31 | mingw32-make
32 | ECHO Installing...
33 | mkdir "%installDir%"
34 | move "./memeasm.exe" "%installDir%\memeasm.exe"
35 | icacls "%installDir%\memeasm.exe" /t /grant everyone:R
36 |
37 | :cleanup
38 | ECHO Cleaning up...
39 | cd ../..
40 | DEL /S /Q MemeAssembly-latest
41 | DEL /F MemeAssembly.zip
42 |
43 | :endofinstall
44 | ECHO Installation done! To use MemeAssembly from the command line, add the directory %installDir% to your system-wide PATH-Variable
45 | PAUSE
46 | EXIT 0
47 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | CC_win=x86_64-w64-mingw32-gcc
2 |
3 | PLATFORM_MACRO=
4 | ifeq ($(OS),Windows_NT) # is Windows_NT on XP, 2000, 7, Vista, 10...
5 | PLATFORM_MACRO=WINDOWS
6 | else
7 | detected_OS := $(shell uname -s)
8 | ifeq ($(detected_OS),Darwin)
9 | PLATFORM_MACRO=MACOS
10 | else
11 | PLATFORM_MACRO=LINUX
12 | endif
13 | endif
14 |
15 | # Compiler Flags
16 | CFLAGS+=-std=gnu17 -D $(PLATFORM_MACRO) -O2
17 | CFLAGS_DEBUG+=-O0 -Wall -Wextra -Wpedantic -Wmisleading-indentation -g
18 |
19 | # Destination directory for make install
20 | bindir=/usr/local/bin
21 |
22 | INSTALL=install
23 | INSTALL_PROGRAM=$(INSTALL)
24 |
25 | # Files to compile
26 | FILES=compiler/memeasm.c compiler/compiler.c compiler/logger/log.c compiler/parser/parser.c compiler/parser/fileParser.c compiler/parser/functionParser.c compiler/analyser/analysisHelper.c compiler/analyser/parameters.c compiler/analyser/functions.c compiler/analyser/jumpMarkers.c compiler/analyser/comparisons.c compiler/analyser/randomCommands.c compiler/analyser/analyser.c compiler/translator/translator.c
27 |
28 | .PHONY: all clean debug uninstall install windows
29 |
30 | # Standard compilation
31 | all:
32 | $(CC) -o memeasm $(FILES) $(CFLAGS)
33 |
34 | # Compilation with debugging-flags
35 | debug:
36 | $(CC) -o memeasm $(FILES) $(CFLAGS) $(CFLAGS_DEBUG)
37 |
38 | # Remove the compiled executable from this directory
39 | clean:
40 | $(RM) memeasm
41 |
42 | # Removes "memeasm" from DESTDIR
43 | uninstall:
44 | $(RM) $(DESTDIR)/memeasm
45 |
46 | # Compiles an executable and stores it in DESTDIR
47 | install: all
48 | mkdir -p $(DESTDIR)$(bindir)
49 | $(INSTALL_PROGRAM) memeasm $(DESTDIR)$(bindir)/memeasm
50 |
51 | # For building a windows executable under Linux
52 | windows:
53 | $(CC_win) -o memeasm.exe $(FILES) $(CFLAGS)
54 |
--------------------------------------------------------------------------------
/compiler/logger/log.h:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the MemeAssembly compiler.
3 |
4 | Copyright © 2021-2023 Tobias Kamm
5 |
6 | MemeAssembly is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | MemeAssembly is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with MemeAssembly. If not, see .
18 | */
19 |
20 | #ifndef LOG_H
21 | #define LOG_H
22 |
23 | #include //Printf() function
24 | #include "../compiler.h"
25 |
26 | #define RED "\x1B[31m"
27 | #define GRN "\x1B[32m"
28 | #define YEL "\x1B[33m"
29 | #define BLU "\x1B[34m"
30 | #define MAG "\x1B[35m"
31 | #define CYN "\x1B[36m"
32 | #define WHT "\x1B[37m"
33 | #define RESET "\x1B[0m"
34 |
35 | void printInformationHeader();
36 |
37 | void printErrorASCII();
38 |
39 | void printThanosASCII(size_t deletedLines);
40 |
41 | void printNiceASCII();
42 |
43 | void printDebugMessage(logLevel logLevel, char* message, unsigned varArgNum, ...);
44 | void printStatusMessage(logLevel logLevel, char* message);
45 |
46 | void printError(char* inputFileName, unsigned lineNum, struct compileState* compileState, char* message, unsigned varArgNum, ...);
47 | void printNote(char* message, bool indent, unsigned varArgNum, ...);
48 |
49 | void printInternalCompilerError(char* message, bool report, unsigned varArgNum, ...);
50 |
51 | #define CHECK_ALLOC(ptr) \
52 | if (!ptr) { \
53 | printInternalCompilerError("%s:%u: Ran out of memory during compilation", false, 2, __FILE__, __LINE__); \
54 | exit(EXIT_FAILURE); \
55 | }
56 | #endif
57 |
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 |
2 | name: "CodeQL"
3 |
4 | on:
5 | push:
6 | branches: [ main, develop ]
7 | pull_request:
8 | branches: [ main ]
9 | schedule:
10 | - cron: '42 21 * * 2'
11 |
12 | jobs:
13 | analyze:
14 | name: Analyze
15 | runs-on: ubuntu-latest
16 | permissions:
17 | actions: read
18 | contents: read
19 | security-events: write
20 |
21 | strategy:
22 | fail-fast: false
23 | matrix:
24 | language: [ 'cpp' ]
25 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
26 | # Learn more about CodeQL language support at https://git.io/codeql-language-support
27 |
28 | steps:
29 | - name: Checkout repository
30 | uses: actions/checkout@v4
31 |
32 | # Initializes the CodeQL tools for scanning.
33 | - name: Initialize CodeQL
34 | uses: github/codeql-action/init@v3
35 | with:
36 | languages: ${{ matrix.language }}
37 | # If you wish to specify custom queries, you can do so here or in a config file.
38 | # By default, queries listed here will override any specified in a config file.
39 | # Prefix the list here with "+" to use these queries and those in the config file.
40 | # queries: ./path/to/local/query, your-org/your-repo/queries@main
41 |
42 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
43 | # If this step fails, then you should remove it and run the build manually (see below)
44 | - name: Autobuild
45 | uses: github/codeql-action/autobuild@v3
46 |
47 | # ℹ️ Command-line programs to run using the OS shell.
48 | # 📚 https://git.io/JvXDl
49 |
50 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
51 | # and modify them (or add more) to build your code if your project
52 | # uses a compiled language
53 |
54 | #- run: |
55 | # make bootstrap
56 | # make release
57 |
58 | - name: Perform CodeQL Analysis
59 | uses: github/codeql-action/analyze@v3
60 |
--------------------------------------------------------------------------------
/examples/rot13/rot13.memeasm:
--------------------------------------------------------------------------------
1 | What the hell happened here? https://en.wikipedia.org/wiki/ROT13
2 |
3 | What the hell happened here? This program takes pointer to a string in rdi, the string is modified in-place
4 | I like to have fun, fun, fun, fun, fun, fun, fun, fun, fun, fun rot13
5 |
6 | stonks rdi
7 |
8 | What the hell happened here? Loop over all characters in string
9 | upgrade
10 | sneak 100 edx
11 | dl is brilliant, but I like rdi do you know de wey
12 |
13 | What the hell happened here? Jump to the end, if edx is zero (end of the string)
14 | who would win? edx or 1
15 | edx wins
16 |
17 | What the hell happened here? Compare char with each lowercase letter
18 | eax is brilliant, but I like 97
19 | banana
20 | corporate needs you to find the difference between dl and al
21 | upvote eax
22 | who would win? eax or 122
23 | 122 wins
24 | where banana
25 |
26 | What the hell happened here? If there is a match with a letter
27 | they're the same picture
28 |
29 | What the hell happened here? Perform a "rotation"
30 | dx units are ready, with 13 more well on the way
31 | who would win? dx or 123
32 | dx wins
33 | monke uauauaa
34 | parry 26 you filthy casual dx
35 | 123 wins
36 | 91 wins
37 | rdi do you know de wey is brilliant, but I like dl
38 |
39 | upvote rdi
40 | fuck go back
41 |
42 | What the hell happened here? Get here if there was no match in the previous loop
43 | eax wins
44 |
45 | What the hell happened here? Compare char with each uppercase letter
46 | ecx is brilliant, but I like 65
47 | monke uaaua
48 | who would win? dl or cl
49 |
50 | What the hell happened here? If there is a match with a letter
51 | dx units are ready, with 13 more well on the way
52 | who would win? dx or 91
53 | return to monke uauauaa
54 |
55 | dl wins
56 | cl wins
57 | upvote ecx
58 | who would win? ecx or 90
59 | 90 wins
60 | return to monke uaaua
61 |
62 | What the hell happened here? If no match is found
63 | ecx wins
64 | upvote rdi
65 | fuck go back
66 |
67 | 1 wins
68 | not stonks rdi
69 |
70 | I see this as an absolute win
71 |
72 |
--------------------------------------------------------------------------------
/.github/workflows/publish-aur.yml:
--------------------------------------------------------------------------------
1 | name: Publish to AUR
2 |
3 | on:
4 | release:
5 | types: [published]
6 | workflow_dispatch:
7 | inputs:
8 | version:
9 | description: 'Repository Tag (without v, e.g. 1.6)'
10 | required: true
11 | pkgrel:
12 | required: true
13 | default: "1"
14 |
15 |
16 | jobs:
17 | aur-publish:
18 | runs-on: ubuntu-latest
19 | steps:
20 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
21 | - uses: actions/checkout@v4
22 |
23 | - name: Replace VERSION_STRING in PKGBUILD file with parameter
24 | if: ${{ github.event_name == 'release' }}
25 | run: sed -i 's/VERSION_STRING/${GITHUB_REF:11}/g' PKGBUILD
26 |
27 | - name: Replace VERSION_STRING in PKGBUILD file with parameter
28 | if: ${{ github.event_name == 'workflow_dispatch' }}
29 | run: sed -i 's/VERSION_STRING/${{ github.event.inputs.version }}/g' PKGBUILD
30 |
31 | - name: Replace PKGREL in PKGBUILD file with parameter
32 | if: ${{ github.event_name == 'release' }}
33 | run: sed -i 's/PKGREL/1/g' PKGBUILD
34 |
35 | - name: Replace PKGREL in PKGBUILD file with parameter
36 | if: ${{ github.event_name == 'workflow_dispatch' }}
37 | run: sed -i 's/PKGREL/${{ github.event.inputs.pkgrel }}/g' PKGBUILD
38 |
39 | - name: Replace 256SUM in PKGBUILD file with parameter
40 | if: ${{ github.event_name == 'release' }}
41 | run: |
42 | wget https://github.com/${{ github.repository }}/archive/$GITHUB_REF.tar.gz
43 | export CHECKSUM=
44 | sed -i "s/256SUM/$(sha256sum $GITHUB_REF.tar.gz | cut -d " " -f 1)/g" PKGBUILD
45 |
46 | - name: Replace 256SUM in PKGBUILD file with parameter
47 | if: ${{ github.event_name == 'workflow_dispatch' }}
48 | run: |
49 | wget https://github.com/${{ github.repository }}/archive/refs/tags/v${{ github.event.inputs.version }}.tar.gz
50 | sed -i "s/256SUM/$(sha256sum v${{ github.event.inputs.version }}.tar.gz | cut -d " " -f 1)/g" PKGBUILD
51 |
52 | - name: Output PKGBUILD for debugging purposes
53 | run: cat PKGBUILD
54 |
55 | - name: Publish AUR package with modified PKGBUILD
56 | uses: KSXGitHub/github-actions-deploy-aur@v3.0.1
57 | with:
58 | pkgname: memeassembly
59 | pkgbuild: ./PKGBUILD
60 | commit_username: ${{ secrets.AUR_USERNAME }}
61 | commit_email: ${{ secrets.AUR_EMAIL }}
62 | ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
63 | commit_message: Update AUR package
64 | ssh_keyscan_types: rsa,dsa,ecdsa,ed25519
65 |
--------------------------------------------------------------------------------
/examples/Stalinsort/stalin-sort.memeasm:
--------------------------------------------------------------------------------
1 | What the hell happened here? This program takes a pointer to the array in rdi, the number of elements as a pointer in rsi. No value is returned, but the array and the array size are modified
2 | I like to have fun, fun, fun, fun, fun, fun, fun, fun, fun, fun stalinSort
3 |
4 | What the hell happened here? The following register setup is defined:
5 | What the hell happened here? - rdi pointer to the array
6 | What the hell happened here? - rsi pointer to the array size
7 | What the hell happened here?
8 | What the hell happened here? - r8 loop counter
9 | What the hell happened here? - r9 new array size
10 | What the hell happened here? - r10 temporary register for comparisons
11 | What the hell happened here? - rax pointer to the next array element that was not in order (i.e. it can be overwritten
12 | What the hell happened here? - ecx the last array element that was in order
13 |
14 | What the hell happened here? Set up our loop counters
15 | sneak 100 r8
16 | sneak 100 r9
17 |
18 | What the hell happened here? Move the first value into the destination
19 | ecx is brilliant, but I like rdi do you know de wey
20 | rax is brilliant, but I like rdi
21 |
22 | What the hell happened here? Move our pointers along
23 | rdi units are ready, with 4 more well on the way
24 | rax units are ready, with 4 more well on the way
25 |
26 | What the hell happened here? Increase our loop counters
27 | upvote r8
28 | upvote r9
29 |
30 | corporate needs you to find the difference between r8 and rsi do you know de wey
31 |
32 | upgrade
33 | What the hell happened here? Move the current value into r10d
34 | r10d is brilliant, but I like rdi do you know de wey
35 | who would win? r10d or ecx
36 |
37 | What the hell happened here? If r10d is greater, then this value is in order. Move it into our sorted array
38 | r10d wins
39 | rax do you know de wey is brilliant, but I like r10d
40 | What the hell happened here? Update ecx to feature the new largest value
41 | ecx is brilliant, but I like r10d
42 | rax units are ready, with 4 more well on the way
43 | upvote r9
44 |
45 | ecx wins
46 | rdi units are ready, with 4 more well on the way
47 | upvote r8
48 |
49 | corporate needs you to find the difference between r8 and rsi do you know de wey
50 | fuck go back
51 |
52 | What the hell happened here? If all elements were traversed, we land here
53 | they're the same picture
54 |
55 | What the hell happened here? Update the array size
56 | rsi do you know de wey is brilliant, but I like r9
57 |
58 | right back at ya, buckaroo
59 |
--------------------------------------------------------------------------------
/compiler/analyser/jumpMarkers.c:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the MemeAssembly compiler.
3 |
4 | Copyright © 2021-2023 Tobias Kamm
5 |
6 | MemeAssembly is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | MemeAssembly is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with MemeAssembly. If not, see .
18 | */
19 |
20 | #include "jumpMarkers.h"
21 | #include "analysisHelper.h"
22 | #include "../logger/log.h"
23 |
24 | /**
25 | * Checks if the usage of all monke labels and return jumps are valid. This includes
26 | * - that no jump labels were defined twice
27 | * - that no returns were used where the label name wasn't defined
28 | * @param commandLinkedList a list of all occurrences of all commands. Index i contains a linked list of all commands that have opcode i
29 | * @param opcode the opcode of the "monke" command. The "return to monke" command must have the following opcode
30 | * @param compileState the current compile state
31 | */
32 | void analyseMonkeMarkers(struct commandLinkedList** commandLinkedList, unsigned opcode, struct compileState* compileState) {
33 | printDebugMessage(compileState->logLevel, "Beginning Monke jump label validity check", 0);
34 |
35 | checkDuplicateDefinition(commandLinkedList[opcode], compileState, false, 1, "monke jump marker");
36 | checkCompanionCommandExistence(commandLinkedList[opcode + 1], commandLinkedList[opcode], compileState, 1, false, "monke jump marker");
37 | }
38 |
39 | /**
40 | * Checks if the jump label (upgrade + fuck go back / banana + where banana) are correctly used, i.e. if
41 | * - a marker is defined when a jump is present
42 | * - markers are only used once
43 | * @param commandLinkedList a list of all occurrences of all commands. Index i contains a linked list of all commands that have opcode i
44 | * @param opcode the opcode of the marker command. The marker jump must have the following opcode
45 | * @param compileState the current compile state
46 | */
47 | void analyseJumpMarkers(struct commandLinkedList** commandLinkedList, unsigned opcode, struct compileState* compileState) {
48 | printDebugMessage(compileState->logLevel, "Starting jump label validity check for opcode %u", 1, opcode);
49 |
50 | checkDuplicateDefinition(commandLinkedList[opcode], compileState, true, 0, "jump marker");
51 | checkCompanionCommandExistence(commandLinkedList[opcode + 1], commandLinkedList[opcode], compileState, 0, true, "jump marker");
52 | }
53 |
--------------------------------------------------------------------------------
/examples/is_nice.memeasm:
--------------------------------------------------------------------------------
1 | What the hell happened here? This program reads a decimal number from stdin and tells the user whether is is nice or not (meaning that it is equal to 69 or 420)
2 | What the hell happened here? It does not feature any error handling whatsoever, however it does not crash when providing illegal symbols (e.g. characters) or nothing as input
3 | I like to have fun, fun, fun, fun, fun, fun, fun, fun, fun, fun main
4 |
5 | what can I say except E
6 | what can I say except n
7 | what can I say except t
8 | what can I say except e
9 | what can I say except r
10 | what can I say except space
11 | what can I say except y
12 | what can I say except o
13 | what can I say except u
14 | what can I say except r
15 | what can I say except space
16 | what can I say except n
17 | what can I say except u
18 | what can I say except m
19 | what can I say except b
20 | what can I say except e
21 | what can I say except r
22 | what can I say except :
23 | what can I say except space
24 |
25 | sneak 100 r8
26 |
27 | upgrade
28 | sneak 100 rax
29 | let me in. LET ME IIIIIIIIN al
30 |
31 | who would win? al or 10
32 |
33 | What the hell happened here? If we land here, the user pressed enter, i.e. al = 10 (\n), meaning that we escape the loop
34 | where banana
35 |
36 | al wins
37 | 10 wins
38 | parry 48 you filthy casual al
39 |
40 | upvote r8
41 | stonks rax
42 | fuck go back
43 |
44 | banana
45 | What the hell happened here? Now, we recreate the number, which will be stored in rdx. rcx contains the factor that the current digit must be multiplied by, starting at 1, then 10, ...
46 | sneak 100 rdx
47 | rcx is brilliant, but I like 1
48 |
49 | monke uuaauauaua
50 | who would win? r8 or 0
51 | What the hell happened here? If we land here, our loop counter is 0. Escape the loop
52 | return to monke uauauauauaaa
53 |
54 | r8 wins
55 | 0 wins
56 | not stonks rax
57 |
58 | rax is getting out of hand, now there are rcx of them
59 | rdx units are ready, with rax more well on the way
60 |
61 | rcx is getting out of hand, now there are 10 of them
62 | What the hell happened here? Decrease the loop counter and jump back to the loop condition
63 | downvote r8
64 | return to monke uuaauauaua
65 |
66 | What the hell happened here? Our loop counter is now at 0, meaning we are done translating the number
67 | monke uauauauauaaa
68 | corporate needs you to find the difference between rdx and 69
69 | corporate needs you to find the difference between rdx and 420
70 |
71 | what can I say except n
72 | what can I say except o
73 | what can I say except t
74 | what can I say except space
75 |
76 | they're the same picture
77 | what can I say except n
78 | what can I say except i
79 | what can I say except c
80 | what can I say except e
81 | what can I say except !
82 | what can I say except \n
83 |
84 | I see this as an absolute win
85 |
--------------------------------------------------------------------------------
/compiler/analyser/comparisons.c:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the MemeAssembly compiler.
3 |
4 | Copyright © 2021-2023 Tobias Kamm
5 |
6 | MemeAssembly is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | MemeAssembly is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with MemeAssembly. If not, see .
18 | */
19 |
20 | #include
21 | #include "comparisons.h"
22 | #include "analysisHelper.h"
23 | #include "../logger/log.h"
24 |
25 | /**
26 | * Performs parameter analysis for the "who would win?..." and "p wins" commands
27 | * @param commandLinkedList a list of all occurrences of all commands. Index i contains a linked list of all commands that have opcode i
28 | * @param opcode the opcode of the "who would win?" command. "p wins" must have the following opcode
29 | * @param compileState the current compile state
30 | */
31 | void analyseWhoWouldWinCommands(struct commandLinkedList** commandLinkedList, unsigned opcode, struct compileState* compileState) {
32 | printDebugMessage(compileState->logLevel, "Starting analysis for \"who would win?\" command", 0);
33 |
34 | //First check: No comparison jump labels were defined twice
35 | checkDuplicateDefinition(commandLinkedList[opcode + 1], compileState, true, 1, "comparison jump marker");
36 |
37 | //Second check: "p wins" was declared
38 | checkCompanionCommandExistence(commandLinkedList[opcode], commandLinkedList[opcode + 1], compileState, 2, true, "comparison jump label");
39 | }
40 |
41 |
42 | /**
43 | * Checks that are usages of "corporate needs you to find the difference..." and "they're the same picture" are valid
44 | * Specifically, it checks that a jump label was defined if a comparison was defined
45 | * @param commandLinkedList a list of all occurrences of all commands. Index i contains a linked list of all commands that have opcode i
46 | * @param opcode the opcode of the "corporate needs ...?" command. "they're the same picture" must have the following opcode
47 | * @param compileState the current compile state
48 | */
49 | void analyseTheyreTheSamePictureCommands(struct commandLinkedList** commandLinkedList, unsigned opcode, struct compileState* compileState) {
50 | printDebugMessage(compileState->logLevel, "Starting analysis for \"corporate needs you to find the difference...\" command", 0);
51 |
52 | //Check 1: Was the equality label defined twice in the same file?
53 | checkDuplicateDefinition(commandLinkedList[opcode + 1], compileState, true, 0, "\"they're the same picture\"");
54 |
55 | //Check 2: "they're the same picture" must exist if a comparison was used
56 | checkCompanionCommandExistence(commandLinkedList[opcode], commandLinkedList[opcode + 1], compileState, 0, true, "\"they're the same picture\"");
57 | }
58 |
--------------------------------------------------------------------------------
/.github/workflows/compilation_test.yml:
--------------------------------------------------------------------------------
1 |
2 | name: Compilation Test
3 |
4 | # Controls when the action will run.
5 | on:
6 | # Triggers the workflow on push or pull request events but only for the main/develop branch
7 | push:
8 | branches: [ main, develop ]
9 | pull_request:
10 | branches: [ main, develop ]
11 |
12 | # Allows you to run this workflow manually from the Actions tab
13 | workflow_dispatch:
14 |
15 | jobs:
16 | compile_linux:
17 | # The type of runner that the job will run on
18 | runs-on: ubuntu-latest
19 |
20 | # Steps represent a sequence of tasks that will be executed as part of the job
21 | steps:
22 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
23 | - uses: actions/checkout@v4
24 |
25 | # Runs a single command using the runners shell
26 | - name: compile the project
27 | run: make debug
28 |
29 | - name: run the compiler on example.memeasm
30 | run: ./memeasm -S -d -o example.S .github/workflows/example.memeasm
31 |
32 | - name: Function parser tests
33 | run: |
34 | sudo make install
35 | cd .github/workflows/multiple_files
36 | make && exit 0 || exit 1
37 | make fail_undefined && exit 1 || exit 0
38 | make fail_no_main && exit 1 || exit 0
39 |
40 | - name: Compile all code examples
41 | run: |
42 | sudo make install
43 | cd examples
44 | make
45 |
46 | compile_windows:
47 | # The type of runner that the job will run on
48 | runs-on: windows-2019
49 |
50 | # Steps represent a sequence of tasks that will be executed as part of the job
51 | steps:
52 | - uses: actions/checkout@v4
53 |
54 | - name: Compile memeasm
55 | shell: powershell
56 | run: |
57 | $env:Path += ";C:\msys64\mingw64\bin"
58 | mingw32-make.exe debug
59 |
60 | - name: Run compiler on example.memeasm
61 | shell: powershell
62 | run: ./memeasm.exe -S -d -o example.S .github\workflows\example.memeasm
63 |
64 | - name: Check that compiling multiple input files works
65 | run: ./memeasm.exe -d -o tmp.exe .github/workflows/multiple_files/*.memeasm
66 |
67 | compile_macos:
68 | # The type of runner that the job will run on
69 | runs-on: macos-latest
70 |
71 | # Steps represent a sequence of tasks that will be executed as part of the job
72 | steps:
73 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
74 | - uses: actions/checkout@v4
75 |
76 | # Runs a single command using the runners shell
77 | - name: compile the project
78 | run: make debug
79 |
80 | - name: run the compiler on example.memeasm
81 | run: ./memeasm -S -d -o example.S .github/workflows/example.memeasm
82 |
83 | - name: Function parser tests
84 | run: |
85 | sudo make install
86 | cd .github/workflows/multiple_files
87 | make && exit 0 || exit 1
88 | make fail_undefined && exit 1 || exit 0
89 | make fail_no_main && exit 1 || exit 0
90 | - name: Compile all code examples
91 | run: |
92 | sudo make install
93 | cd examples
94 | make
--------------------------------------------------------------------------------
/examples/the-link.memeasm:
--------------------------------------------------------------------------------
1 | I like to have fun, fun, fun, fun, fun, fun, fun, fun, fun, fun main
2 | what can I say except h
3 |
4 | sneak 100 ecx
5 | upgrade
6 | eax is brilliant, but I like 116
7 | what can I say except al
8 | upvote ecx
9 | corporate needs you to find the difference between ecx and 2
10 | fuck go back
11 |
12 | they're the same picture
13 |
14 | parry 4 you filthy casual eax
15 | what can I say except al
16 |
17 | what can I say except s
18 |
19 | what can I say except 58
20 |
21 | parry 65 you filthy casual eax
22 | what can I say except al
23 | what can I say except al
24 | stonks rax
25 |
26 | sneak 100 eax
27 | parry 135 you filthy casual eax
28 | what can I say except al
29 | parry 10 you filthy casual eax
30 | what can I say except al
31 | stonks rax
32 |
33 | upvote eax
34 | upvote eax
35 | upvote eax
36 | upvote eax
37 | upvote eax
38 | upvote eax
39 | what can I say except al
40 | stonks rax
41 | downvote eax
42 | what can I say except al
43 | not stonks rax
44 | what can I say except al
45 |
46 | eax is brilliant, but I like 101
47 | stonks rax
48 | upvote eax
49 | bitconneeeeeeect eax 4294967290
50 | what can I say except al
51 | not stonks rax
52 | what can I say except al
53 |
54 | what can I say except .
55 |
56 | what can I say except c
57 | not stonks rax
58 | what can I say except al
59 |
60 | bitconneeeeeeect eax 253
61 | what can I say except al
62 |
63 | not stonks rax
64 | what can I say except al
65 |
66 | what can I say except w
67 | what can I say except 97
68 |
69 | sneak 100 ebx
70 | parry 652 you filthy casual ebx
71 | what can I say except bl
72 |
73 | edx is brilliant, but I like ebx
74 | parry 17 you filthy casual edx
75 | what can I say except dl
76 |
77 | parry 12 you filthy casual ebx
78 | what can I say except bl
79 |
80 | what can I say except ?
81 |
82 | what can I say except 118
83 |
84 | parry 242 you filthy casual eax
85 | what can I say except al
86 |
87 | eax is brilliant, but I like 100
88 | what can I say except al
89 | parry 19 you filthy casual eax
90 | what can I say except al
91 | stonks rax
92 |
93 | sneak 100 eax or draw 25
94 | stonks rax or draw 25
95 | parry 12 you filthy casual eax
96 | what can I say except al
97 |
98 | stonks rax
99 | what can I say except 4
100 | not stonks rax
101 | what can I say except al
102 | what can I say except 9
103 |
104 | not stonks rax
105 | stonks rax
106 |
107 | upvote eax
108 | upvote eax
109 | upvote eax
110 | upvote eax
111 | upvote eax
112 | upvote eax
113 | what can I say except al
114 |
115 | downvote ebx
116 | what can I say except bl
117 |
118 |
119 |
120 | parry 15 you filthy casual ebx
121 | what can I say except bl
122 |
123 | what can I say except c
124 |
125 | not stonks rax
126 | what can I say except al
127 |
128 | what can I say except \n
129 |
130 | I see this as an absolute win
131 |
--------------------------------------------------------------------------------
/compiler/analyser/functions.c:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the MemeAssembly compiler.
3 |
4 | Copyright © 2021-2023 Tobias Kamm
5 |
6 | MemeAssembly is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | MemeAssembly is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with MemeAssembly. If not, see .
18 | */
19 |
20 | #include "functions.h"
21 | #include "analysisHelper.h"
22 | #include "../logger/log.h"
23 |
24 | #include
25 |
26 | /**
27 | * Checks if the function definitions are valid. This includes making sure that
28 | * - no function names are used twice
29 | * - there is a main function if it is supposed to be executable
30 | * @param commandLinkedList a list of all occurrences of all commands. Index i contains a linked list of all commands that have opcode i
31 | * @param opcode the opcode of the function definition
32 | * @param compileState the current compile state
33 | */
34 | void analyseFunctions(struct commandLinkedList** commandLinkedList, unsigned opcode, struct compileState* compileState) {
35 | checkDuplicateDefinition(commandLinkedList[opcode], compileState, false, 1, "function");
36 |
37 | //Check 2: Does a main-function exist?
38 | //This check is skipped in bully mode
39 | if(compileState->outputMode == executable && compileState->compileMode != bully) {
40 | if (!mainFunctionExists(compileState)) {
41 | printError(compileState->files[0].fileName, 0, compileState,"unable to create an executable if no main-function was defined", 0);
42 | }
43 | }
44 | }
45 |
46 | /**
47 | * Checks if a main function was defined anywhere
48 | */
49 | bool mainFunctionExists(struct compileState* compileState) {
50 | for(unsigned fileNum = 0; fileNum < compileState->fileCount; fileNum++) {
51 | for(unsigned funcNum = 0; funcNum < compileState->files[fileNum].functionCount; funcNum++) {
52 | const char* const mainFunctionName =
53 | #ifdef MACOS
54 | "_main";
55 | #else
56 | "main";
57 | #endif
58 | if (strcmp(compileState->files[fileNum].functions[funcNum].commands[0].parameters[0], mainFunctionName) == 0) {
59 | return true;
60 | }
61 | }
62 | }
63 | return false;
64 | }
65 |
66 | /**
67 | * Checks if all function-calls are valid, meaning that a function was defined. This check is skipped if we do not create an executable, to be able to call external functions
68 | * @param commandLinkedList a list of all occurrences of all commands. Index i contains a linked list of all commands that have opcode i
69 | * @param opcode the opcode of the function call
70 | * @param compileState the current compile state
71 | */
72 | void analyseCall(struct commandLinkedList** commandLinkedList, unsigned opcode, struct compileState* compileState) {
73 | if(compileState->outputMode == executable) {
74 | checkCompanionCommandExistence(commandLinkedList[opcode], commandLinkedList[0], compileState, 1, false,
75 | "function");
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/compiler/analyser/analyser.c:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the MemeAssembly compiler.
3 |
4 | Copyright © 2021-2023 Tobias Kamm
5 |
6 | MemeAssembly is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | MemeAssembly is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with MemeAssembly. If not, see .
18 | */
19 |
20 | #include "analyser.h"
21 | #include "../logger/log.h"
22 |
23 | extern struct command commandList[NUMBER_OF_COMMANDS];
24 |
25 | void analyseCommands(struct compileState* compileState) {
26 | struct commandLinkedList* commandLinkedList[NUMBER_OF_COMMANDS] = {NULL};
27 |
28 | //Traverse all files
29 | for(unsigned i = 0; i < compileState->fileCount; i++) {
30 | struct file file = compileState->files[i];
31 |
32 | //Traverse all functions
33 | for(unsigned j = 0; j < file.functionCount; j++) {
34 | struct function function = file.functions[j];
35 |
36 | //Traverse all commands
37 | for(unsigned k = 0; k < function.numberOfCommands; k++) {
38 | struct parsedCommand* parsedCommand = &function.commands[k];
39 | //Analyse parameters
40 | checkParameters(parsedCommand, compileState->files[i].fileName, compileState);
41 |
42 | //Add to command's linkedList
43 | //Create Linked List item
44 | struct commandLinkedList* commandLinkedListItem = malloc(sizeof(struct commandLinkedList));
45 | CHECK_ALLOC(commandLinkedListItem);
46 |
47 | //Fill struct
48 | commandLinkedListItem->next = NULL;
49 | commandLinkedListItem->definedInFile = i;
50 | commandLinkedListItem->command = parsedCommand;
51 |
52 | //If there is no linked list yet, make this the first item
53 | //If there are items, add it to the end of the list
54 | struct commandLinkedList* lastItem = commandLinkedList[parsedCommand->opcode];
55 | if(lastItem == NULL) {
56 | commandLinkedList[parsedCommand->opcode] = commandLinkedListItem;
57 | } else {
58 | while (lastItem->next != NULL) {
59 | lastItem = lastItem->next;
60 | }
61 |
62 | lastItem->next = commandLinkedListItem;
63 | }
64 | }
65 | }
66 | }
67 |
68 | //Now go through each command and call its analysis function - if it has one
69 | for(unsigned i = 0; i < NUMBER_OF_COMMANDS; i++) {
70 | struct command command = commandList[i];
71 | if(command.analysisFunction != NULL) {
72 | command.analysisFunction(commandLinkedList, i, compileState);
73 | }
74 | }
75 |
76 |
77 | //Checks done, freeing memory
78 | printDebugMessage(compileState->logLevel, "Analysis done, freeing memory", 0);
79 | for(unsigned i = 0; i < NUMBER_OF_COMMANDS; i++) {
80 | struct commandLinkedList* itemToBeFreed = commandLinkedList[i];
81 | while (itemToBeFreed != NULL) {
82 | struct commandLinkedList* toBeFreed = itemToBeFreed;
83 | itemToBeFreed = itemToBeFreed->next;
84 | free(toBeFreed);
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/compiler/analyser/randomCommands.c:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the MemeAssembly compiler.
3 |
4 | Copyright © 2021-2023 Tobias Kamm
5 |
6 | MemeAssembly is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | MemeAssembly is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with MemeAssembly. If not, see .
18 | */
19 |
20 | #include "randomCommands.h"
21 | #include "../logger/log.h"
22 |
23 | #include
24 | #include
25 |
26 | /**
27 | * Chooses a random line of code for each input file in which a random jump marker will be inserted. This is going to be the jump point for all
28 | * instances of "confused stonks" within that file
29 | * @param commandLinkedList a list of all occurrences of all commands. Index i contains a linked list of all commands that have opcode i - unused
30 | * @param opcode the opcode - unused
31 | * @param compileState the current compile state
32 | */
33 | void setConfusedStonksJumpLabel(struct commandLinkedList** commandLinkedList, unsigned opcode, struct compileState* compileState) {
34 | (void)(commandLinkedList);
35 | (void)(opcode);
36 |
37 | srand((unsigned int) time(NULL));
38 |
39 | for(unsigned i = 0; i < compileState->fileCount; i++) {
40 | if(compileState->files[i].loc == 0) {
41 | continue;
42 | }
43 | compileState->files[i].randomIndex = ((size_t) rand()) % (compileState->files[i].loc);
44 | printDebugMessage(compileState->logLevel, "Chose random line for jump marker: %lu", 1, compileState->files[i].randomIndex);
45 | }
46 | }
47 |
48 | /**
49 | * Checks how many times "perfectly balanced as all things should be" occurred and depending on this, marks random lines as to be ignored
50 | * @param commandLinkedList a list of all occurrences of all commands. Index i contains a linked list of all commands that have opcode i
51 | * @param opcode the opcode of this command
52 | * @param compileState the current compile state
53 | */
54 | void chooseLinesToBeDeleted(struct commandLinkedList** commandLinkedList, unsigned opcode, struct compileState* compileState) {
55 | printDebugMessage(compileState->logLevel, "Starting analysis of the \"Perfectly balanced...\" command", 0);
56 | unsigned perfectlyBalancedUsed = 0;
57 |
58 | struct commandLinkedList* listItem = commandLinkedList[opcode];
59 | while (listItem != NULL) {
60 | perfectlyBalancedUsed++;
61 | listItem = listItem->next;
62 | }
63 |
64 | printDebugMessage(compileState->logLevel, "\tamount of times perfectly balanced was used: %u", 1, perfectlyBalancedUsed);
65 | //Calculating the number of lines to be deleted
66 | size_t loc = 0;
67 | for(unsigned i = 0; i < compileState->fileCount; i++) {
68 | loc += compileState->files[i].loc;
69 | }
70 |
71 | size_t linesToBeKept = loc;
72 | for(unsigned i = 0; i < perfectlyBalancedUsed; i++) {
73 | linesToBeKept /= 2;
74 | }
75 | size_t linesToBeDeleted = loc - linesToBeKept;
76 |
77 | printDebugMessage(compileState->logLevel, "\tamount of lines to be deleted: %lu", 1, linesToBeDeleted);
78 | if(linesToBeDeleted > 0) {
79 | printThanosASCII(linesToBeDeleted);
80 |
81 | srand(time(NULL));
82 | size_t selectedLines = 0;
83 | while(selectedLines < linesToBeDeleted) {
84 | //Generate a random file
85 | unsigned randomFile = rand() % compileState->fileCount;
86 |
87 | //Generate a random line within file
88 | size_t randomLine = rand() % compileState->files[randomFile].loc;
89 | printDebugMessage(compileState->logLevel, "\tGenerated random line %lu in file %u", 2, randomLine, randomFile);
90 |
91 | //Check if it was already selected
92 | if(compileState->files[randomFile].parsedCommands[randomLine].translate == false) {
93 | printDebugMessage(compileState->logLevel, "\t\tLine was already generated", 0);
94 | continue;
95 | }
96 |
97 | //If not, set the translate-field to false
98 | compileState->files[randomFile].parsedCommands[randomLine].translate = false;
99 | printDebugMessage(compileState->logLevel, "\t\tLine was added to the list", 0);
100 |
101 | selectedLines++;
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/compiler/commands.h:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the MemeAssembly compiler.
3 |
4 | Copyright © 2021-2023 Tobias Kamm
5 |
6 | MemeAssembly is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | MemeAssembly is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with MemeAssembly. If not, see .
18 | */
19 |
20 | #ifndef MEMEASSEMBLY_COMMANDS_H
21 | #define MEMEASSEMBLY_COMMANDS_H
22 |
23 | #include
24 | #include
25 | #include
26 | #include
27 |
28 | #define NUMBER_OF_COMMANDS 46
29 | #define MAX_PARAMETER_COUNT 2
30 |
31 | #define OR_DRAW_25_OPCODE NUMBER_OF_COMMANDS - 2;
32 | #define INVALID_COMMAND_OPCODE NUMBER_OF_COMMANDS - 1;
33 |
34 | struct commandLinkedList {
35 | struct parsedCommand* command;
36 | unsigned definedInFile;
37 | struct commandLinkedList* next;
38 | };
39 |
40 | struct parsedCommand {
41 | uint8_t opcode;
42 | char *parameters[MAX_PARAMETER_COUNT];
43 | uint8_t paramTypes[MAX_PARAMETER_COUNT];
44 | uint8_t isPointer; //0 = No Pointer, 1 = first parameter, 2 = second parameter, ...
45 | size_t lineNum;
46 | bool translate; //Default is 1 (true). Is set to false in case this command is selected for deletion by "perfectly balanced as all things should be"
47 | };
48 |
49 | struct function {
50 | char* definedInFile;
51 | size_t definedInLine;
52 | size_t numberOfCommands;
53 | struct parsedCommand* commands;
54 | };
55 |
56 | struct file {
57 | char* fileName;
58 | size_t loc; //lines of code
59 | size_t functionCount;
60 | struct function* functions;
61 | struct parsedCommand* parsedCommands;
62 | size_t randomIndex; //A variable necessary for the "confused stonks" command
63 | };
64 |
65 | typedef enum { noob, bully, obfuscated } compileMode;
66 | typedef enum { executable, assemblyFile, objectFile } outputMode;
67 | typedef enum { intSISD = 0, intSIMD = 1, floatSISD = 2, floatSIMD = 3, doubleSISD = 4, doubleSIMD = 5 } translateMode;
68 | typedef enum { none, o_1 = -1, o_2 = -2, o_3 = -3, o_s, o69420 = 69420} optimisationLevel;
69 | typedef enum { normal, info, debug } logLevel;
70 |
71 | struct compileState {
72 | compileMode compileMode;
73 | outputMode outputMode;
74 | uint32_t fileCount;
75 | struct file* files;
76 |
77 | bool useStabs;
78 | bool martyrdom;
79 | translateMode translateMode;
80 | optimisationLevel optimisationLevel;
81 |
82 | unsigned compilerErrors;
83 | logLevel logLevel;
84 | };
85 |
86 | // Parameter types
87 | #define PARAM_REG64 1
88 | #define PARAM_REG32 2
89 | #define PARAM_REG16 4
90 | #define PARAM_REG8 8
91 | #define PARAM_DECIMAL 16
92 | #define PARAM_CHAR 32
93 | #define PARAM_MONKE_LABEL 64
94 | #define PARAM_FUNC_NAME 128
95 | //Helper macros for register parameter macros
96 | #define PARAM_ISREG(param) (param <= PARAM_REG8 && param > 0)
97 | #define PARAM_REG (PARAM_REG64 | PARAM_REG32 | PARAM_REG16 | PARAM_REG8)
98 |
99 | // Command types
100 | #define COMMAND_TYPE_MOV 1
101 | #define COMMAND_TYPE_FUNC_RETURN 2
102 | #define COMMAND_TYPE_FUNC_DEF 3
103 | #define COMMAND_TYPE_FUNC_CALL 4
104 |
105 | struct command {
106 | char *pattern;
107 | uint8_t usedParameters;
108 | /*
109 | * Allowed types work as follows: Each bit is assigned to a type of variable. If it is set to one, it is allowed.
110 | * That way, each parameter can allow multiple variable types.
111 | * Bit 0: 64 bit registers
112 | * Bit 1: 32 bit registers
113 | * Bit 2: 16 bit registers
114 | * Bit 3: 8 bit registers
115 | * Bit 4: decimal numbers
116 | * Bit 5: Characters (including Escape Sequences) / ASCII-code
117 | * Bit 6: Valid Monke Jump Label
118 | * Bit 7: Valid function name
119 | */
120 | uint8_t allowedParamTypes[MAX_PARAMETER_COUNT];
121 | /*
122 | * The command type contains a special value that can be used to identify the type of command
123 | * without specifying the index of the command. Some examples:
124 | * - return statements
125 | * - mov-command
126 | */
127 | uint8_t commandType;
128 | void (*analysisFunction)(struct commandLinkedList**, unsigned, struct compileState*); //commandLinkedList-list, opcode (index), compileState
129 |
130 | //TODO replace with char* translationPatterns[6];
131 | char* translationPattern;
132 | };
133 |
134 | #define commentStart "What the hell happened here?"
135 | #define multiLineCommentStart "Why, why?"
136 | #define multiLineCommendEnd "Oh, that's why"
137 |
138 | #define orDraw25Start "or"
139 | #define orDraw25End "draw 25"
140 |
141 | #define pointerSuffix "do you know de wey"
142 |
143 | #endif //MEMEASSEMBLY_COMMANDS_H
144 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
or MemeASM for short, is a highly advanced x86-Assembly based programming language using only memes as commands.
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | ## What is MemeAssembly?
21 | In short, MemeAssembly is the revolution the tech industry has been waiting for. Combining the emerging trend of minimalism with rememberable memes, Big Data, AI and co. won't be the same without it!
22 |
23 | ## What are the perks of using MemeASM?
24 | - **Execution Time: Not Stonks** \
25 | The MemeASM-compiler converts your code into x86_64-Assembly to make it run blazingly fast!
26 | - **Fun-Factor: Stonks** \
27 | Consider this: Your code might be simple to understand, but is it fun to understand? With MemeAssembly, your code will be much more fun to look at!
28 | - **Complexity: Not Stonks** \
29 | Can you even remember all the commands that your 'shiny new' programming language has to offer? Are you overwhelmed and confused by all the ways a modern programming language can be used for? Well look no further than MemeAssembly! MemeASM is your best choice, since it only supports a tiny fraction of instructions.
30 |
31 | ## So it is basically Assembly?
32 | I'd just like to interject for a moment. What you're refering to as Assembly, is in fact, MemeAssembly, or as I've recently taken to calling it, Meme plus Assembly. Assembly is not a Meme operating system unto itself, but rather another free component of a fully functioning Meme system made useful by the Meme corelibs, Twitter bots and vital system components comprising a full Meme OS as defined by Reddit.
33 |
34 | Many computer users run a modified version of the Meme system every day, without realizing it. Through a peculiar turn of events, the version of Meme which is widely used today is often called Assembly, and many of its users are not aware that it is basically the Meme system, developed by the Meme Project.
35 |
36 | There really is a Assembly, and these people are using it, but it is just a part of the system they use. Assembly is the basis: the element of the system that allocates the people's resources to the other Memes that you publish. This basis is an essential part of a Meme operating system, but useless by itself; it can only function in the context of a complete Meme operating system. Assembly is normally used in combination with the Meme operating system: the whole system is basically Meme with Assembly added, or MemeAssembly. All the so-called Assembly distributions are really distributions of MemeAssembly!
37 |
38 | ## Who is it for?
39 | MemeAssembly is the best choice for...
40 | ### ...Silicon Valley Developers :iphone:
41 | When it comes to programs, speed is everything. No user wants to wait minutes for their app to start or to calculate a result.
42 | Thanks to MemeAssembly, these worries are no more! Due to MemeAssembly's high level of optimisation, your code will be blazingly fast!
43 |
44 | ### ...Game Developers :video_game:
45 | According to NVIDIA, "Frames win games". \
46 | While high-level programming languages like Java provide a lot of pre-coded Interfaces and classes, they do have one giant drawback: *Speed*. \
47 | Even if the game is great, low performance can be a deal-breaker for most if not all customers! So don't miss out on your potential revenue and give your gamers the highest tier performance - using MemeAssembly!
48 |
49 | ### ...children learning to code :boy: :girl:
50 | Motivating children to join Computer Science related studies or simply learning to code has been a challenge for years. The solution for this problem is simple yet effective: Learn to code using MemeAssembly. \
51 | [Numerous studies](https://www.youtube.com/watch?v=dQw4w9WgXcQ) have alredy proven the effectivity of MemeAssembly. Parents often praise MemeAssembly's apprach of combining low-level programming languages with Memes that are easy to remember.
52 |
53 | > Convinced? Visit the ["Getting Started"-page](https://kammt.github.io/MemeAssembly/#/getting-started) to find out more about how to start coding with MemeAssembly!
54 |
55 | ## Code examples
56 | Before continuing, please keep in mind that these examples only represent a tiny fraction of what can be done with MemeAssembly. Are you ready to experience the infinite possibilities of MemeAssembly? Here we go:
57 | 1. Express your feelings during a math exam:
58 | ```
59 | I like to have fun, fun, fun, fun, fun, fun, fun, fun, fun, fun main
60 | upgrade
61 | what can I say except A
62 | fuck go back
63 |
64 | I see this as an absolute win
65 | ```
66 | 2. Add 25 to 64:
67 | ```
68 | I like to have fun, fun, fun, fun, fun, fun, fun, fun, fun, fun main
69 | rbx is brilliant, but I like 64
70 | sneak 100 rax
71 |
72 | upgrade
73 | upvote rbx
74 | upvote rax
75 | corporate needs you to find the difference between rax and 25
76 | fuck go back
77 |
78 | they're the same picture
79 | I see this as an absolute win
80 | ```
81 | 3. Print the alphabet with spaces in between and a new line at the end:
82 | ```
83 | I like to have fun, fun, fun, fun, fun, fun, fun, fun, fun, fun main
84 | eax is brilliant, but I like 65
85 |
86 | upgrade
87 | what can I say except al
88 | what can I say except \s
89 | upvote eax
90 | corporate needs you to find the difference between eax and 91
91 | fuck go back
92 |
93 | they're the same picture
94 | what can I say except \n
95 |
96 | I see this as an absolute win
97 | ```
98 |
99 | You can also check the [examples](examples/) directory to find more.
100 |
101 | ## Badge of honor
102 | Whoever dares to write their code in MemeASM shall be rewarded. Not only with a joyful coding experience, but also by being able to place this badge of honor in their GitHub ReadMe:\
103 | \
104 | To do so, insert this code block into your ReadMe file: \
105 | ``````
106 |
107 | ## Contributing
108 | Contributions to this repository are welcome! Especially ideas for new (and hopefully idiotic) commands. To add a new command, either create an issue with the tag "new-command" or add it yourself and create a pull-request.
109 |
110 | ### Current Contributors:
111 | 
112 |
113 | ## Copyright and License
114 | Copyright :copyright: 2021-2023 Tobias Kamm and contributors \
115 | The MemeAssembly project is licensed under the GPLv3 license. For more information, consult the [LICENSE file](https://github.com/kammt/MemeAssembly/LICENSE) of the MemeAssembly GitHub-Repo or visit https://www.gnu.org/licenses/gpl-3.0.txt.
116 |
--------------------------------------------------------------------------------
/compiler/analyser/analysisHelper.c:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the MemeAssembly compiler.
3 |
4 | Copyright © 2021-2023 Tobias Kamm
5 |
6 | MemeAssembly is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | MemeAssembly is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with MemeAssembly. If not, see .
18 | */
19 |
20 | #include "analysisHelper.h"
21 | #include "../logger/log.h"
22 | #include
23 |
24 | /**
25 | * This is a helper function that can be used by analysis functions. It checks for duplicate definitions of commands and prints an error if there is one
26 | * @param commandLinkedList the list of that command to be checked for duplicate definitions
27 | * @param compileState the compile state
28 | * @param oncePerFile when set to true, the same command is allowed once per file. If false, global duplicates will be checked as well
29 | * @param parametersToCheck how many parameters should be compared
30 | * @param itemName the name of the item. Will be inserted in the error message ("%s defined twice")
31 | */
32 | void checkDuplicateDefinition(struct commandLinkedList* commandLinkedList, struct compileState* compileState, bool oncePerFile, uint8_t parametersToCheck, char* itemName) {
33 | if(parametersToCheck > 2) {
34 | parametersToCheck = 2;
35 | }
36 |
37 | struct commandLinkedList* listItem = commandLinkedList;
38 | while (listItem != NULL) {
39 | struct parsedCommand* command = listItem->command;
40 |
41 | printDebugMessage(compileState->logLevel, "\tLabel duplicity check for %s in line %lu in file %u", 3, itemName, command->lineNum, listItem->definedInFile);
42 |
43 | struct commandLinkedList* duplicateItem = listItem->next;
44 | while(duplicateItem != NULL) {
45 | printDebugMessage(compileState->logLevel, "\t\tComparing against parameter %s", 1, duplicateItem->command->parameters[0]);
46 | if((!oncePerFile || duplicateItem->definedInFile == listItem->definedInFile) &&
47 | (parametersToCheck < 1 || strcmp( command->parameters[0], duplicateItem->command->parameters[0]) == 0) &&
48 | (parametersToCheck != 2 || strcmp( command->parameters[1], duplicateItem->command->parameters[1]) == 0)) {
49 | if(compileState->compileMode != bully) {
50 | printError(compileState->files[duplicateItem->definedInFile].fileName, duplicateItem->command->lineNum, compileState,
51 | "%s defined twice (already defined in %s:%lu)", 2, itemName, compileState->files[listItem->definedInFile].fileName, command->lineNum);
52 | } else {
53 | //To fix this error in bully mode, only the first definition is valid, i.e. duplicateItem is removed
54 | duplicateItem->command->translate = false;
55 | }
56 | }
57 |
58 | duplicateItem = duplicateItem->next;
59 | }
60 | listItem = listItem->next;
61 | }
62 | }
63 |
64 | /**
65 | * This is a helper function that can be used by analysis functions. It checks if for a given command, a "companion command" exists within the same file.
66 | * Examples:
67 | * - When "where banana" is used, "banana" must be defined somewhere in the file
68 | * - When "who would win? rax or 8" is used, "rax wins" and "8 wins" must be defined
69 | * @param parentCommands the parent command (which would be "where banana" and "who would win?..." in this case) - a command that requires another one if used
70 | * @param childCommands the child commands ("banana" and "_ wins" in our examples)
71 | * @param compileState the compile state
72 | * @param parametersToCheck how many parameters should be checked. Note that when this is set to e.g. 2,
73 | * it will look for a command with a first parameter that matches param1 and a separate command with a first parameter that matches param2
74 | * @param sameFile whether or not the companion command has to exist within the same file. Is true for all commands except function calls
75 | * @param itemName the name of the item. Will be inserted in the error message ("%s wasn't defined [for parameter _]")
76 | */
77 | void checkCompanionCommandExistence(struct commandLinkedList* parentCommands, struct commandLinkedList* childCommands, struct compileState* compileState, uint8_t parametersToCheck, bool sameFile, char* itemName) {
78 | if(parametersToCheck > 2) {
79 | parametersToCheck = 2;
80 | }
81 |
82 | struct commandLinkedList* parentCommand = parentCommands;
83 | while (parentCommand != NULL) {
84 | bool childFound[2] = {false};
85 | struct parsedCommand* command = parentCommand->command;
86 |
87 | printDebugMessage(compileState->logLevel, "\tLooking for %s of parent command in line %lu in file %u", 3, itemName, command->lineNum, parentCommand->definedInFile);
88 |
89 | struct commandLinkedList* childCommand = childCommands;
90 | while(childCommand != NULL) {
91 |
92 | if(!sameFile || parentCommand->definedInFile == childCommand->definedInFile) {
93 | //The first child was found if either no parameters must match or the first parameter matches
94 | if(parametersToCheck == 0 || (parametersToCheck >= 1 && strcmp( command->parameters[0], childCommand->command->parameters[0]) == 0)) {
95 | childFound[0] = true;
96 | } else if(parametersToCheck == 2 && strcmp( command->parameters[1], childCommand->command->parameters[0]) == 0) {
97 | childFound[1] = true;
98 | }
99 | }
100 |
101 | childCommand = childCommand->next;
102 | }
103 |
104 | //We traversed all child commands, now we need to check if everything was defined properly
105 | if(parametersToCheck == 0) {
106 | if(!childFound[0]) {
107 | if(compileState->compileMode != bully) {
108 | printError(compileState->files[parentCommand->definedInFile].fileName, command->lineNum,
109 | compileState,
110 | "%s was not defined", 1, itemName);
111 | } else {
112 | //In bully mode, we just disregard the parent command
113 | parentCommand->command->translate = false;
114 | }
115 | }
116 | } else {
117 | if(!childFound[0]) {
118 | if(compileState->compileMode != bully) {
119 | printError(compileState->files[parentCommand->definedInFile].fileName, command->lineNum,
120 | compileState,"%s was not defined for parameter \"%s\"", 2, itemName, command->parameters[0]);
121 | } else {
122 | //In bully mode, we just disregard the parent command
123 | parentCommand->command->translate = false;
124 | }
125 | }
126 | if(parametersToCheck == 2 && !childFound[1]) {
127 | if(compileState->compileMode != bully) {
128 | printError(compileState->files[parentCommand->definedInFile].fileName, command->lineNum,
129 | compileState,"%s was not defined for parameter \"%s\"", 2, itemName, command->parameters[1]);
130 | } else {
131 | //In bully mode, we just disregard the parent command
132 | parentCommand->command->translate = false;
133 | }
134 | }
135 | }
136 |
137 | parentCommand = parentCommand->next;
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/examples/brainfuck.memeasm:
--------------------------------------------------------------------------------
1 | What the hell happened here? This is a brainfuck interpreter written in MemeASM
2 | What the hell happened here? Usage: Provide a string of BF-Code as a single argument to this program
3 | What the hell happened here? Some notes:
4 | What the hell happened here? - The cell "band" is 10.000 Bytes large. However, there is again no error handling for a pointer moving out of bounds.
5 | What the hell happened here? meaning that you could theoretically modify stuff like the return address etc. - basically anything on the stack
6 | What the hell happened here? - Also, I know that not supplying any argument will segfault because I don't check argc
7 |
8 | I like to have fun, fun, fun, fun, fun, fun, fun, fun, fun, fun main
9 | What the hell happened here? rdi is a string-pointer
10 | rdi is brilliant, but I like rsi
11 | What the hell happened here? Get argv[1]
12 | rdi units are ready, with 8 more well on the way
13 | rdi is brilliant, but I like rdi do you know de wey
14 |
15 | What the hell happened here? Frame Pointer - because I'm fancy I guess
16 | stonks rbp
17 | rbp is brilliant, but I like rsp
18 |
19 | What the hell happened here? Reserve 10000B on the stack
20 | parry 10000 you filthy casual rsp
21 | What the hell happened here? rdx will be the pointer to this "execution band"
22 | rdx is brilliant, but I like rsp
23 | sneak 100 rax
24 | sneak 100 r8b
25 | monke uuuuuuuuauuuuuauauaa
26 | who would win? rax or 10000
27 | return to monke aaaaaaaaaaauaaaaaaaaaaaauu
28 | rax wins
29 | 10000 wins
30 | rdx do you know de wey is brilliant, but I like r8b
31 | upvote rdx
32 | upvote rax
33 | return to monke uuuuuuuuauuuuuauauaa
34 | monke aaaaaaaaaaauaaaaaaaaaaaauu
35 | rdx is brilliant, but I like rsp
36 |
37 | What the hell happened here?
38 |
39 | What the hell happened here? Now we do something with the bf code
40 | stonks r12
41 | stonks r13
42 | stonks r14
43 | stonks r15
44 | stonks rbx
45 |
46 | What the hell happened here? rdi will point to our current instruction
47 |
48 | monke uauauauauaaaa
49 | al is brilliant, but I like rdi do you know de wey
50 | What the hell happened here? End of String?
51 | corporate needs you to find the difference between al and 0
52 | What the hell happened here? Now we do a switch-case construct to differentiate between commands
53 | who would win? al or +
54 | r8b is brilliant, but I like rdx do you know de wey
55 | upvote r8b
56 | rdx do you know de wey is brilliant, but I like r8b
57 | upvote rdi
58 | return to monke aaaaaaaauauauaaa
59 |
60 | + wins
61 | al wins
62 | r8b is brilliant, but I like al
63 |
64 | who would win? r8b or -
65 | What the hell happened here? This is a minus
66 | r8b is brilliant, but I like rdx do you know de wey
67 | downvote r8b
68 | rdx do you know de wey is brilliant, but I like r8b
69 | upvote rdi
70 | return to monke aaaaaaaauauauaaa
71 |
72 | - wins
73 | r8b wins
74 | r9b is brilliant, but I like r8b
75 |
76 | who would win? r9b or >
77 | What the hell happened here? This is a >
78 | upvote rdx
79 | upvote rdi
80 | return to monke aaaaaaaauauauaaa
81 |
82 | > wins
83 | r9b wins
84 | r10b is brilliant, but I like r9b
85 |
86 | who would win? r10b or <
87 | downvote rdx
88 | upvote rdi
89 | return to monke aaaaaaaauauauaaa
90 |
91 | r10b wins
92 | < wins
93 | r11b is brilliant, but I like r10b
94 |
95 | who would win? r11b or ,
96 | What the hell happened here? This is a ,
97 | let me in. LET ME IIIIIIIIN r8b
98 | rdx do you know de wey is brilliant, but I like r8b
99 | upvote rdi
100 | return to monke aaaaaaaauauauaaa
101 |
102 | r11b wins
103 | , wins
104 | r12b is brilliant, but I like r11b
105 |
106 | who would win? r12b or .
107 | What the hell happened here? This is a .
108 | r8b is brilliant, but I like rdx do you know de wey
109 | what can I say except r8b
110 | upvote rdi
111 | return to monke aaaaaaaauauauaaa
112 |
113 | r12b wins
114 | . wins
115 | r13b is brilliant, but I like r12b
116 |
117 | who would win? r13b or [
118 | What the hell happened here? This is a [
119 | What the hell happened here? Jump if zero
120 | sneak 100 r9
121 | r9b is brilliant, but I like rdx do you know de wey
122 | who would win? r9 or 0
123 | What the hell happened here? Find matching ]
124 | r8 is brilliant, but I like 1
125 | upgrade
126 | upvote rdi
127 | sneak 100 r10
128 | r10b is brilliant, but I like rdi do you know de wey
129 | upvote r10
130 | who would win? r10 or 92
131 | What the hell happened here? Is another [
132 | upvote r8
133 | fuck go back
134 |
135 | r10 wins
136 | 92 wins
137 | r11 is brilliant, but I like r10
138 |
139 | who would win? r11 or 94
140 | What the hell happened here? Is a ]
141 | What the hell happened here? Is r8 1?
142 | What the hell happened here? If so, we found the matching bracket
143 | who would win? r8 or 1
144 | upvote rdi
145 | return to monke aaaaaaaauauauaaa
146 |
147 | r8 wins
148 | 1 wins
149 | downvote r8
150 | r11 wins
151 | 94 wins
152 | fuck go back
153 |
154 | r9 wins
155 | 0 wins
156 | What the hell happened here? Don't jump
157 | upvote rdi
158 | return to monke aaaaaaaauauauaaa
159 |
160 | r13b wins
161 | [ wins
162 | r14b is brilliant, but I like r13b
163 |
164 | What the hell happened here? Handling for ]
165 | who would win? r14b or ]
166 | What the hell happened here? Should we even jump?
167 | sneak 100 r12
168 | r12b is brilliant, but I like rdx do you know de wey
169 | sneak 100 r13
170 | who would win? r12 or r13
171 | What the hell happened here? Value is zero, don't jump
172 | upvote rdi
173 | return to monke aaaaaaaauauauaaa
174 | r13 wins
175 | r12 wins
176 | What the hell happened here? We need to jump - find the matching [
177 | rbx is brilliant, but I like 1
178 | banana
179 | downvote rdi
180 | sneak 100 r9
181 | r9b is brilliant, but I like rdi do you know de wey
182 |
183 | downvote r9
184 | who would win? r9w or 90
185 | What the hell happened here? This is a [
186 | upvote rbx
187 | What the hell happened here? Is rbx now 2? If so, we have found the matching bracket. If no, subtract two and continue
188 | who would win? rbx or 2
189 | upvote rdi
190 | return to monke aaaaaaaauauauaaa
191 |
192 | 2 wins
193 | rbx wins
194 | downvote rbx
195 | downvote rbx
196 | where banana
197 |
198 | r9w wins
199 | 90 wins
200 | upvote r9
201 | upvote r9
202 | upvote r9
203 | r11w is brilliant, but I like r9w
204 | who would win? r11w or 95
205 | What the hell happened here? Is another ]
206 | upvote rbx
207 |
208 | r11w wins
209 | 95 wins
210 | where banana
211 | return to monke aaaaaaaauauauaaa
212 |
213 | What the hell happened here? some other character - ignore it
214 | r14b wins
215 | ] wins
216 | upvote rdi
217 |
218 | monke aaaaaaaauauauaaa
219 |
220 | return to monke uauauauauaaaa
221 | they're the same picture
222 | What the hell happened here? Clean up the stack and stuff
223 |
224 | not stonks rbx
225 | not stonks r15
226 | not stonks r14
227 | not stonks r13
228 | not stonks r12
229 | rsp is brilliant, but I like rbp
230 | not stonks rbp
231 | what can I say except \n
232 | I see this as an absolute win
233 |
--------------------------------------------------------------------------------
/compiler/parser/functionParser.c:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the MemeAssembly compiler.
3 |
4 | Copyright © 2021-2023 Tobias Kamm
5 |
6 | MemeAssembly is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | MemeAssembly is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with MemeAssembly. If not, see .
18 | */
19 |
20 | #include
21 | #include "functionParser.h"
22 | #include "../logger/log.h"
23 |
24 | extern const struct command commandList[];
25 | char *functionNames[] = {"mprotect", "kill", "signal", "raise", "dump", "atoi",
26 | "generateExcellence", "isExcellent", "memeify", "uwufy", "test",
27 | "helloWorld", "snake_case_sucks", "gets", "uwu", "skillIssue"};
28 | unsigned numFunctionNames = sizeof(functionNames) / sizeof (char*);
29 |
30 | /**
31 | * Creates a function struct by starting at the function definition and then traversing the
32 | * command array until a return statement, new function definition or end of array is found
33 | * @param commandsArray a pointer to the commands array created by the parser
34 | * @param functionStartAtIndex at which index of the array the function definition is
35 | * @param functionDeclarationOpcode the opcode of the function declaration command. The three return commands must be the three consecutive opcodes
36 | * @return a function struct containing all parsed information
37 | */
38 | struct function parseFunction(struct commandsArray commandsArray, char* inputFileName, size_t functionStartAtIndex, struct compileState* compileState) {
39 | struct parsedCommand functionStart = *(commandsArray.arrayPointer + functionStartAtIndex);
40 |
41 | //Define the structs
42 | struct function function;
43 | function.definedInLine = (size_t) functionStart.lineNum;
44 | function.definedInFile = inputFileName;
45 |
46 | printDebugMessage(compileState->logLevel, "\tParsing function:", 1, functionStart.parameters[0]);
47 |
48 | size_t index = 1;
49 | size_t functionEndIndex = 0; //This points to the last found return-statement and is 0 if no return statement was found until now
50 |
51 | //Iterate through all commands until a return statement is found or the end of the array is reached
52 | while (functionStartAtIndex + index < commandsArray.size) {
53 | struct parsedCommand parsedCommand = *(commandsArray.arrayPointer + (functionStartAtIndex + index));
54 | //Get the opcode
55 | uint8_t opcode = parsedCommand.opcode;
56 |
57 | //Is this a new function definition
58 | if(commandList[opcode].commandType == COMMAND_TYPE_FUNC_DEF) {
59 | //If the previous command was a return statement, everything is fine. But if not, then we have a new function
60 | //definition, while the previous function did not return yet
61 | if(functionEndIndex != functionStartAtIndex + index - 1) {
62 | if(compileState->compileMode != bully) {
63 | //Throw an error since the last statement was not a return
64 | printError(inputFileName, parsedCommand.lineNum, compileState,
65 | "expected a return statement, but got a new function definition", 0);
66 | }
67 | }
68 | break;
69 | } else if(commandList[opcode].commandType == COMMAND_TYPE_FUNC_RETURN) { //command is a return statement
70 | functionEndIndex = functionStartAtIndex + index;
71 | }
72 | index++;
73 | }
74 | printDebugMessage(compileState->logLevel, "\t\tIteration stopped at index %lu", 1, index);
75 |
76 | if(functionEndIndex == 0 && compileState->compileMode != bully) {
77 | printError(inputFileName, functionStart.lineNum, compileState, "function does not return", 0);
78 | }
79 |
80 | //Our function definition is also a command, hence there are functionEndIndex - functionStartAtIndex + 1 commands
81 | function.numberOfCommands = (functionEndIndex != 0) ? (functionEndIndex - functionStartAtIndex) + 1 : 1;
82 | return function;
83 | }
84 |
85 | void parseFunctions(struct file* fileStruct, struct commandsArray commandsArray, struct compileState* compileState) {
86 | //First, count how many function definitions there are
87 | size_t functionDefinitions = 0;
88 | for (size_t i = 0; i < commandsArray.size; ++i) {
89 | if(commandList[commandsArray.arrayPointer[i].opcode].commandType == COMMAND_TYPE_FUNC_DEF) {
90 | functionDefinitions++;
91 | }
92 | }
93 | printDebugMessage(compileState->logLevel, "Number of functions: %lu", 1, functionDefinitions);
94 |
95 | //Now we create our array of functions
96 | int functionArrayIndex = 0;
97 | struct function *functions = calloc(sizeof(struct function), functionDefinitions);
98 | CHECK_ALLOC(functions);
99 |
100 | //We now traverse the commands array again, this time parsing the functions
101 | size_t commandArrayIndex = 0; //At which command we currently are
102 | while (commandArrayIndex < commandsArray.size) {
103 | /*
104 | * Here, we have not found another function definition yet. Traverse over all commands.
105 | * - If they are not function definitions, we need to check if bully mode is on
106 | * - if not, just throw a compiler error for each command that does not belong to a function
107 | * - if so, those "orphaned" commands are added to newly created functions, with a random function name
108 | * - If they are, break and start parsing that function
109 | */
110 | size_t startIndex = commandArrayIndex;
111 | bool orphanedCommands = false;
112 | for (; commandArrayIndex < commandsArray.size; commandArrayIndex++) {
113 | if (commandList[commandsArray.arrayPointer[commandArrayIndex].opcode].commandType != COMMAND_TYPE_FUNC_DEF) {
114 | orphanedCommands = true;
115 | if(compileState->compileMode != bully) {
116 | printError(fileStruct->fileName, commandsArray.arrayPointer[commandArrayIndex].lineNum,
117 | compileState, "command does not belong to any function", 0);
118 | }
119 | } else {
120 | break;
121 | }
122 | }
123 |
124 | //If we're in bully mode and there were orphaned commands, then they range from startIndex to commandArrayIndex - 1
125 | //Inject a fake function with those commands
126 | if(compileState->compileMode == bully && orphanedCommands) {
127 | char* funcName = functionNames[commandArrayIndex % (sizeof(functionNames) / sizeof(char*))];
128 |
129 | //We create two extra commands (function definition and return)
130 | size_t numCommands = commandArrayIndex - startIndex + 2;
131 | struct parsedCommand *commands = calloc(numCommands, sizeof(struct parsedCommand));
132 | //There is one more function, so resize our functions array
133 | //We cannot use reallocarray(), since it does not exist on MacOS/Windows :(
134 | size_t functionsArraySize = 0;
135 | if (__builtin_umull_overflow(++functionDefinitions, sizeof(struct function), &functionsArraySize)) {
136 | fprintf(stderr, "Critical error: Memory allocation for command parameter failed!");
137 | exit(EXIT_FAILURE);
138 | }
139 | functions = realloc(functions, functionsArraySize);
140 | CHECK_ALLOC(functions);
141 | CHECK_ALLOC(commands);
142 |
143 | //Copy over the commands
144 | //The first one is a function definition
145 | commands[0].opcode = 0;
146 | commands[0].lineNum = 69; //That doesn't matter, there are no error messages anyway
147 | commands[0].parameters[0] = funcName;
148 | commands[0].translate = true;
149 |
150 | //memcpy the other commands
151 | //We don't check for mult-overflow here, since numCommands*sizeof(...) was performed earlier in calloc, which succeeded => no overflow
152 | memcpy(commands + 1, &commandsArray.arrayPointer[startIndex], (numCommands - 2) * sizeof(struct parsedCommand));
153 |
154 | //The last one is a return
155 | commands[numCommands - 1].opcode = 1;
156 | commands[numCommands - 1].lineNum = 420;
157 | commands[numCommands - 1].translate = true;
158 |
159 |
160 | //Set the function-struct accordingly
161 | functions[functionArrayIndex].definedInFile = fileStruct->fileName;
162 | functions[functionArrayIndex].numberOfCommands = numCommands;
163 | functions[functionArrayIndex].commands = commands;
164 |
165 | //Increase the index
166 | functionArrayIndex++;
167 | }
168 |
169 | if(commandArrayIndex >= commandsArray.size) {
170 | break;
171 | }
172 |
173 | //Parse the function
174 | functions[functionArrayIndex] = parseFunction(commandsArray, fileStruct->fileName, commandArrayIndex, compileState);
175 | //Set the commands
176 | functions[functionArrayIndex].commands = &commandsArray.arrayPointer[commandArrayIndex];
177 | //Increase our command index so that it points to the next unparsed command
178 | commandArrayIndex += functions[functionArrayIndex].numberOfCommands;
179 | //Increase our function array index so that it points to the next uninitialised struct
180 | functionArrayIndex++;
181 | }
182 |
183 | //Update the file struct
184 | fileStruct->functionCount = functionDefinitions;
185 | fileStruct->functions = functions;
186 | }
187 |
--------------------------------------------------------------------------------
/compiler/memeasm.c:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the MemeAssembly compiler.
3 |
4 | Copyright © 2021-2023 Tobias Kamm and contributors
5 |
6 | MemeAssembly is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | MemeAssembly is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with MemeAssembly. If not, see .
18 | */
19 |
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 |
27 | #include "compiler.h"
28 | #include "parser/parser.h"
29 | #include "logger/log.h"
30 | extern const char* const versionString;
31 |
32 | /**
33 | * Prints the help page of this command. Launched by using the -h option in the terminal
34 | */
35 | void printHelpPage(char* programName) {
36 | printInformationHeader();
37 | printf("Usage:\n");
38 | printf(" %s [options] -o outputFile [-i | -d] inputFile\t\tCompiles the specified file into an executable\n", programName);
39 | printf(" %s [options] -S -o outputFile.S [-i | -d] inputFile\tOnly compiles the specified file and saves it as x86_64 Assembly code\n", programName);
40 | printf(" %s [options] -O -o outputFile.o [-i | -d] inputFile\tOnly compiles the specified file and saves it an object file\n", programName);
41 | printf(" %s (-h | --help)\t\t\t\t\tDisplays this help page\n", programName);
42 | printf(" %s -v\t\t\t\t\t\t\tPrints version information\n\n", programName);
43 | printf("Compiler options:\n");
44 | printf(" -O-1 \t\t- reverse optimisation stage 1: A nop is inserted after every command\n");
45 | printf(" -O-2 \t\t- reverse optimisation stage 2: A register is moved to and from the Stack after every command\n");
46 | printf(" -O-3 \t\t- reverse optimisation stage 3: A xmm-register is moved to and from the Stack using movups after every command\n");
47 | printf(" -O-s \t\t- reverse storage optimisation: Intentionally increases the file size by aligning end of the compiled Assembly-code to 536870912B\n");
48 | printf(" -O69420 \t- maximum optimisation. Reduces the execution to close to 0s by optimising out your entire code\n");
49 | printf(" -fcompile-mode - Change the compile mode to noob (default), bully, or obfuscated\n");
50 | printf(" -g \t\t- write debug info into the compiled file. Currently, only the STABS format is supported (Linux-only)\n");
51 | printf(" -fno-martyrdom - Disables martyrdom\n");
52 | printf(" -d \t\t- enables debug logs\n");
53 | }
54 |
55 | void printExplanationMessage(char* programName) {
56 | printf("Usage: %s -o outputFile inputFile\n", programName);
57 | }
58 |
59 | int main(int argc, char* argv[]) {
60 | struct compileState compileState = {
61 | .compileMode = noob,
62 | .optimisationLevel = none,
63 | .translateMode = intSISD,
64 | .outputMode = executable,
65 | .useStabs = false,
66 | .compilerErrors = 0,
67 | .logLevel = normal
68 | };
69 |
70 | char *outputFileString = NULL;
71 | FILE *inputFile;
72 |
73 | int optimisationLevel = 0;
74 | int martyrdom = true;
75 | const struct option long_options[] = {
76 | {"output", required_argument, 0, 'o'},
77 | {"help", no_argument, 0, 'h'},
78 | {"debug", no_argument, 0, 'd'},
79 | {"fno-martyrdom", no_argument,&martyrdom, false},
80 | {"fcompile-mode", required_argument,0, 'c'},
81 | { 0, 0, 0, 0 }
82 | };
83 |
84 | int opt;
85 | int option_index = 0;
86 |
87 | while ((opt = getopt_long_only(argc, argv, "o:hO::dgSv", long_options, &option_index)) != -1) {
88 | switch (opt) {
89 | case 'h':
90 | printHelpPage(argv[0]);
91 | return 0;
92 | case 'v':
93 | //Print the version number, but without the "v" at the beginning
94 | printf("%s\n", versionString+1);
95 | return 0;
96 | case 'S':
97 | compileState.outputMode = assemblyFile;
98 | break;
99 | case 'O':
100 | if(!optarg) {
101 | compileState.outputMode = objectFile;
102 | } else {
103 | if(strcmp(optarg, "-s") == 0) {
104 | compileState.optimisationLevel = o_s;
105 | } else {
106 | char *endptr;
107 | errno = 0;
108 | long res = strtol(optarg, &endptr, 10);
109 | if (errno) {
110 | perror("Invalid optimisation level specified");
111 | return 1;
112 | } else if (endptr == optarg || *endptr != '\0' ||
113 | (res != 69420 && res != -1 && res != -2 && res != -3)) {
114 | fprintf(stderr, "Invalid optimisation level specified: %s\n", optarg);
115 | return 1;
116 | }
117 |
118 | compileState.optimisationLevel = res;
119 | }
120 | }
121 | break;
122 | case 'd':
123 | compileState.logLevel = debug;
124 | break;
125 | case 'o':
126 | outputFileString = optarg;
127 | break;
128 | case 'g':
129 | #ifdef WINDOWS
130 | //If we use Windows, STABS does not work - output a warning, but don't do anything
131 | printNote("-g cannot be used on Windows-systems, this option will be ignored.", false, 0);
132 | #elif defined(MACOS)
133 | //If we use MacOS, STABS does not work - output a warning, but don't do anything
134 | printNote("-g cannot be used on MacOS-systems, this option will be ignored.", false, 0);
135 | #else
136 | compileState.useStabs = true;
137 | #endif
138 | break;
139 | case 'c': //-fcompile-mode
140 | if(strcmp(optarg, "bully") == 0) { //Bully mode
141 | compileState.compileMode = bully;
142 | } else if(strcmp(optarg, "obfuscated") == 0) { //obfuscated mode
143 | compileState.compileMode = obfuscated;
144 | } else if(strcmp(optarg, "noob") == 0) { //noob mode
145 | compileState.compileMode = noob;
146 | } else {
147 | fprintf(stderr, "Error: invalid compile mode (must be one of \"noob\", \"bully\", \"obfuscated\")\n");
148 | return 1;
149 | }
150 | break;
151 | case '?':
152 | fprintf(stderr, "Error: Unknown option provided\n");
153 | printExplanationMessage(argv[0]);
154 | return 1;
155 | }
156 | }
157 | compileState.martyrdom = martyrdom;
158 | if(compileState.useStabs && compileState.compileMode == bully) {
159 | printNote("-g cannot be used in bully mode, this option will be ignored.", false, 0);
160 | compileState.useStabs = false;
161 | }
162 |
163 | if(outputFileString == NULL) {
164 | fprintf(stderr, "Error: No output file specified\n");
165 | printExplanationMessage(argv[0]);
166 | return 1;
167 | } else if(argc < optind + 1) {
168 | fprintf(stderr, "Error: No input file(s) specified\n");
169 | printExplanationMessage(argv[0]);
170 | return 1;
171 | } else {
172 | //We have one or more input files, check how many there are
173 | //The first is at optind, the last at argc-1
174 | uint32_t fileCount = argc - optind;
175 |
176 | //Now allocate fileCount file structs on the heap
177 | struct file* fileStructs = calloc(fileCount, sizeof(struct file));
178 | CHECK_ALLOC(fileStructs);
179 |
180 | //Open each file one by one and parse it into a "struct file"
181 | for(int i = optind; i < argc; i++) {
182 | inputFile = fopen(argv[i], "r");
183 | //If the pointer is NULL, then the file failed to open. Print an error
184 | if (inputFile == NULL) {
185 | perror("Failed to open input file");
186 | printExplanationMessage(argv[0]);
187 | return 1;
188 | }
189 |
190 | //Create a stat struct to check if the file is a regular file. If we did not check for this, an input file like "/dev/urandom" would pass without errors
191 | struct stat inputFileStat;
192 | fstat(fileno(inputFile), &inputFileStat);
193 | if (!S_ISREG(inputFileStat.st_mode)) {
194 | fprintf(stderr,
195 | "Error while opening input file: Your provided file name does not point to a regular file (e.g. it could be a directory, character device or a socket)\n");
196 | fclose(inputFile);
197 | printExplanationMessage(argv[0]);
198 | return 1;
199 | }
200 |
201 | //Set the attribute "fileName" in the struct, because the parsing function uses this attribute for error printing
202 | fileStructs[i - optind].fileName = argv[i];
203 |
204 | //Parse file
205 | printDebugMessage(compileState.logLevel, "Opening file \"%s\" successful, parsing file...", 1, argv[i]);
206 | parseFile(&fileStructs[i - optind], inputFile, &compileState);
207 | printDebugMessage(compileState.logLevel, "File parsing done, closing file...", 0);
208 | fclose(inputFile);
209 | }
210 | compileState.fileCount = fileCount;
211 | compileState.files = fileStructs;
212 |
213 | //Convert our optmisationLevel to a value that our struct can work with to make it more readable later on
214 | //If optimisationLevel == 0, then leave the value at none (default)
215 | if(optimisationLevel == -1) {
216 | compileState.optimisationLevel = o_1;
217 | } else if (optimisationLevel == -2) {
218 | compileState.optimisationLevel = o_2;
219 | } else if (optimisationLevel == -3) {
220 | compileState.optimisationLevel = o_3;
221 | } else if (optimisationLevel == -4) {
222 | compileState.optimisationLevel = o_s;
223 | } else if (optimisationLevel == 69420) {
224 | compileState.optimisationLevel = o69420;
225 | }
226 |
227 | compile(compileState, outputFileString);
228 | }
229 | }
230 |
--------------------------------------------------------------------------------
/compiler/logger/log.c:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the MemeAssembly compiler.
3 |
4 | Copyright © 2021-2023 Tobias Kamm and contributors
5 |
6 | MemeAssembly is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | MemeAssembly is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with MemeAssembly. If not, see .
18 | */
19 |
20 | #include "log.h"
21 | #include
22 | #include
23 |
24 | const char* const versionString = "v1.6";
25 | const char* const platformSuffix =
26 | #ifdef WINDOWS
27 | "Windows";
28 | #elif defined(MACOS)
29 | "MacOS";
30 | #else
31 | "Linux";
32 | #endif
33 |
34 | const char* const randomErrorMessages[] = {
35 | //sudo
36 | "you are not in the sudoers file. This incident will be reported.",
37 | "you are not allowed to run sudo. This incident will be reported.",
38 | //erno - cause why not?
39 | "ENOSPC: No space left on device",
40 | "ENOENT: No such file or directory",
41 | //glibc
42 | "double free or corruption (top)",
43 | "corrupted top size",
44 | "double free or corruption (!prev)",
45 | "free: invalid pointer",
46 | //gcc
47 | "implicit declaration of function `gets'",
48 | "invalid type argument of `unary *'",
49 | "passing arg 2 of `strcpy' makes pointer from integer without a cast",
50 | "syntax error before '}' token",
51 | "ld returned exit 1 status",
52 | "no match for ‘operator==’ in ‘__first.__gnu_cxx::__normal_iterator::operator* [with _Iterator = std::vector*, _Container = std::vector >, __gnu_cxx::__normal_iterator::reference = std::vector&]() == __val’",
53 | "error: cannot bind rvalue ‘(short unsigned int)((const char*)\"\")’ to ‘short unsigned int&’",
54 | "no match for 'operator<<' (operand types are 'std::ostream' {aka 'std::basic_ostream'} and 'std::array')",
55 | "invalid conversion from `int' to `std::_Rb_tree_node >*'",
56 | //ld
57 | "relocation truncated to fit: R_X86_64_PC32 against symbol `main'",
58 | "(.ARM.exidx.text._ZNSt8_Rb_treeIiSt4pairIKiSt10shared_ptrIN4SWGL7ContextEEESt10_Select1stIS6_ESt4lessIiESaIS6_EE13_Rb_tree_implISA_Lb1EED2Ev[_ZNSt8_Rb_treeIiSt4pairIKiSt10shared_ptrIN4SWGL7ContextEEESt10_Select1stIS6_ESt4lessIiESaIS6_EE13_Rb_tree_implISA_Lb1EED5Ev]+0x0): relocation truncated to fit: R_ARM_PREL31 against `.text._ZNSt8_Rb_treeIiSt4pairIKiSt10shared_ptrIN4SWGL7ContextEEESt10_Select1stIS6_ESt4lessIiESaIS6_EE13_Rb_tree_implISA_Lb1EED2Ev'",
59 | "error adding symbols: DSO missing from command line",
60 | "undefined reference to `main'",
61 | //Cobol
62 | "programmer is impolite",
63 | "programmer is excessively polite",
64 | //actual MemeASM errors
65 | "a decimal number cannot be a pointer",
66 | "a function name cannot be a pointer",
67 | "invalid parameter combination: 64 Bit arithmetic operation commands require the decimal number to be sign-extendable from 32 Bits",
68 | "function does not return",
69 | "an executable cannot be created if no main function exists"
70 | };
71 |
72 | /**
73 | * Prints an ASCII-Art title and version information.
74 | */
75 | void printInformationHeader() {
76 | printf(BLU" __ __ _ _ \n");
77 | printf(" | \\/ | /\\ | | | | \n");
78 | printf(" | \\ / | ___ _ __ ___ ___ / \\ ___ ___ ___ _ __ ___ | |__ | |_ _ \n");
79 | printf(" | |\\/| |/ _ \\ '_ ` _ \\ / _ \\ / /\\ \\ / __/ __|/ _ \\ '_ ` _ \\| '_ \\| | | | |\n");
80 | printf(" | | | | __/ | | | | | __// ____ \\\\__ \\__ \\ __/ | | | | | |_) | | |_| |\n");
81 | printf(" |_| |_|\\___|_| |_| |_|\\___/_/ \\_\\___/___/\\___|_| |_| |_|_.__/|_|\\__, |\n");
82 | printf(RESET" A Meme-based programming language. " BLU " __/ |\n");
83 | printf(" |___/ \n\n"RESET);
84 | printf("For more information, a list of commands and code examples, please visit https://github.com/kammt/MemeAssembly.\n");
85 | printf("This is the MemeAssembly compiler %s (%s), created by Tobias Kamm.\n\n", versionString, platformSuffix);
86 | }
87 |
88 | /**
89 | * Called if there is an error in the specified file. It prints a "Wait, that's illegal!" ASCII-Art and exits the program
90 | */
91 | void printErrorASCII() {
92 | printf("\n");
93 | printf("\n");
94 | printf(YEL " __ __ _ _ _ _ _ _ _ _ _ _ _ \n");
95 | printf(" \\ \\ / / (_| | | | | | | | ( ) (_| | | | | | \n");
96 | printf(" \\ \\ /\\ / __ _ _| |_ | |_| |__ __ _| |_|/ ___ _| | | ___ __ _ __ _| | | \n");
97 | printf(" \\ \\/ \\/ / _` | | __| | __| '_ \\ / _` | __| / __| | | | |/ _ \\/ _` |/ _` | | | \n");
98 | printf(" \\ /\\ | (_| | | |_ _ | |_| | | | (_| | |_ \\__ \\ | | | | __| (_| | (_| | |_| \n");
99 | printf(" \\/ \\/ \\__,_|_|\\__( ) \\__|_| |_|\\__,_|\\__| |___/ |_|_|_|\\___|\\__, |\\__,_|_(_) \n");
100 | printf(" |/ __/ | \n");
101 | printf(" |___/ \n" RESET);
102 | }
103 |
104 | /**
105 | * Called when the command 'perfectly balanced as all things should be' is used. It prints a Snap ASCII art
106 | * @param deletedLines the number of lines that got deleted
107 | */
108 | void printThanosASCII(size_t deletedLines) {
109 | printf("\n");
110 | printf("\n");
111 | printf(YEL " _____ \n");
112 | printf(" / ____| \n");
113 | printf(" | (___ _ __ __ _ _ __ \n");
114 | printf(" \\___ \\| '_ \\ / _` | '_ \\ \n");
115 | printf(" ____) | | | | (_| | |_) | \n");
116 | printf(" |_____/|_| |_|\\__,_| .__/ \n");
117 | printf(" | | \n");
118 | printf(" |_| \n" RESET);
119 | printf(GRN "\nDid you do it?\n" RESET);
120 | printf(MAG "Yes\n" RESET);
121 | printf(GRN "What did it cost?\n" RESET);
122 | printf(MAG "%lu lines of code\n\n" RESET, deletedLines);
123 | }
124 |
125 | /**
126 | * Called when a decimal parameter with value 420 or 69 is encountered. It prints a "Nice" ASCII art
127 | */
128 | void printNiceASCII() {
129 | printf("\n");
130 | printf("\n");
131 | printf("\x1B[38;5;197m" " _ _ _ \n");
132 | printf("\x1B[38;5;197m" " | \\ | (_) \n");
133 | printf("\x1B[38;5;198m" " | \\| |_ ___ ___ \n");
134 | printf("\x1B[38;5;198m" " | . ` | |/ __/ _ \\\n");
135 | printf("\x1B[38;5;199m" " | |\\ | | (_| __/\n");
136 | printf("\x1B[38;5;199m" " |_| \\_|_|\\___\\___|\n\n" RESET);
137 | }
138 |
139 | /**
140 | * Prints a debug message. It can be called with a variable number of arguments that will be inserted in the respective places in the format string
141 | */
142 | void printDebugMessage(logLevel logLevel, char* message, unsigned varArgNum, ...) {
143 | if(logLevel == debug) {
144 | va_list vaList;
145 | va_start(vaList, varArgNum);
146 |
147 | vprintf(message, vaList);
148 | printf("\n");
149 | }
150 | }
151 |
152 | /**
153 | * Prints an error message. It can be called with a variable number of arguments that will be inserted in the respective places in the format string
154 | * @param inputFileName name of the input file
155 | * @param lineNum the line number in which the error occurred
156 | * @param compileState the current compileState. Needed to increase the error count
157 | * @param message the message (with printf-like formatting)
158 | * @param varArgNum How many variable arguments were passed (important!)
159 | * @param ... variable arguments
160 | */
161 | void printError(char* inputFileName, unsigned lineNum, struct compileState* compileState, char* message, unsigned varArgNum, ...) {
162 | compileState->compilerErrors++;
163 |
164 | //First, only print the file name and line
165 | printf("%s:%u: " RED "error: " RESET, inputFileName, lineNum);
166 |
167 | if(compileState->compileMode != obfuscated) {
168 | //Initialise va_list to pass it on to vprintf
169 | va_list vaList;
170 | va_start(vaList, varArgNum);
171 | //Now print the custom message with variable args
172 | vprintf(message, vaList);
173 | printf("\n");
174 | } else {
175 | //Obfuscated mode: print a random error message instead
176 | uint64_t computedIndex = lineNum;
177 | for(size_t i = 0; i < strlen(inputFileName); i++) {
178 | computedIndex += inputFileName[i];
179 | }
180 | for(size_t i = 0; i < strlen(message); i++) {
181 | computedIndex += message[i];
182 | }
183 | computedIndex += varArgNum;
184 |
185 | printf("%s\n", randomErrorMessages[computedIndex % (sizeof(randomErrorMessages) / sizeof(char*))]);
186 | }
187 | }
188 |
189 | /**
190 | * Prints a note. It can be called with a variable number of arguments that will be inserted in the respective places in the format string
191 | * @param message the message (with printf-like formatting)
192 | * @param indent whether the entire message should be indented
193 | * @param varArgNum How many variable arguments were passed (important!)
194 | * @param ... variable arguments
195 | */
196 | void printNote(char* message, bool indent, unsigned varArgNum, ...) {
197 | //Initialise va_list to pass it on to vprintf
198 | va_list vaList;
199 | va_start(vaList, varArgNum);
200 |
201 | //First, only print the file name and line
202 | if(indent) printf("\t");
203 | printf(MAG "note: " RESET);
204 | //Now print the custom message with variable args
205 | vprintf(message, vaList);
206 | printf("\n");
207 | }
208 |
209 | /**
210 | * Prints an internal compiler error, after which the compiler terminates
211 | * @param message the message (with printf-like formatting)
212 | * @param report whether to print a message telling the user to report this error
213 | * @param varArgNum How many variable arguments were passed (important!)
214 | * @param ... variable arguments
215 | */
216 | void printInternalCompilerError(char* message, bool report, unsigned varArgNum, ...) {
217 | //Initialise va_list to pass it on to vprintf
218 | va_list vaList;
219 | va_start(vaList, varArgNum);
220 |
221 | //First, only print the file name and line
222 | fprintf(stderr, RED "Internal compiler error: " RESET);
223 | //Now print the custom message with variable args
224 | vfprintf(stderr, message, vaList);
225 | fprintf(stderr, "\n");
226 | if(report) fprintf(stderr, "Please report this error at https://github.com/kammt/MemeAssembly/issues/new");
227 | }
228 |
--------------------------------------------------------------------------------
/images/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
22 |
23 |
295 |
--------------------------------------------------------------------------------
/images/logo_square.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
22 |
23 |
306 |
--------------------------------------------------------------------------------
/compiler/parser/fileParser.c:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the MemeAssembly compiler.
3 |
4 | Copyright © 2021-2023 Tobias Kamm
5 |
6 | MemeAssembly is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | MemeAssembly is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with MemeAssembly. If not, see .
18 | */
19 |
20 | #include "fileParser.h"
21 | #include "parser.h"
22 | #include
23 | #include
24 |
25 | #include "../logger/log.h"
26 |
27 | #ifdef WINDOWS
28 | /* strtok_r does not exist on Windows and instead is strtok_s. Use a preprocessor directive to replace all occurrences */
29 | # define strtok_r strtok_s
30 | #endif
31 |
32 | extern struct command commandList[];
33 |
34 | //Used to pseudo-random generation when using bully mode
35 | uint64_t computedIndex = 69;
36 |
37 | /**
38 | * Removes the \n from a string if it is present at the end of the string
39 | */
40 | void removeLineBreaksAndTabs(char* line) {
41 | size_t i = strlen(line) - 1;
42 | while (line[i] == '\t' || line[i] == '\n' || line[i] == ' ') {
43 | i--;
44 | }
45 | line[i + 1] = '\0';
46 | }
47 |
48 | /**
49 | * Checks whether this line should be skipped or not
50 | * @return 1 if it is of interest (=> code), 0 if it should be skipped (e.g. it is a comment or it's empty)
51 | */
52 | int isLineOfInterest(const char* line, ssize_t lineLength) {
53 | //To support tabbed comments, we need to determine when the text actually starts
54 | int i = 0;
55 | while (line[i] == '\t' || line[i] == ' ') {
56 | i++; //Increase our variable as long as there are only tabs or spaces
57 | }
58 |
59 | if(line[i] != '\n' && lineLength != i && strncmp((line + i), commentStart, strlen(commentStart)) != 0) {
60 | return 1;
61 | }
62 | return 0;
63 | }
64 |
65 | /**
66 | * A basic implementation of a getline-function.
67 | * Reads a full line and stores it in lineptr. If lineptr is NULL, it will be initialised and n will be set accordingly. When too little is allocated, 128 more Bytes will be added
68 | * @param lineptr a pointer to the current storage for lines. May be NULL
69 | * @param n must be the size of lineptr and will be updated by this function
70 | * @param stream from where to read
71 | * @return the number of bytes read if successful, -1 on error (e.g. EOF found, malloc/realloc failed)
72 | */
73 | ssize_t getLine(char **restrict lineptr, size_t *restrict n, FILE *restrict stream) {
74 | if(*lineptr == NULL) {
75 | if(!(*lineptr = malloc(128))) {
76 | return -1;
77 | }
78 | *n = 128;
79 | }
80 |
81 | char* result = *lineptr;
82 | char c = 'c';
83 | ssize_t bytesRead = 0;
84 | while(c != '\n') {
85 | size_t readRes = fread(&c, 1, 1, stream);
86 | if(readRes == 0) {
87 | if(bytesRead == 0) {
88 | return -1;
89 | }
90 | //If EOF was found somewhere while reading from file, still return this string
91 | break;
92 | }
93 |
94 | *result = c;
95 | bytesRead++;
96 | result++;
97 | if(bytesRead == (ssize_t) *n) {
98 | *n += 128;
99 | *lineptr = realloc(*lineptr, *n);
100 | result = *lineptr + bytesRead;
101 |
102 | if(!*lineptr) {
103 | return -1;
104 | }
105 | }
106 | }
107 |
108 | //On Windows, file endings are done using \r\n. This means that there will be a \r at the end of every string, breaking the entire compiler
109 | //To fix this, check if the string ends with \r\n. If so, replace it with \n
110 | //However, we first need to check that we are not reading out of bounds
111 | if(((uintptr_t) result - 2 >= (uintptr_t) *lineptr) && *(result - 2) == '\r') {
112 | *(result - 2) = '\n';
113 | result--;
114 | }
115 | //We got to the end of a line or the end of a file, now append a '\0'
116 | *result = '\0';
117 | return bytesRead;
118 | }
119 |
120 | /**
121 | * Counts the lines of code in a memeasm file. A line counts as a line of code if:
122 | * - it does not start with "What the hell happened here?" (a comment)
123 | * - it is not empty
124 | * @param inputFile the input file
125 | * @return the number of lines of code in the file
126 | */
127 | size_t getLinesOfCode(FILE *inputFile) {
128 | size_t loc = 0;
129 | char* line = NULL;
130 | size_t len;
131 | ssize_t lineLength;
132 |
133 | while((lineLength = getLine(&line, &len, inputFile)) != -1) {
134 | if(isLineOfInterest(line, lineLength) == 1) {
135 | loc++;
136 | }
137 | }
138 | CHECK_ALLOC(line);
139 |
140 | rewind(inputFile);
141 | free(line);
142 | return loc;
143 | }
144 |
145 | /**
146 | * Frees the memory of variables after they are not needed anymore
147 | * @param parsedCommand the parsedCommand struct
148 | * @param numberOfParameters how many variables are currently in use (allocated)
149 | */
150 | void freeAllocatedMemory(struct parsedCommand parsedCommand, int numberOfParameters) {
151 | for(int i = 0; i < numberOfParameters; i++) {
152 | free(parsedCommand.parameters[i]);
153 | }
154 | }
155 |
156 | /**
157 | * Parses a provided line of code and attempts to match it to a command
158 | * @param inputFileName the origin file. Required for error printing
159 | * @param line the line as a string
160 | * @param lineNum the line number in the origin file. Required for error printing
161 | * @param compileState the current compile state
162 | * @return
163 | */
164 | struct parsedCommand parseLine(char* inputFileName, size_t lineNum, char* line, struct compileState* compileState) {
165 | struct parsedCommand parsedCommand;
166 | parsedCommand.lineNum = lineNum; //Set the line number
167 | parsedCommand.translate = 1;
168 |
169 | //Temporarily save the line on the stack to be able to restore when a comparison failed
170 | char lineCpy[strlen(line) + 1];
171 | strcpy(lineCpy, line);
172 |
173 | //Define save pointers for strtok_r
174 | char *savePtrLine;
175 | char *savePtrPattern;
176 |
177 | //Iterate through all possible commands
178 | for(int i = 0; i < NUMBER_OF_COMMANDS - 2; i++) {
179 | strcpy(lineCpy, line);
180 | savePtrLine = NULL;
181 | savePtrPattern = NULL;
182 |
183 | //Copy the current command pattern out of read-only memory
184 | char commandString[strlen(commandList[i].pattern) + 1];
185 | strcpy(commandString, commandList[i].pattern);
186 |
187 | //Tokenize both strings. Tabs at the beginning are allowed and should be ignored, hence they are a delimiter
188 | char *commandToken = strtok_r(commandString, " \t", &savePtrPattern);
189 | char *lineToken = strtok_r(lineCpy, " \t", &savePtrLine);
190 |
191 | int numberOfParameters = 0;
192 | parsedCommand.isPointer = 0;
193 |
194 | //Enter the comparison loop
195 | while (commandToken != NULL && lineToken != NULL) {
196 | printDebugMessage(compileState->logLevel, "\tcomparing with %s", 1, commandToken);
197 |
198 | if(strstr(commandToken, "{p}") != NULL) {
199 | //First check that everything before and after the {p} matches
200 |
201 | //The difference between the starting address of commandToken and the starting address of {p} is the number of characters before {p}
202 | size_t charsBefore = ((size_t) strstr(commandToken, "{p}") - (size_t) commandToken);
203 | //The difference between the total string length of commandToken and (charsBefore + 3)
204 | size_t charsAfter = (strlen(commandToken) - charsBefore - 3);
205 |
206 | if(strncmp(commandToken, lineToken, charsBefore) == 0 &&
207 | strncmp(commandToken + charsBefore + 3, lineToken + strlen(lineToken) - charsAfter, charsAfter) == 0) {
208 | printDebugMessage(compileState->logLevel, "\t\t%s contains a parameter", 1, lineToken);
209 |
210 | size_t parameterLength = strlen(lineToken) - charsBefore - charsAfter;
211 |
212 | //When allocating space for a function name on MacOS, we need an extra _ -prefix, hence +2
213 | char *variable = malloc(parameterLength + 2);
214 | CHECK_ALLOC(variable);
215 |
216 | #ifdef MACOS
217 | if (i == 0 || i == 4) {
218 | strcpy(variable, "_");
219 | strncat(variable, lineToken, parameterLength);
220 | variable[parameterLength + 1] = '\0';
221 | } else {
222 | #endif
223 | //On Windows and Linux, only this line is executed
224 | strncpy(variable, lineToken, parameterLength);
225 | variable[parameterLength] = '\0';
226 | #ifdef MACOS
227 | }
228 | #endif
229 |
230 | parsedCommand.parameters[numberOfParameters++] = variable;
231 |
232 | //If the line after this parameter contains "do you know de wey", mark it as a pointer
233 | if (savePtrLine != NULL && strlen(savePtrLine) >= strlen(pointerSuffix) &&
234 | strncmp(pointerSuffix, savePtrLine, strlen(pointerSuffix)) == 0) {
235 | printDebugMessage(compileState->logLevel,
236 | "\t\t\t'do you know de wey' was found, interpreting as pointer", 0);
237 | //If another parameter is already marked as a variable, print an error
238 | //This error is skipped when bully mode is on
239 | if (parsedCommand.isPointer != 0 && compileState->compileMode != bully) {
240 | printError(inputFileName, lineNum, compileState,
241 | "Only one parameter is allowed to be a pointer", 0);
242 | }
243 | parsedCommand.isPointer = (uint8_t) numberOfParameters;
244 | //Move the save pointer so that "do you know de wey" is not tokenized by strtok_r
245 | savePtrLine += strlen(pointerSuffix);
246 | }
247 | } else {
248 | //Characters before and after parameter do not match
249 | printDebugMessage( compileState->logLevel, "\t\tMatching failed - chars before or after {p} mismatching, attempting to match next command", 0);
250 | freeAllocatedMemory(parsedCommand, numberOfParameters);
251 | break;
252 | }
253 | } else if(strcmp(commandToken, lineToken) != 0) {
254 | //If both tokens do not match, try the next command
255 | printDebugMessage( compileState->logLevel, "\t\tMatching failed, attempting to match next command", 0);
256 | freeAllocatedMemory(parsedCommand, numberOfParameters);
257 | break;
258 | }
259 |
260 | //Tokenize both strings again. This time, only spaces are allowed
261 | commandToken = strtok_r(NULL, " ", &savePtrPattern);
262 | lineToken = strtok_r(NULL, " ", &savePtrLine);
263 | }
264 |
265 | if(commandToken != NULL && lineToken != NULL) {
266 | continue;
267 | }
268 |
269 | /*Either the line or the command pattern have reached their end. We now have to check what caused the problem
270 | * - if both are NULL, then there is no problem!
271 | * - if the commandToken is NULL, then we should have been at the end of the line. Check if the rest is equal to 'or draw 25'. If not, try the next command
272 | * - if the token is NULL, then the line is too short, try the next command
273 | */
274 | if(commandToken == NULL && lineToken == NULL) {
275 | parsedCommand.opcode = (uint8_t) i;
276 | return parsedCommand;
277 | } else if(lineToken == NULL) {
278 | printDebugMessage(compileState->logLevel, "\t\tMatching failed, lineToken is NULL while commandToken is not. Attempting to match next command", 0);
279 | freeAllocatedMemory(parsedCommand, numberOfParameters);
280 | continue;
281 | //If the current token is 'or' and the rest of the string is only 'draw 25', then set the opcode as "or draw 25" and return
282 | } else if(strcmp(lineToken, orDraw25Start) == 0 && strlen(savePtrLine) == strlen(orDraw25End) && strncmp(orDraw25End, savePtrLine, strlen(orDraw25End)) == 0) {
283 | printDebugMessage(compileState->logLevel, "\t\t'or draw 25' was found, replacing opcode", 0);
284 | //Before we replace the opcode though, we need to free memory that was allocated for parameters
285 | for(int j = 0; j < commandList[i].usedParameters; j++) {
286 | free(parsedCommand.parameters[j]);
287 | }
288 | //Now we can change the opcode and return the struct
289 | parsedCommand.opcode = OR_DRAW_25_OPCODE;
290 | return parsedCommand;
291 | }
292 | }
293 |
294 | if(compileState->compileMode == bully) {
295 | /*
296 | * In bully mode, we replace this non-working command with a valid one
297 | * But we want to make it deterministic, with a lot of possible commands,
298 | * so we take the sum of ascii characters in this line, and use this value
299 | * to create the random command
300 | *
301 | * The variable "computedIndex" is global, meaning that the value
302 | * is dependent on the previous illegal commands - *perfection*
303 | */
304 | const char* randomParams[] = {"rax", "rcx", "rbx", "r8", "r9", "r10", "r12", "rsp", "rbp", "ax", "al", "r8b", "r9d", "r14b", "99", "1238", "12", "420", "987654321", "8", "9", "69", "8268", "2", "_", "a", "b", "d", "f", "F", "sigreturn", "uaauuaa", "uau", "uu", "main", "gets", "srand", "mprotect", "au", "uwu", "space"};
305 | unsigned randomParamCount = sizeof randomParams / sizeof(char*);
306 |
307 | for(size_t i = 0; i < strlen(line); i++) {
308 | computedIndex += line[i];
309 | }
310 | computedIndex = ((computedIndex * lineNum) % 420) * inputFileName[0];
311 |
312 | parsedCommand.opcode = computedIndex % (NUMBER_OF_COMMANDS - 1);
313 | if(commandList[parsedCommand.opcode].usedParameters > 0) {
314 | parsedCommand.parameters[0] = strdup(randomParams[computedIndex % randomParamCount]);
315 | CHECK_ALLOC(parsedCommand.parameters[0]);
316 | }
317 | if (commandList[parsedCommand.opcode].usedParameters > 1) {
318 | parsedCommand.parameters[1] = strdup(randomParams[(computedIndex * inputFileName[0]) % randomParamCount]);
319 | CHECK_ALLOC(parsedCommand.parameters[1]);
320 | }
321 | } else {
322 | parsedCommand.opcode = INVALID_COMMAND_OPCODE;
323 | printError(inputFileName, lineNum, compileState, "Invalid command: \"%s\"", 1, line);
324 | //Any error will increase the "compilationErrors" variable in log.c, meaning that we can safely return something that doesn't make sense
325 | //We don't exit immediately because we want to print every error possible
326 | }
327 | return parsedCommand;
328 | }
329 |
330 |
331 | /**
332 | * Parses an input file line by line and fills a provided struct commandsArray
333 | */
334 | void parseCommands(FILE *inputFile, char* inputFileName, struct compileState* compileState, struct commandsArray* commandsArray) {
335 | //Variable declarations
336 | char* line = NULL;
337 | size_t len = 0;
338 | ssize_t lineLength;
339 |
340 | //First, we create an array of command structs
341 | size_t loc = getLinesOfCode(inputFile);
342 | printDebugMessage(compileState->logLevel, "The number of lines are %lu", 1, loc);
343 |
344 | if(loc == 0) {
345 | if(compileState->compileMode != bully) {
346 | printError(inputFileName, 0, compileState, "file does not contain any commands", 0);
347 | }
348 |
349 | commandsArray->arrayPointer = NULL;
350 | commandsArray->size = 0;
351 | return;
352 | }
353 |
354 | struct parsedCommand *commands = calloc(sizeof(struct parsedCommand), loc);
355 | CHECK_ALLOC(commands);
356 | printDebugMessage( compileState->logLevel, "Struct array was created successfully", 0);
357 |
358 | //Iterate through the file again, this time parsing each line of interest and adding it to our command struct array
359 | int i = 0; //The number of structs in the array
360 | int lineNumber = 1; //The line number we are currently on. We differentiate between number of commands and number of lines to print the correct line number in case of an error
361 |
362 | //Parse the file line by line
363 | while((lineLength = getLine(&line, &len, inputFile)) != -1) {
364 | //Check if the line contains actual code or if it's empty/contains comments
365 | if(isLineOfInterest(line, lineLength) == 1) {
366 | //Remove \n from the end of the line
367 | removeLineBreaksAndTabs(line);
368 | printDebugMessage( compileState->logLevel, "Parsing line: %s", 1, line);
369 | //Parse the command and add the returned struct into the array
370 | *(commands + i) = parseLine(inputFileName, lineNumber, line, compileState);
371 | //Increase our number of structs in the array
372 | i++;
373 | }
374 | lineNumber++;
375 | }
376 |
377 | commandsArray->size = loc;
378 | commandsArray->arrayPointer = commands;
379 |
380 | free(line);
381 | }
382 |
383 |
--------------------------------------------------------------------------------
/compiler/compiler.c:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the MemeAssembly compiler.
3 |
4 | Copyright © 2021-2023 Tobias Kamm and contributors
5 |
6 | MemeAssembly is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | MemeAssembly is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with MemeAssembly. If not, see .
18 | */
19 | #include "compiler.h"
20 |
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 |
27 | #include "parser/parser.h"
28 | #include "analyser/analyser.h"
29 | #include "translator/translator.h"
30 | #include "logger/log.h"
31 |
32 | const struct command commandList[NUMBER_OF_COMMANDS] = {
33 | ///Functions
34 | {
35 | .pattern = "I like to have fun, fun, fun, fun, fun, fun, fun, fun, fun, fun {p}",
36 | .commandType = COMMAND_TYPE_FUNC_DEF,
37 | .usedParameters = 1,
38 | .allowedParamTypes = {PARAM_FUNC_NAME},
39 | .analysisFunction = &analyseFunctions,
40 | .translationPattern = "{0}:"
41 | },
42 | {
43 | .pattern = "right back at ya, buckaroo",
44 | .commandType = COMMAND_TYPE_FUNC_RETURN,
45 | .usedParameters = 0,
46 | .analysisFunction = NULL,
47 | .translationPattern = "ret"
48 | },
49 | {
50 | .pattern = "no, I don't think I will",
51 | .commandType = COMMAND_TYPE_FUNC_RETURN,
52 | .usedParameters = 0,
53 | .analysisFunction = NULL,
54 | .translationPattern = "mov rax, 1\n\tret"
55 | },
56 | {
57 | .pattern = "I see this as an absolute win",
58 | .commandType = COMMAND_TYPE_FUNC_RETURN,
59 | .usedParameters = 0,
60 | .analysisFunction = NULL,
61 | .translationPattern = "xor rax, rax\n\tret"
62 | },
63 | {
64 | .pattern = "{p}: whomst has summoned the almighty one",
65 | .commandType = COMMAND_TYPE_FUNC_CALL,
66 | .usedParameters = 1,
67 | .allowedParamTypes = {PARAM_FUNC_NAME},
68 | .analysisFunction = &analyseCall,
69 | .translationPattern = "call {0}"
70 | },
71 |
72 | ///Stack operations
73 | {
74 | .pattern = "stonks {p}",
75 | .usedParameters = 1,
76 | .allowedParamTypes = {PARAM_REG64 | PARAM_DECIMAL | PARAM_CHAR},
77 | .analysisFunction = NULL,
78 | .translationPattern = "push {0}"
79 | },
80 | {
81 | .pattern = "not stonks {p}",
82 | .usedParameters = 1,
83 | .allowedParamTypes = {PARAM_REG64},
84 | .analysisFunction = NULL,
85 | .translationPattern = "pop {0}"
86 | },
87 |
88 | ///Logical Operations
89 | {
90 | .pattern = "bitconneeeeeeect {p} {p}",
91 | .usedParameters = 2,
92 | .analysisFunction = NULL,
93 | .allowedParamTypes = {PARAM_REG, PARAM_REG | PARAM_DECIMAL | PARAM_CHAR},
94 | .translationPattern = "and {0}, {1}"
95 | },
96 | {
97 | .pattern = "{p} \\s",
98 | .usedParameters = 1,
99 | .analysisFunction = NULL,
100 | .allowedParamTypes = {PARAM_REG},
101 | .translationPattern = "not {0}"
102 | },
103 |
104 | ///Register Manipulation
105 | {
106 | .pattern = "sneak 100 {p}",
107 | .usedParameters = 1,
108 | .allowedParamTypes = {PARAM_REG},
109 | .analysisFunction = NULL,
110 | .translationPattern = "xor {0}, {0}"
111 | },
112 | {
113 | .pattern = "{p} is brilliant, but I like {p}",
114 | .commandType = COMMAND_TYPE_MOV,
115 | .usedParameters = 2,
116 | .allowedParamTypes = {PARAM_REG, PARAM_REG | PARAM_DECIMAL | PARAM_CHAR},
117 | .analysisFunction = NULL,
118 | .translationPattern = "mov {0}, {1}"
119 | },
120 |
121 | ///Arithmetic operations
122 | {
123 | .pattern = "upvote {p}",
124 | .usedParameters = 1,
125 | .allowedParamTypes = {PARAM_REG},
126 | .analysisFunction = NULL,
127 | .translationPattern = "add {0}, 1"
128 | },
129 | {
130 | .pattern = "downvote {p}",
131 | .usedParameters = 1,
132 | .allowedParamTypes = {PARAM_REG},
133 | .analysisFunction = NULL,
134 | .translationPattern = "sub {0}, 1"
135 | },
136 | {
137 | .pattern = "parry {p} you filthy casual {p}",
138 | .usedParameters = 2,
139 | .allowedParamTypes = {PARAM_REG | PARAM_DECIMAL | PARAM_CHAR, PARAM_REG},
140 | .analysisFunction = NULL,
141 | .translationPattern = "sub {1}, {0}"
142 | },
143 | {
144 | .pattern = "{p} units are ready, with {p} more well on the way",
145 | .usedParameters = 2,
146 | .allowedParamTypes = {PARAM_REG, PARAM_REG | PARAM_DECIMAL | PARAM_CHAR},
147 | .analysisFunction = NULL,
148 | .translationPattern = "add {0}, {1}"
149 | },
150 | {
151 | .pattern = "upgrades, people. Upgrades {p}",
152 | .usedParameters = 1,
153 | .allowedParamTypes = {PARAM_REG},
154 | .analysisFunction = NULL,
155 | .translationPattern = "shl {0}, 1"
156 | },
157 | {
158 | .pattern = "they had us in the first half, not gonna lie {p}",
159 | .usedParameters = 1,
160 | .allowedParamTypes = {PARAM_REG},
161 | .analysisFunction = NULL,
162 | .translationPattern = "shr {0}, 1"
163 | },
164 | {
165 | .pattern = "{p} is getting out of hand, now there are {p} of them",
166 | .usedParameters = 2,
167 | .allowedParamTypes = {PARAM_REG64 | PARAM_REG32, PARAM_REG64 | PARAM_REG32 | PARAM_DECIMAL | PARAM_CHAR},
168 | .analysisFunction = NULL,
169 | .translationPattern = "imul {0}, {1}"
170 | },
171 | {
172 | .pattern = "look at what {p} needs to mimic a fraction of {p}",
173 | .usedParameters = 2,
174 | .allowedParamTypes = {PARAM_REG64 | PARAM_DECIMAL | PARAM_CHAR, PARAM_REG64},
175 | .analysisFunction = NULL,
176 | .translationPattern = "mov QWORD PTR [rip + .Ltmp64], {0}\n\t"
177 | "push rdx\n\t"
178 | "cqo\n\t"
179 | "push rax\n\t"
180 | "mov rax, {1}\n\t"
181 | "idiv QWORD PTR [rip + .Ltmp64]\n\t"
182 | "push rax\n\t"
183 | "mov rax, [rsp + 8]\n\t"
184 | "pop {1}\n\t"
185 | "add rsp, 8\n\t"
186 | "pop rdx\n\t"
187 | },
188 | {
189 | .pattern = "{p} UNLIMITED POWER {p}",
190 | .usedParameters = 2,
191 | .allowedParamTypes = {PARAM_REG64, PARAM_REG64 | PARAM_DECIMAL | PARAM_CHAR},
192 | .analysisFunction = NULL,
193 | .translationPattern = "mov QWORD PTR [rip + .Ltmp64], {1}\n\t"
194 | "cmp QWORD PTR [rip + .Ltmp64], 0\n\t"
195 | "jne 2f\n\t" //Jump forward to 2 if not zero
196 | //y is zero, load 1 and jump to the end (numeric label 4)
197 | "xor {0}, {0}\n\t"
198 | "inc {0}\n\t"
199 | "jmp 4f\n\t"
200 | //Now loop until our y is zero
201 | "2: push {0}\n\t" //Preparation: push x to the stack to remember it for later
202 | "dec QWORD PTR [rip + .Ltmp64]\n\t"
203 | "3: imul {0}, [rsp]\n\t"
204 | "dec QWORD PTR [rip + .Ltmp64]\n\t"
205 | "jnz 3b\n\t" //If the result was not zero (ZF set from subtraction), jump back
206 | "add rsp, 8\n\t"
207 | "4:\n\t"
208 | },
209 |
210 |
211 | ///Jumps and Jump Markers
212 | {
213 | .pattern = "upgrade",
214 | .usedParameters = 0,
215 | .analysisFunction = &analyseJumpMarkers,
216 | .translationPattern = ".LUpgradeMarker_{F}:"
217 | },
218 | {
219 | .pattern = "fuck go back",
220 | .usedParameters = 0,
221 | .analysisFunction = NULL,
222 | .translationPattern = "jmp .LUpgradeMarker_{F}"
223 | },
224 | {
225 | .pattern = "banana",
226 | .usedParameters = 0,
227 | .analysisFunction = &analyseJumpMarkers,
228 | .translationPattern = ".LBananaMarker_{F}:"
229 | },
230 | {
231 | .pattern = "where banana",
232 | .usedParameters = 0,
233 | .analysisFunction = NULL,
234 | .translationPattern = "jmp .LBananaMarker_{F}"
235 | },
236 | {
237 | .pattern = "monke {p}",
238 | .usedParameters = 1,
239 | .allowedParamTypes = {PARAM_MONKE_LABEL},
240 | .analysisFunction = &analyseMonkeMarkers,
241 | .translationPattern = ".L{0}:"
242 | },
243 | {
244 | .pattern = "return to monke {p}",
245 | .usedParameters = 1,
246 | .allowedParamTypes = {PARAM_MONKE_LABEL},
247 | .analysisFunction = NULL,
248 | .translationPattern = "jmp .L{0}"
249 | },
250 | {
251 | .pattern = "who would win? {p} or {p}",
252 | .usedParameters = 2,
253 | .allowedParamTypes = {PARAM_REG, PARAM_REG | PARAM_DECIMAL | PARAM_CHAR},
254 | .analysisFunction = &analyseWhoWouldWinCommands,
255 | .translationPattern = "cmp {0}, {1}\n\tjg .L{0}Wins_{F}\n\tjl .L{1}Wins_{F}"
256 | },
257 | {
258 | .pattern = "{p} wins",
259 | .usedParameters = 1,
260 | .allowedParamTypes = {PARAM_REG | PARAM_DECIMAL | PARAM_CHAR},
261 | .analysisFunction = NULL,
262 | .translationPattern = ".L{0}Wins_{F}:"
263 | },
264 | {
265 | .pattern = "corporate needs you to find the difference between {p} and {p}",
266 | .usedParameters = 2,
267 | .allowedParamTypes = {PARAM_REG, PARAM_REG | PARAM_DECIMAL | PARAM_CHAR},
268 | .analysisFunction = &analyseTheyreTheSamePictureCommands,
269 | .translationPattern = "cmp {0}, {1}\n\tje .LSamePicture_{F}"
270 | },
271 | {
272 | .pattern = "they're the same picture",
273 | .usedParameters = 0,
274 | .analysisFunction = NULL,
275 | .translationPattern = ".LSamePicture_{F}:"
276 | },
277 |
278 | ///IO-Operations
279 | {
280 | .pattern = "what can I say except {p}",
281 | .usedParameters = 1,
282 | .analysisFunction = NULL,
283 | .allowedParamTypes = {PARAM_REG8 | PARAM_CHAR},
284 | .translationPattern = "mov BYTE PTR [rip + .LCharacter], {0}\n\t"
285 | "test rsp, 0xF\n\t"
286 | "jz 1f\n\t"
287 | "sub rsp, 8\n\t"
288 | "call writechar\n\t"
289 | "add rsp, 8\n\t"
290 | "jmp 2f\n\t"
291 | "1: call writechar\n\t"
292 | "2:\n\t"
293 | },
294 | {
295 | .pattern = "let me in. LET ME IIIIIIIIN {p}",
296 | .usedParameters = 1,
297 | .analysisFunction = NULL,
298 | .allowedParamTypes = {PARAM_REG8},
299 | .translationPattern = "test rsp, 0xF\n\t"
300 | "jz 1f\n\t"
301 | "sub rsp, 8\n\t"
302 | "call readchar\n\t"
303 | "add rsp, 8\n\t"
304 | "jmp 2f\n\t"
305 | "1: call readchar\n\t"
306 | "2:\n\t"
307 | "mov {0}, BYTE PTR [rip + .LCharacter]\n\t"
308 | },
309 |
310 | ///Random commands
311 | {
312 | .pattern = "guess I'll die",
313 | .usedParameters = 0,
314 | .analysisFunction = NULL,
315 | .translationPattern = "mov rax, [69]"
316 | },
317 | {
318 | .pattern = "confused stonks",
319 | .usedParameters = 0,
320 | .analysisFunction = &setConfusedStonksJumpLabel,
321 | .translationPattern = "jmp .LConfusedStonks_{F}"
322 | },
323 | {
324 | .pattern = "perfectly balanced as all things should be",
325 | .usedParameters = 0,
326 | .analysisFunction = &chooseLinesToBeDeleted,
327 | .translationPattern = ""
328 | },
329 | {
330 | .pattern = "wait, that's illegal",
331 | .usedParameters = 0,
332 | .analysisFunction = NULL,
333 | .translationPattern = "xor rbx, rbx\n\txor rbp, rbp\n\txor r12, r12\n\txor r13 r13"
334 | },
335 | {
336 | .pattern = "oh no! anyway",
337 | .usedParameters = 0,
338 | .analysisFunction = NULL,
339 | .translationPattern = "nop"
340 | },
341 | {
342 | .pattern = "it's over 9000 {p}",
343 | .usedParameters = 1,
344 | .allowedParamTypes = {PARAM_REG},
345 | .analysisFunction = NULL,
346 | .translationPattern = "cmp {0}, 9000\n\tjg 1f\n\thlt\n\t1:"
347 | },
348 | {
349 | .pattern = "refuses to elaborate and leaves",
350 | .usedParameters = 0,
351 | .analysisFunction = NULL,
352 | .translationPattern = "mov rbp, rsp\n\tpop rsp"
353 | },
354 | {
355 | .pattern = "you shall not pass!",
356 | .usedParameters = 0,
357 | .analysisFunction = NULL,
358 | .translationPattern = "1: xor rax, rax\n\tjmp 1b"
359 | },
360 | {
361 | .pattern = "Houston, we have a problem",
362 | .usedParameters = 0,
363 | .analysisFunction = NULL,
364 | .translationPattern = "xor rsp, rsp"
365 | },
366 | {
367 | .pattern = "it's dangerous to go alone, take {p}",
368 | .usedParameters = 1,
369 | .allowedParamTypes = {PARAM_REG64 | PARAM_REG32 | PARAM_REG16},
370 | .analysisFunction = NULL,
371 | .translationPattern = "rdrand {0}"
372 | },
373 | {
374 | .pattern = "we need air support",
375 | .usedParameters = 0,
376 | .analysisFunction = NULL,
377 | .translationPattern = "syscall"
378 | },
379 |
380 | ///Debug commands
381 | {
382 | .pattern = "it's a trap",
383 | .usedParameters = 0,
384 | .analysisFunction = NULL,
385 | .translationPattern = "int3"
386 | },
387 | //Insert commands above this one
388 | {
389 | .pattern = "or draw 25",
390 | .usedParameters = 0,
391 | .analysisFunction = NULL,
392 | .translationPattern = "add eax, 25"
393 | },
394 | {
395 | .pattern = "",
396 | .usedParameters = 0,
397 | .analysisFunction = NULL,
398 | .translationPattern = "0"
399 | }
400 | };
401 |
402 |
403 |
404 | /**
405 | *
406 | * @param compileState a struct containing all necessary infos. Most notably, it contains the outputMode, optimisation level and all parsed input files
407 | * @param outputFileName the name of the output file
408 | */
409 | void compile(struct compileState compileState, char* outputFileName) {
410 | ///Analysis
411 | analyseCommands(&compileState);
412 |
413 | //Analysis done. If any errors occurred until now, print to stderr and exit
414 | if(compileState.compilerErrors > 0) {
415 | printErrorASCII();
416 | fprintf(stderr, "Compilation failed with %u error(s), please check your code and try again.\n", compileState.compilerErrors);
417 | exit(EXIT_FAILURE);
418 | }
419 |
420 | ///Translation
421 | FILE* output;
422 | int gccResult = 0;
423 | //When generating an assembly file, we open the output file in writing mode directly
424 | if(compileState.outputMode == assemblyFile) {
425 | output = fopen(outputFileName, "w") ;
426 | if(output == NULL) {
427 | perror("Failed to open output file");
428 | exit(EXIT_FAILURE);
429 | }
430 | //When letting gcc do the work for us (object file or executable), we just pipe the code into gcc via stdin
431 | } else {
432 | char* commandPrefix;
433 | if(compileState.outputMode == objectFile) {
434 | #ifndef LINUX
435 | commandPrefix = "gcc -w -O -c -x assembler - -o";
436 | #else
437 | commandPrefix = "gcc -z execstack -w -O -c -x assembler - -o";
438 | #endif
439 | } else {
440 | #ifndef LINUX
441 | commandPrefix = "gcc -w -O -x assembler - -o";
442 | #else
443 | commandPrefix = "gcc -z execstack -w -O -no-pie -x assembler - -o"; //-no-pie is only defined because for some reason, the generated stabs info does not work when a PIE object is generated
444 | #endif
445 | }
446 |
447 | char command[strlen(commandPrefix) + strlen(outputFileName) + 1];
448 | strcpy(command, commandPrefix);
449 | strcat(command, outputFileName);
450 |
451 | // Pipe assembler code directly to GCC via stdin
452 | output = popen(command, "w");
453 | }
454 |
455 | writeToFile(&compileState, output);
456 |
457 | if(compileState.outputMode == assemblyFile) {
458 | fclose(output);
459 | } else {
460 | gccResult = pclose(output);
461 | }
462 |
463 | if(gccResult != 0) {
464 | fprintf(stderr, "gcc exited unexpectedly with exit code %d. If you did not expect this to happen, please report this issue at https://github.com/kammt/MemeAssembly/issues so that it can be fixed\n", gccResult);
465 | exit(EXIT_FAILURE);
466 | } else {
467 | exit(EXIT_SUCCESS);
468 | }
469 | }
470 |
--------------------------------------------------------------------------------
/compiler/translator/translator.c:
--------------------------------------------------------------------------------
1 | /*
2 | This file is part of the MemeAssembly compiler.
3 |
4 | Copyright © 2021-2023 Tobias Kamm and contributors
5 |
6 | MemeAssembly is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | MemeAssembly is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with MemeAssembly. If not, see .
18 | */
19 |
20 | #include "translator.h"
21 | #include "../logger/log.h"
22 | #include "../analyser/functions.h"
23 |
24 | #include
25 | #include
26 | #include
27 | #include
28 |
29 | ///STABS flags
30 | #define N_SO 100
31 | #define N_SLINE 68
32 | #define N_FUN 36
33 | #define N_LBRAC 0xc0
34 | #define N_RBRAC 0xe0
35 |
36 | extern const char* const versionString;
37 | extern const struct command commandList[];
38 |
39 | //Used to pseudo-random generation when using bully mode
40 | extern uint64_t computedIndex;
41 |
42 | const char* const martyrdomCode = "push rax\n"
43 | " push rdi\n"
44 | " push rsi\n"
45 | " push rdx\n"
46 | " push r10\n"
47 | " push rcx\n"
48 | " push r11\n"
49 | " \n"
50 | " lea rax, [rip + killParent]\n"
51 | " mov [rip + .Lsa_handler], rax\n"
52 | #ifdef MACOS
53 | //For some reason, signaling SIGINT on MacOS leads to a segmentation fault if the second qword of the sigaction struct
54 | //doesn't contain the address as well
55 | " mov [rip + .Lsa_handler_2], rax\n"
56 | #endif
57 | "\n"
58 | #ifdef LINUX
59 | " mov rax, 13\n"
60 | #else
61 | " mov rax, 0x200002E\n"
62 | #endif
63 | " mov rdi, 2\n"
64 | " lea rsi, [rip + .LsigStruct]\n"
65 | " xor rdx, rdx\n"
66 | " mov r10, 8\n"
67 | " syscall\n"
68 | " \n"
69 | " pop r11\n"
70 | " pop rcx\n"
71 | " pop r10\n"
72 | " pop rdx\n"
73 | " pop rsi\n"
74 | " pop rdi\n"
75 | " pop rax\n\n";
76 |
77 | /**
78 | * Creates the first STABS entry in which the origin file is stored
79 | * @param outputFile the output file
80 | */
81 | void stabs_writeFileInfo(FILE *outputFile, char* inputFileString) {
82 | //Check if the input file string starts with a /. If it does, it is an absolute path
83 | char cwd[PATH_MAX + 1];
84 | if(inputFileString[0] == '/') {
85 | fprintf(outputFile, ".stabs \"%s\", %d, 0, 0, .Ltext0\n", inputFileString, N_SO);
86 | } else {
87 | fprintf(outputFile, ".stabs \"%s/%s\", %d, 0, 0, .Ltext0\n", getcwd(cwd, PATH_MAX), inputFileString, N_SO);
88 | }
89 | }
90 |
91 | /**
92 | * Creates a function info STABS of a given function
93 | * @param outputFile the output file
94 | * @param functionName the name of the function
95 | */
96 | void stabs_writeFunctionInfo(FILE *outputFile, char* functionName) {
97 | fprintf(outputFile, ".stabs \"%s:F1\", %d, 0, 0, %s\n", functionName, N_FUN, functionName);
98 | fprintf(outputFile, ".stabn %d, 0, 0, %s\n", N_LBRAC, functionName);
99 | fprintf(outputFile, ".stabn %d, 0, 0, .Lret_%s\n", N_RBRAC, functionName);
100 | }
101 |
102 | /**
103 | * Is called after a function return command is found. Creates a label for the function info stab to use
104 | * @param outputFile the output file
105 | */
106 | void stabs_writeFunctionEndLabel(FILE *outputFile, char* currentFunctionName) {
107 | fprintf(outputFile, "\t.Lret_%s:\n", currentFunctionName);
108 | }
109 |
110 | /**
111 | * Creates a label for the line number STABS to use
112 | * @param outputFile the output file
113 | * @param parsedCommand the command that requires a line number info
114 | */
115 | void stabs_writeLineLabel(FILE *outputFile, struct parsedCommand parsedCommand) {
116 | fprintf(outputFile, "\t.Lcmd_%lu:\n", parsedCommand.lineNum);
117 | }
118 |
119 | /**
120 | * Creates a line number STABS of the provided command
121 | * @param outputFile the output file
122 | * @param parsedCommand the command that requires a line number info
123 | */
124 | void stabs_writeLineInfo(FILE *outputFile, struct parsedCommand parsedCommand) {
125 | fprintf(outputFile, "\t.stabn %d, 0, %lu, .Lcmd_%lu\n", N_SLINE, parsedCommand.lineNum, parsedCommand.lineNum);
126 | }
127 |
128 | /**
129 | * Receives a command and writes its assembly translation into the output file
130 | * @param compileState the current compile state
131 | * @param currentFunctionName the name of the current function. Needed for writing some stabs debugging info
132 | * @param parsedCommand the command to be translated
133 | * @param fileNum the id of the current file
134 | * @param outputFile the file where the translation should be written to
135 | */
136 | void translateToAssembly(struct compileState* compileState, char* currentFunctionName, struct parsedCommand parsedCommand, unsigned fileNum, bool lastCommand, FILE *outputFile) {
137 | if(commandList[parsedCommand.opcode].commandType != COMMAND_TYPE_FUNC_DEF && compileState->optimisationLevel == o69420) {
138 | printDebugMessage(compileState->logLevel, "\tCommand is not a function declaration, abort.", 0);
139 | return;
140 | }
141 |
142 | //If we are supposed to create STABS info, we now need to create labels
143 | if(compileState->useStabs) {
144 | //If this is a function declaration, update the current function name
145 | if(commandList[parsedCommand.opcode].commandType != COMMAND_TYPE_FUNC_DEF) {
146 | stabs_writeLineLabel(outputFile, parsedCommand);
147 | }
148 | }
149 |
150 | struct command command = commandList[parsedCommand.opcode];
151 | char *translationPattern = command.translationPattern;
152 |
153 | if(commandList[parsedCommand.opcode].commandType != COMMAND_TYPE_FUNC_DEF) {
154 | fprintf(outputFile, "\t");
155 | }
156 | for(size_t i = 0; i < strlen(translationPattern); i++) {
157 |
158 | //Check if this is a format specifier
159 | if(translationPattern[i] == '{' && translationPattern[i + 2] == '}') {
160 | char formatSpecifier = translationPattern[i + 1];
161 | //If the format_specifier is F, we need to add the value of the current file's index to the string
162 | if(formatSpecifier == 'F') {
163 | fprintf(outputFile, "%u", fileNum);
164 | //Is it a parameter?
165 | } else if(formatSpecifier >= '0' && formatSpecifier < command.usedParameters + '0') {
166 | uint8_t index = formatSpecifier - 48;
167 | char *parameter = parsedCommand.parameters[index];
168 | if(parsedCommand.isPointer == index + 1) {
169 | /*
170 | * If we are in bully mode, we first need to check if the operand size is unknown (e.g. a pointer
171 | * and a decimal number are used). This is because this check is skipped in parameters.c
172 | */
173 | if(compileState->compileMode == bully && commandList[parsedCommand.opcode].usedParameters == 2 && !PARAM_ISREG(parsedCommand.paramTypes[index + 1 % 2])) {
174 | const char* operandSizes[] = {"BYTE PTR", "WORD PTR", "DWORD PTR", "QWORD PTR"};
175 | fprintf(outputFile, "%s [%s]", operandSizes[computedIndex % 4], parameter);
176 | } else {
177 | fprintf(outputFile, "[%s]", parameter);
178 | }
179 | } else {
180 | /*
181 | * If the parameter is a decimal number, write it as a hex string. Fixes issue #73
182 | * The check is only needed here, as a decimal number cannot be a pointer
183 | */
184 | if(parsedCommand.paramTypes[index] == PARAM_DECIMAL) {
185 | fprintf(outputFile, "0x%llX", strtoll(parameter, NULL, 10));
186 | } else {
187 | fprintf(outputFile, "%s", parameter);
188 | }
189 | }
190 | } else {
191 | printInternalCompilerError("Invalid translation format specifier '%c' for opcode %u", true, 2, formatSpecifier, parsedCommand.opcode);
192 | exit(EXIT_FAILURE);
193 | }
194 |
195 | //move our pointer along by three characters instead of one, as we just parsed three characters
196 | i += 2;
197 | } else {
198 | fprintf(outputFile, "%c", translationPattern[i]);
199 | }
200 | }
201 | fprintf(outputFile, "\n");
202 |
203 | //Now, we need to insert more commands based on the current optimisation level
204 | if (compileState->optimisationLevel == o_1) {
205 | //Insert a nop
206 | fprintf(outputFile, "\tnop\n");
207 | } else if (compileState->optimisationLevel == o_2) {
208 | //Push and pop rax
209 | fprintf(outputFile, "\tpush rax\n\tpop rax\n");
210 | } else if (compileState->optimisationLevel == o_3) {
211 | //Save and restore xmm0 on the stack using movups
212 | fprintf(outputFile, "\tmovups [rsp + 8], xmm0\n\tmovups xmm0, [rsp + 8]\n");
213 | } else if(compileState->optimisationLevel == o69420) {
214 | //If we get here, then this was a function declaration. Insert a ret-statement and exit
215 | fprintf(outputFile, "\txor rax, rax\n\tret\n");
216 | }
217 |
218 | if(compileState->useStabs && commandList[parsedCommand.opcode].commandType != COMMAND_TYPE_FUNC_DEF) {
219 | //If this was a return statement and this is the end of file or a function definition is followed by it, we reached the end of the function. Define the label for the N_RBRAC stab
220 | if(lastCommand) {
221 | stabs_writeFunctionEndLabel(outputFile, currentFunctionName);
222 | }
223 | //In any case, we now need to write the line info to the file
224 | stabs_writeLineInfo(outputFile, parsedCommand);
225 | }
226 | }
227 |
228 | void writeToFile(struct compileState* compileState, FILE *outputFile) {
229 | time_t t = time(NULL);
230 | struct tm tm = *localtime(&t);
231 |
232 | fprintf(outputFile, "#\n# Generated by the MemeAssembly compiler %s on %s#\n", versionString, asctime(&tm));
233 | fprintf(outputFile, ".intel_syntax noprefix\n");
234 |
235 | //Define all functions as global
236 | for(unsigned i = 0; i < compileState->fileCount; i++) {
237 | for(size_t j = 0; j < compileState->files[i].functionCount; j++) {
238 | //Only write if the function definition is to be translated
239 | if(compileState->files[i].functions[j].commands[0].translate) {
240 | //Write the function name with the prefix ".global" to the file
241 | fprintf(outputFile, ".global %s\n", compileState->files[i].functions[j].commands[0].parameters[0]);
242 | }
243 | }
244 | }
245 |
246 | #ifdef WINDOWS
247 | //To interact with the Windows API, we need to reference the needed functions
248 | fprintf(outputFile, "\n.extern GetStdHandle\n.extern WriteFile\n.extern ReadFile\n");
249 | #endif
250 |
251 | fprintf(outputFile, "\n.data\n\t");
252 | fprintf(outputFile, ".LCharacter: .ascii \"a\"\n\t.Ltmp64: .byte 0, 0, 0, 0, 0, 0, 0, 0\n");
253 |
254 | //Struct for martyrdom command
255 | #ifdef LINUX
256 | fprintf(outputFile, "\t.LsigStruct:\n"
257 | "\t\t.Lsa_handler: .quad 0\n"
258 | "\t\t.quad 0x04000000\n"
259 | "\t\t.quad 0, 0\n\n");
260 | #elif defined(MACOS)
261 | fprintf(outputFile, "\t.LsigStruct:\n"
262 | "\t\t.Lsa_handler: .quad 0\n"
263 | "\t\t.Lsa_handler_2: .quad 0\n"
264 | "\t\t.quad 0, 0\n\n");
265 | #endif
266 |
267 | fprintf(outputFile, "\n\n.text\n\t");
268 | fprintf(outputFile, "\n\n.Ltext0:\n");
269 |
270 | #ifndef WINDOWS
271 | fprintf(outputFile, "killParent:\n"
272 | #ifdef LINUX
273 | " mov rax, 110\n"
274 | #else
275 | " mov rax, 0x2000027\n"
276 | #endif
277 | " syscall\n"
278 | "\n"
279 | " mov rdi, rax\n"
280 | " mov rsi, 9\n"
281 | #ifdef LINUX
282 | " mov rax, 62\n"
283 | #else
284 | " mov rax, 0x2000025\n"
285 | #endif
286 | " syscall\n"
287 | "\n"
288 | " mov rdi, 0\n"
289 | " mov rax, 60\n"
290 | " syscall\n"
291 | " ret\n\n");
292 |
293 | #endif
294 |
295 | /*
296 | * If we're in bully mode and an executable is to be generated, we omitted the check
297 | * if there was a main-function
298 | * We do that check now. If no main function exists, the first function in the file becomes the main function
299 | */
300 | if(compileState->compileMode == bully && compileState->outputMode == executable && !mainFunctionExists(compileState)) {
301 | fprintf(outputFile, "\n.global main\n\t");
302 | fprintf(outputFile, "\nmain:\n\t");
303 | fprintf(outputFile, "%s", martyrdomCode);
304 | }
305 |
306 | for(unsigned i = 0; i < compileState->fileCount; i++) {
307 | struct file currentFile = compileState->files[i];
308 | //Write the file info if we are using stabs
309 | if(compileState->useStabs) {
310 | stabs_writeFileInfo(outputFile, currentFile.fileName);
311 | }
312 |
313 | size_t line = 0;
314 | for(size_t j = 0; j < currentFile.functionCount; j++) {
315 | struct function currentFunction = currentFile.functions[j];
316 | char* functionName = currentFunction.commands[0].parameters[0];
317 |
318 | for(size_t k = 0; k < currentFunction.numberOfCommands; k++) {
319 | #ifndef WINDOWS
320 | const char *const mainFuncName =
321 | #ifdef MACOS
322 | "_main";
323 | #else
324 | "main";
325 | #endif
326 |
327 | if (compileState->martyrdom && k == 1 && strcmp(functionName, mainFuncName) == 0) {
328 | fprintf(outputFile, "%s", martyrdomCode);
329 | }
330 | #endif
331 |
332 | struct parsedCommand currentCommand = currentFunction.commands[k];
333 |
334 | //Print the confused stonks label now if it should be at this position
335 | if (line == currentFile.randomIndex) {
336 | fprintf(outputFile, "\t.LConfusedStonks_%u: \n", i);
337 | }
338 |
339 | //If it should be translated, translate it
340 | if (currentCommand.translate) {
341 | translateToAssembly(compileState, functionName, currentCommand, i,
342 | (k == currentFunction.numberOfCommands - 1), outputFile);
343 | }
344 |
345 | //Insert STABS function-info
346 | if (compileState->useStabs) {
347 | stabs_writeFunctionInfo(outputFile, functionName);
348 | }
349 | line++;
350 | }
351 | }
352 | }
353 |
354 | //If the optimisation level is 42069, then this function will not be used as all commands are optimised out
355 | if(compileState->optimisationLevel != o69420) {
356 | #ifdef WINDOWS
357 | //Using Windows API
358 | fprintf(outputFile,
359 | "\n\nwritechar:\n"
360 | "\tpush rcx\n"
361 | "\tpush rax\n"
362 | "\tpush rdx\n"
363 | "\tpush r8\n"
364 | "\tpush r9\n"
365 | //Get Handle of stdout
366 | "\tsub rsp, 32\n"
367 | "\tmov rcx, -11\n" //-11=stdout
368 | "\tcall GetStdHandle\n"//return value is in rax
369 | //Prepare the parameters for output
370 | "\tmov rcx, rax\n" //move Handle of stdout into rcx
371 | "\tlea rdx, [rip + .LCharacter]\n"
372 | "\tmov r8, 1\n" //Length of message = 1 character
373 | "\tlea r9, [rip + .Ltmp64]\n" //Number of bytes written, just discard that value
374 | "\tmov QWORD PTR [rsp + 32], 0\n"
375 | "\tcall WriteFile\n"
376 | "\tadd rsp, 32\n"
377 |
378 | //Restore all registers
379 | "\tpop r9\n"
380 | "\tpop r8\n"
381 | "\tpop rdx\n"
382 | "\tpop rax\n"
383 | "\tpop rcx\n"
384 | "\tret\n");
385 |
386 | fprintf(outputFile,
387 | "\n\nreadchar:\n"
388 | "\tpush rcx\n"
389 | "\tpush rax\n"
390 | "\tpush rdx\n"
391 | "\tpush r8\n"
392 | "\tpush r9\n"
393 | //Get Handle of stdin
394 | "\tsub rsp, 32\n"
395 | "\tmov rcx, -10\n" //-10=stdin
396 | "\tcall GetStdHandle\n"//return value is in rax
397 | //Prepare the parameters for reading from input
398 | "\tmov rcx, rax\n" //move Handle of stdin into rcx
399 | "\tlea rdx, [rip + .LCharacter]\n"
400 | "\tmov r8, 1\n" //Bytes to read = 1 character
401 | "\tlea r9, [rip + .Ltmp64]\n" //Number of bytes read, just discard that value
402 | //Parameter 5 and then 4 Bytes of emptiness on the stack
403 | "\tmov QWORD PTR [rsp + 32], 0\n"
404 | "\tcall ReadFile\n"
405 | "\tadd rsp, 32\n"
406 |
407 | //Restore all registers
408 | "\tpop r9\n"
409 | "\tpop r8\n"
410 | "\tpop rdx\n"
411 | "\tpop rax\n"
412 | "\tpop rcx\n"
413 | "\tret\n");
414 | #else
415 | //Using Linux syscalls
416 | fprintf(outputFile, "\n\nwritechar:\n\t"
417 | "push rcx\n\t"
418 | "push r11\n\t"
419 | "push rax\n\t"
420 | "push rdi\n\t"
421 | "push rsi\n\t"
422 | "push rdx\n\t"
423 | "mov rdx, 1\n\t"
424 | "lea rsi, [rip + .LCharacter]\n\t"
425 | "mov rdi, 1\n\t"
426 | #ifdef LINUX
427 | "mov rax, 1\n\t"
428 | #else
429 | "mov rax, 0x2000004\n\t"
430 | #endif
431 | "syscall\n\t"
432 | "pop rdx\n\t"
433 | "pop rsi\n\t"
434 | "pop rdi\n\t"
435 | "pop rax\n\t"
436 | "pop r11\n\t"
437 | "pop rcx\n\t\n\t"
438 | "ret\n");
439 |
440 | fprintf(outputFile, "\n\nreadchar:\n\t"
441 | "push rcx\n\t"
442 | "push r11\n\t"
443 | "push rax\n\t"
444 | "push rdi\n\t"
445 | "push rsi\n\t"
446 | "push rdx\n\n\t"
447 | "mov rdx, 1\n\t"
448 | "lea rsi, [rip + .LCharacter]\n\t"
449 | "mov rdi, 0\n\t"
450 | #ifdef LINUX
451 | "mov rax, 0\n\t"
452 | #else
453 | "mov rax, 0x2000003\n\t"
454 | #endif
455 | "syscall\n\n\t"
456 | "pop rdx\n\t"
457 | "pop rsi\n\t"
458 | "pop rdi\n\t"
459 | "pop rax\n\t"
460 | "pop r11\n\t"
461 | "pop rcx\n\t"
462 | "ret\n");
463 | #endif
464 | }
465 |
466 | //Add an "end marker" if we are using stabs
467 | if(compileState->useStabs) {
468 | fprintf(outputFile, "\n.LEOF:\n");
469 | fprintf(outputFile, ".stabs \"\", %d, 0, 0, .LEOF\n", N_SO);
470 | }
471 |
472 | if(compileState->optimisationLevel == o_s) {
473 | fprintf(outputFile, ".align 536870912\n");
474 | }
475 | }
476 |
--------------------------------------------------------------------------------