online compiler and debugger for c/c++

code. compile. run. debug. share.
Source Code   
Language
// Bit Tool v0.1.0 // /* Used for showing raw bits without reading thousands of pages of documentation. */ // was for practicing but turned out to be real // Copyright C 2026 Johnryzon Z. Abejero // ==========> MIT License <========== // </> Code ---> #include <stdio.h> // for printing and inputting #include <stdlib.h> // for malloc and free // shouldn't include <malloc.h> since it's deprecated // MACROS // Just some flavors :) #define print printf // aliases printf to print // using func instead of typing the return type directly #define func(type) type // define custom boolean macros to prevent including <stdbool.h> #define bool _Bool // in programming booleans are just integers #define true 1 // true is equal to 1 #define false 0 // false is equal to 0 // ^MACROS^ // The "Label" /* has the needed token types for main to know what the type was without comparing it's lexeme */ typedef enum TokenType { // most of this types here are operators // Don't mind to read it number, bitshift_left, bitshift_right, bit_xor, bit_not, bit_or, bit_and, plus, minus, times, divide, greater, less, /* ------> */ scan_error // <--- for error reporting } TokenType; // enum // Token structure // Used by the lexer typedef struct Token { // -> struct // a type label instead of comparing strings which is slow TokenType type; // stores the line number which is useful for error reporting int line; /* stores the length of the lexeme (useful to print the lexeme without printing text from the start of the token to the very end) */ int length; // stores the "lexeme" from the start of the token to the very end char* lexeme; // Optional: for error messages char* message; // stores error messages } Token; // struct // Holder for the scanner typedef struct Scanner { // -> struct char* start; // The start for the token char* current; // the current character (The moving pointer) int line; // The current line -- For error reporting } Scanner; // struct // for moving the current character func(void) nextChar(Scanner* scanner) { // -> none(void) scanner->current++; // add 1 to current's memory address } // func(void) nextChar(Scanner* scanner) // for looking at the current character func(char) peek(Scanner* scanner) { // -> character if (!scanner) { // if scanner was not initialized // return the none character '\0' and print a message print("BUG: Scanner was not initialized."); // SECURITY feature return '\0'; // return none } // if (!scanner) return *scanner->current; // return the current character } // func(char) peek(Scanner* scanner) // for looking at the next character without moving current func(char) peekNext(Scanner* scanner) { if (peek(scanner) == '\0') { // if the current character is at the end return '\0'; // return nothing to stop segfaults } // if (peek(scanner) == '\0') // using '+ 1' instead of just '[1]' return *(scanner->current + 1); // a more pointer world } // func(char) peekNext(Scanner* scanner) /* move the current character and return true if the next character is the same as the expected character or else just return false */ func(bool) match(Scanner* scanner, char expected) { // if the next character is equal to the given expected character if (peekNext(scanner) == expected) { // move the current pointer nextChar(scanner); nextChar(scanner); // and return true return true; } // but if it not then return false return false; } // Checks if the given character is a number func(bool) isnum(char c) { if (c >= '0' && c <= '9') return true; return false; } // For comparing strings without loading the huge cstring.h header func(bool) strcompr(char* str1, char* str2) { // -> bool // while the first string character is not in the end and also the second string while (*str1 != '\0' && *str2 != '\0') { /* if the current character in string 1 is not equal to the curent character in string 2 then return false */ if (*str1 != *str2) return false; // return false // increment string 1 and string 2's current character str1++; // add 1 str2++; // add 1 } // while (*str1 != '\0 && *str2 != '\0') // return true only if string 1 and string 2 stopped at the same length return (*str1 == '\0' && *str2 == '\0'); // give the result } // func(bool) strcompr(char* str1, char* str2) // Converts a token to a number func(double) token_to_num(Token* token) { // -> double // declare result to 0 double result = 0; // used for tracking the decimal double fraction = 0.1; // for telling the program if a number has a decimal bool hasdot = false; // a loop from 0 to the token's length for (int i = 0; i < token->length; i++) { // set c to the current lexeme char c = token->lexeme[i]; // no need to type the whole 'token->lexeme[i]' everytime // check for a dot if (c == '.') { // set hasdot to true hasdot = true; continue; // skip the rest of the code and loop back } // if (c == '.') // if it doesn't have a dot if (!hasdot) { // set result by result * 10 and add the character - hex of '0' result = (result * 10) + (c - '0'); // convert to number } else { // but if has a decimal point // result will be result + c - hex of '0' * the location of the decimal result = result + (c - '0') * fraction; /* convert to number and add fraction to turn it to decimal */ fraction /= 10.0; // divide fraction by 10 } // if (!hasdot) {} else } // for (int i = 0; i < token->length; i++) // give back result return result; // return } // func(double) token_to_num(Token* token) // Creates a new token, set needed information and gives it back func(Token) createToken(Scanner* scanner, TokenType type) { // -> Token // Create an uninitialized tokem Token token; // uninitialized // set the token's type to the given type token.type = type; // type to given type // set the line to the scanner's current line token.line = scanner->line; // line to scanner's line // set the length by subtracting current's memory address and start's memory address token.length = scanner->current - scanner->start; // length to current - start // store start to the lexeme token.lexeme = scanner->start; // lexeme to start // set message to nothing since we don't use it on regular tokens token.message = ""; // none // return the initilized token return token; // return } // func(Token) createToken(Scanner* scanner, TokenType type) /* creates a token, put needed things in it (including the error message) and gives it back */ func(Token) scanError(Scanner* scanner, char* message) { // -> Token // Create an uninitialized tokem Token token; // uninitialized // set the token's type to error mode token.type = scan_error; // type to error mode // set the line to the scanner's current line token.line = scanner->line; // line to scanner's line // set the length by subtracting current's memory address and start's memory address token.length = scanner->current - scanner->start; // length by the current - start // store start to the lexeme token.lexeme = scanner->start; // lexeme to start // set message to the given message token.message = message; // message to the given message // return the initialized token return token; // give it back } // func(Token) scanError(Scanner* scanner, char* message) // initilizes the scanner func(void) initScanner(Scanner* scanner, char* src) { // -> none scanner->start = src; // start to given source scanner->current = src; // current to given source scanner->line = 1; // line to 1 } // func(void) initScanner(Scanner* scanner, char* src) // Skips spaces/other things that is not needed func(void) skipSpaces(Scanner* scanner) { // -> none // set an infinite loop while (1) { // store the current char at c char c = peek(scanner); // switch instead of a giant if and else statements switch (c) { // check for a space, a tab and a carriage return(enter) and if found then skip it case ' ': case '\t': case '\r': nextChar(scanner); break; // but if found a newline skip it and add 1 to line case '\n': nextChar(scanner); scanner->line++; break; // for the default i just return so no other symbol bugs default: return; } } } // scans a single token func(Token) scanToken(Scanner* scanner) { // set start to the current character scanner->start = scanner->current; // use c instead of using peek everytime char c = peek(scanner); // set a switch switch (c) { case '+': nextChar(scanner); return createToken(scanner, plus); break; case '-': nextChar(scanner); return createToken(scanner, minus); break; case '*': nextChar(scanner); return createToken(scanner, times); break; case '/': nextChar(scanner); return createToken(scanner, divide); break; case '<': if (match(scanner, '<')) return createToken(scanner, bitshift_left); nextChar(scanner); return createToken(scanner, less); case '>': if (match(scanner, '>')) return createToken(scanner, bitshift_right); nextChar(scanner); return createToken(scanner, greater); case '|': nextChar(scanner); return createToken(scanner, bit_or); case '&': nextChar(scanner); return createToken(scanner, bit_and); case '^': nextChar(scanner); return createToken(scanner, bit_xor); case '~': nextChar(scanner); return createToken(scanner, bit_not); default: { if (isnum(c)) { while(isnum(peek(scanner))) nextChar(scanner); // if the current character is a dot consume it if (peek(scanner) == '.') { // consume '.' nextChar(scanner); while (isnum(peek(scanner))) nextChar(scanner); } return createToken(scanner, number); } nextChar(scanner); return scanError(scanner, "Unexpected character."); } } return scanError(scanner, "BUG: Switch didn't run for some reason."); } // Shows the moving of bytes in an operation func(void) visualBits(double n) { print("=========== Visual bits ==========\n"); print("<---------------------------------\n"); for (int i = 31; i >= 0; i--) { int bit = ((int)n >> i) & 1; print("%d", bit); if (i % 8 == 0) print(" "); } print("\n"); } // Shows the raw bytes of a number func(void) rawBytes(double n) { unsigned char *p = (unsigned char *)&n; for (size_t i = 0; i < sizeof(double); i++) { printf("%02X ", p[i]); } printf("\n"); } func(void) REPL(Scanner* scanner) { double result = 0; bool hasleft = false; bool didMath = false; bool isCond = false; // is it a Condition like > TokenType currentOp; while (peek(scanner) != '\0' && peek(scanner) != '\n') { skipSpaces(scanner); Token tok = scanToken(scanner); if (tok.type == scan_error) { print("Error: %s\n", tok.message); return; } if (tok.type == number) { double val = token_to_num(&tok); if (currentOp == bit_not) { val = ~(int)val; didMath = true; currentOp = scan_error; } if (!hasleft) { result = val; hasleft = true; } else { isCond = true; hasleft = false; if (currentOp == greater) { result = result > token_to_num(&tok); if (result) print("Result: True\n"); else print("Result: False\n"); } else if (currentOp == less) { result = result < token_to_num(&tok); if (result) print("Result: True\n"); else print("Result: False\n"); } if (currentOp != greater && currentOp != less) { isCond = false; didMath = true; hasleft = true; } if (currentOp == plus) result += val; else if (currentOp == minus) result -= val; else if (currentOp == times) result *= val; else if (currentOp == divide) result /= val; else if (currentOp == bit_and) result = (int)result & (int)val; else if (currentOp == bit_or) result = (int)result | (int)val; else if (currentOp == bitshift_left) result = (int)result << (int)val; else if (currentOp == bitshift_right) result = (int)result >> (int)val; else if (currentOp == bit_xor) result = (int)result ^ (int)val; } } else { currentOp = tok.type; } } if (didMath) { print("Warning: Bit operators don't allow decimals.\n\ Note: Using decimal numbers may cause bittool to round it off.\n\n"); visualBits(result); print("Result: %lg\n", result); print("Result (hex): 0x%X\n", (unsigned int)result); print("Result (scientific hex): %a\n", result); print("Result (raw bytes): "); rawBytes(result); } else if (hasleft) { print("Number: %lg\n", result); print("Number (hex): 0x%X\n", (unsigned int)result); print("Number (scientific hex): %a\n", result); print("Number (raw bytes): "); rawBytes(result); } else if (!isCond) { print("Warning: Operators cannot be on their own.\n"); } } // I got tired of making comments :) func(int) main(int argc, char* argv[]) { // misc char input[100]; bool fromArgs = false; Scanner* scanner = malloc(sizeof(Scanner)); if (argc > 2) { print("Usage: bittool [command]\n"); return 1; } print("====== Bit Tool in C v0.1.0 ======\n"); print("- 64 bit representation\n"); if (argc == 2) fromArgs = true; if (!fromArgs) { print("Enter 'clear' to clear the screen and 'exit' to exit.\n"); print("Note: 'clear' may not work on ide terminals or some old terminals.\n"); } else if (fromArgs) { initScanner(scanner, argv[1]); REPL(scanner); return 0; } while (true) { // read print(">> "); fgets(input, sizeof(input), stdin); // check for a newline to skip lexing if (input[0] == '\n' || input[0] == '\0') continue; // check for clear if (strcompr(input, "clear\n")) { // print the "magic" ASCII sequece print("\033[H\033[2J"); continue; } else if (strcompr(input, "exit\n")) { // check for exit break; // exit the loop } initScanner(scanner, input); REPL(scanner); } // get the memory back free(scanner); return 0; }

Compiling Program...

Command line arguments:
Standard Input: Interactive Console Text
×

                

                

Program is not being debugged. Click "Debug" button to start program in debug mode.

#FunctionFile:Line
VariableValue
RegisterValue
ExpressionValue