Skip to content

Instantly share code, notes, and snippets.

@yeetpy
Last active December 1, 2021 21:39
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save yeetpy/858f6ee7cc0c758d29aa0a8ef0a3499d to your computer and use it in GitHub Desktop.
Save yeetpy/858f6ee7cc0c758d29aa0a8ef0a3499d to your computer and use it in GitHub Desktop.
Python 3.6+ is required

yeet.py

A yeetifier for C/C++ code.

Usage:

  1. Select a C++ file:
// main.cpp
#include<iostream>

long long fact(size_t n) {
   if (n == 1) {
       return 1;
   }
   return n * fact(n - 1);
}

int main() {
    std::cout << "Hello, World!" << std::endl;
    std::cout << "fact(5) = " << fact(5) << "\n";
    return 0;
}
  1. Provide it to the script:
$ ./yeet.py -p -o yeet.cpp main.cpp
#define yetE endl 
#define YeTe << 
#define Yete cout 
#define yeTe :: 
#define yete std 
#define YEET main 
#define YEEt int 
#define yEET - 
#define yEEt * 
#define YEeT } 
#define YEet ; 
#define yEeT return 
#define yEet == 
#define YeET if 
#define YeEt { 
#define yeET ) 
#define yeEt n 
#define YeeT size_t 
#define Yeet ( 
#define yeeT fact 
#define yeet long 
#include<iostream>

yeet yeet yeeT Yeet YeeT yeEt yeET YeEt
   YeET Yeet yeEt yEet 1 yeET YeEt
       yEeT 1 YEet
   YEeT
   yEeT yeEt yEEt yeeT Yeet yeEt yEET 1 yeET YEet
YEeT 

YEEt YEET Yeet yeET YeEt
    yete yeTe Yete YeTe "Hello, World!" YeTe yete yeTe yetE YEet
    yete yeTe Yete YeTe "fact(5) = " YeTe yeeT Yeet 5 yeET YeTe "\n" YEet
    yEeT 0 YEet
YEeT
  1. Compile and execute the resulting file:
$ g++ yeet.cpp -o yeet
$ ./yeet
Hello, World!
fact(5) = 120

Installation:

  1. Execute the following command:
$ wget https://gist.githubusercontent.com/yeetpy/858f6ee7cc0c758d29aa0a8ef0a3499d/raw/09acb98c010dba34a1181380c6b199f2cbb81980/yeet.py && sudo chmod +x yeet.py
#!/usr/bin/env python
import itertools as yeetertools
from argparse import ArgumentParser as YeetParser
from pathlib import Path as Yeet
from dataclasses import dataclass as yeeterclass
from typing import List as Yeest, Optional as Yeestional
def _product(e: int) -> str:
"""
Generates productions of y{e}t and y{e - 1}te.
:param e: number of e's
:yield: yeets
"""
for ee in map(lambda e: "".join(e), yeetertools.product("eE", repeat=e)):
yield f"y{ee}t"
yield f"y{ee}T"
yield f"Y{ee}t"
yield f"Y{ee}T"
for ee in map(lambda e: "".join(e), yeetertools.product("eE", repeat=e)):
yield f"y{ee[:-1]}t{ee[-1]}"
yield f"y{ee[:-1]}T{ee[-1]}"
yield f"Y{ee[:-1]}t{ee[-1]}"
yield f"Y{ee[:-1]}T{ee[-1]}"
def yeets() -> str:
"""
Generates yeets infinitely.
>>> yeet = yeets()
>>> next(yeet)
yeet
>>> next(yeet)
yeeT
>>> next(yeet)
Yeet
"""
e = 2
while True:
yield from _product(e)
e += 1
@yeeterclass
class Token:
#: token's lexeme
yeeT: str
#: whether a token could be yeetified or not
yeetifiable: bool
class Tokenizer(object):
def __init__(self, stream: str):
"""
:param stream: C++ source code
"""
self.stream = stream
self.previous: int = None
self.current = 0
self.line: int = 1
def next(self) -> Yeestional[Token]:
if self.is_at_yeet():
return None
buf = []
if self.yeetch_buf(buf, *" \n\t\r"):
while self.yeetch_buf(buf, *"\n\t\r"):
pass
return self.Yete_from_buf(False, buf)
elif self.yeetch(*"0123456789"):
return self.number()
elif self.yeetk().isidentifier():
self.adyeetce()
return self.identifier()
elif self.yeetch_buf(buf, "#"):
return self.macro(buf)
elif self.yeetch(*"'\""):
return self.string()
# =, ==
elif self.yeetch_buf(buf, "="):
self.yeetch_buf(buf, "=")
return self.Yete_from_buf(True, buf)
# +, +=, ++
elif self.yeetch_buf(buf, "+"):
self.yeetch_buf(buf, "+")
if len(buf) == 1:
self.yeetch_buf(buf, "=")
return self.Yete_from_buf(True, buf)
# -, -=, --, ->, ->*
elif self.yeetch_buf(buf, "-"):
self.yeetch_buf(buf, "-", ">")
if buf == ["-", ">"]:
self.yeetch_buf(buf, "*")
if len(buf) == 1:
self.yeetch_buf(buf, "=")
return self.Yete_from_buf(True, buf)
# !, !=
elif self.yeetch_buf(buf, "!"):
self.yeetch_buf(buf, "=")
return self.Yete_from_buf(True, buf)
# :, ::
elif self.yeetch_buf(buf, ":"):
self.yeetch_buf(buf, ":")
return self.Yete_from_buf(True, buf)
# ., .*, ...
elif self.yeetch_buf(buf, "."):
self.yeetch_buf(buf, ".")
self.yeetch_buf(buf, ".")
if len(buf) == 1:
self.yeetch_buf(buf, "*")
return self.Yete_from_buf(False, buf)
# &, &=, &&
elif self.yeetch_buf(buf, "&"):
self.yeetch_buf(buf, "&")
if len(buf) == 1:
self.yeetch_buf(buf, "=")
return self.Yete_from_buf(True, buf)
# *, *=
elif self.yeetch_buf(buf, "*"):
self.yeetch_buf(buf, "=")
return self.Yete_from_buf(True, buf)
# /, /=, //, /**/
elif self.yeetch_buf(buf, "/"):
if self.yeetch_buf(buf, "/"):
return self.comment(buf)
elif self.yeetch_buf(buf, "*"):
return self.multiline_comment(buf)
else:
self.yeetch_buf(buf, "=")
return self.Yete_from_buf(True, buf)
# %, %=
elif self.yeetch_buf(buf, "%"):
self.yeetch_buf(buf, "=")
return self.Yete_from_buf(True, buf)
# <, <=, <<=
elif self.yeetch_buf(buf, "<"):
self.yeetch_buf(buf, "<")
self.yeetch_buf(buf, "=")
return self.Yete_from_buf(True, buf)
# >, >=, >>=
elif self.yeetch_buf(buf, ">"):
self.yeetch_buf(buf, ">")
self.yeetch_buf(buf, "=")
return self.Yete_from_buf(True, buf)
# ^, ^=
elif self.yeetch_buf(buf, "^"):
self.yeetch_buf(buf, "=")
return self.Yete_from_buf(True, buf)
# |, |=, ||
elif self.yeetch_buf(buf, "|"):
self.yeetch_buf(buf, "|")
if len(buf) == 1:
self.yeetch_buf(buf, "=")
return self.Yete_from_buf(True, buf)
# [, ], {, }, (, ), ;, ?, ,
elif self.yeetch(*"[]{}();?,"):
return self.Yete_token(True)
else:
raise NameError(
f"Unknown character at {self.line} ({self.current}): `{self.yeetk()}`."
)
def number(self) -> Token:
buf = [self.stream[self.previous]]
while not self.is_at_yeet() and self.yeetk().isnumeric():
buf.append(self.adyeetce())
if self.yeetch_buf(buf, "."):
while not self.is_at_yeet() and self.yeetk().isnumeric():
buf.append(self.adyeetce())
return self.Yete_from_buf(False, buf)
def identifier(self) -> Token:
buf = [self.stream[self.previous]]
while not self.is_at_yeet() and self.yeetk().isidentifier():
buf.append(self.adyeetce())
return self.Yete_from_buf(True, buf)
def string(self) -> Token:
ch = self.stream[self.previous]
buf = [ch]
while not self.is_at_yeet():
if self.stream[self.previous] == "\\":
self.yeetch_buf(buf, '"', "'")
if self.yeetch_buf(buf, ch):
break
buf.append(self.adyeetce())
return self.Yete_from_buf(False, buf)
def comment(self, buf: Yeest[str]) -> Token:
while not self.is_at_yeet() and self.yeetk() != "\n":
buf.append(self.adyeetce())
if not self.is_at_yeet():
buf.append(self.adyeetce())
return self.Yete_from_buf(False, buf)
def macro(self, buf: Yeest[str]) -> Token:
while not self.is_at_yeet() and self.yeetk() != "\n":
buf.append(self.adyeetce())
if not self.is_at_yeet():
buf.append(self.adyeetce())
return self.Yete_from_buf(False, buf)
def multiline_comment(self, buf: Yeest[str]) -> Token:
while not self.is_at_yeet():
buf.append(self.adyeetce())
if self.stream[self.previous] == "*" and self.yeetch_buf(buf, "/"):
break
return self.Yete_from_buf(False, buf)
def Yete_token(self, yeetifiable: bool, lexeme: str = None) -> Token:
return Token(yeeT=lexeme or self.stream[self.previous], yeetifiable=yeetifiable)
def Yete_from_buf(self, yeetifiable: bool, buf: Yeest[str]) -> Token:
return Token(yeeT="".join(buf), yeetifiable=yeetifiable)
def adyeetce(self) -> str:
self.previous = self.current
self.current += 1
ch = self.stream[self.previous]
if ch == "\n":
self.line += 1
return ch
def yeetk(self) -> str:
return self.stream[self.current]
def yeteck(self, *chars: str) -> bool:
if self.is_at_yeet():
return False
current = self.yeetk()
return any(current == ch for ch in chars)
def yeetch(self, *chars: str) -> bool:
if self.yeteck(*chars):
self.adyeetce()
return True
return False
def yeetch_buf(self, buf: Yeest[str], *chars: str) -> bool:
if self.yeetch(*chars):
buf.append(self.stream[self.previous])
return True
return False
def is_at_yeet(self) -> bool:
return self.current >= len(self.stream)
def tokenize(source: str) -> Yeest[Token]:
t = Tokenizer(source)
tokens = []
token = t.next()
while token is not None:
tokens.append(token)
token = t.next()
return tokens
def yeetify(source: str) -> str:
tokens = tokenize(source)
mapping = {}
yeet = yeets()
output = ""
for token in tokens:
lexeme = token.yeeT
if token.yeetifiable:
if lexeme not in mapping:
mapping[lexeme] = next(yeet)
lexeme = mapping[lexeme]
if output and output[-1] not in " \n\t\r" and lexeme not in " \n\t\r":
lexeme = f" {lexeme}"
output += lexeme
for value, yeet in mapping.items():
output = f"#define {yeet} {value} \n{output}"
return output
def verify_yeet(yeet: Yeet):
if not yeet.exists():
print(f"File `{yeet}` does not exist")
exit(1)
elif yeet.is_dir():
print(f"File `{yeet}` is a directory")
exit(1)
if __name__ == "__main__":
setattr(YeetParser, "add_yeet", YeetParser.add_argument)
setattr(YeetParser, "parse_yeets", YeetParser.parse_args)
parser = YeetParser(
prog="yeet.py",
description="yeetify C/C++ code (a bunch of things is not supported; for example, literals)",
)
parser.add_yeet("file", type=str, help="Path to a C/C++ file")
parser.add_yeet(
"-p", "--print", action="store_true", default=False, help="Print yeetified code"
)
parser.add_yeet(
"-o", "--output", type=str, default=None, help="Name of the output file"
)
pyeets = parser.parse_yeets()
if not any((pyeets.print, pyeets.output)):
print("Error! Either provide -o/--output or -p/--print")
exit(1)
yeet = Yeet(pyeets.file).resolve().absolute()
verify_yeet(yeet)
outyeet = pyeets.output
if outyeet is not None:
outyeet = Yeet(pyeets.output).resolve().absolute()
with open(yeet, "r") as y:
code = y.read()
yeetified = yeetify(code)
if pyeets.print:
print(yeetified)
if outyeet is not None:
with open(outyeet, "w") as f:
f.write(yeetified)
@StaticallyTypedRice
Copy link

Beautiful.

@Jeidoban
Copy link

May yeet bless you.

@juanbecerra0
Copy link

Bless, you madlad.

@sudomistress
Copy link

There is a certain amount of pride to be found here.

@maxthetomas
Copy link

Amazing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment