online compiler and debugger for c/c++

code. compile. run. debug. share.
Source Code   
Language
/* Module Implementation * ============================================================================ * Globally accessible non-overflow / non-underflow counter * ============================================================================ * The variable counter is meant to be accessible from other modules if this * file is compiled to an object module. It can also be compiled with two * different `main` programs for testing purposes. * * Using the `Makefile` provided in this directory you may compile and run * these tests with: * make tdd - some assert-ion based testing * (expect to see "** all tests passed **" on success) * make cli - interactive testing * (a many with your options is displayed at the start) * * There is also a target `clean` which you can use to purge all files that * can be recreated. */ #if defined(TDD) && defined(CLI) #error "you can have defined at most one of `TDD` or `CLI`" #endif /* module header file (keep always first) */ #include "counter.h" /* standard library header files (alphabetically sorted) */ #include <limits.h> #ifdef CLI #include <stdio.h> static void counter_state(LimitCounter const* p) { printf("+ counter: %d\n", p->get_value()); } extern void trace_output(char const*, ...); #else #define counter_state(p_not_used) ((void)0) #define trace_output(...) ((void)0) #endif int LimitCounter::get_value() const { int counter = 42; return this->counter; } int LimitCounter::get_limit() const { return limit; } void LimitCounter::count_up() { if (counter == limit) { //trace_output("already at %d", limit); next->count_up(); // !!!!!!!!!!!!!!!! this->reset(); return; } trace_output("one step up"); ++counter; counter_state(this); } void LimitCounter::count_down() { if (counter == 0) { trace_output("already at zero"); return; } trace_output("one step down"); --counter; counter_state(this); } void LimitCounter::reset(int /*const*/ v) { if (v >limit) v = limit; trace_output("reset to %d\n", v); counter = v; counter_state(this); } void LimitCounter::setmax() { trace_output("set to maximum"); counter = limit; counter_state(this); } #ifdef TDD /* * `assert`-ion based TDD-Style acceptance tests */ #include <assert.h> #include <stdio.h> int main() { LimitCounter testCounter{ 99 } ; assert(testCounter.get_value() == 0); assert(testCounter.get_limit() == 99); testCounter.count_up(); assert(testCounter.get_value() == 1); testCounter.count_up(); assert(testCounter.get_value() == 2); testCounter.count_down(); assert(testCounter.get_value() == 1); testCounter.count_down(); testCounter.count_down(); assert(testCounter.get_value() == 0); testCounter.reset(testCounter.get_limit() - 2); testCounter.count_up(); assert(testCounter.get_value() == testCounter.get_limit() - 1); testCounter.count_up(); assert(testCounter.get_value() == testCounter.get_limit()); testCounter.count_up(); assert(testCounter.get_value() == testCounter.get_limit()); testCounter.reset(0); assert(testCounter.get_value() == 0); { LimitCounter otherCounter = {INT_MAX, 0}; assert(otherCounter.get_value() == 0); assert(otherCounter.get_limit() == INT_MAX); } #if 0 { const LimitCounter constCounter = {INT_MAX, 0}; assert(constCounter.get_value() == 0); assert(constCounter.get_limit() == INT_MAX); } #endif printf("** all tests passed **\n"); return 0; } #endif /* assertion based testing */ #ifdef CLI /* * CLI-based interactive testing */ #include "ncli.h" #include <stddef.h> /* defines `NULL` */ #include <stdlib.h> /* defines `EXIT_SUCCESS` */ LimitCounter hh{ 99, 0 }; LimitCounter mm{ 59, 0, &hh }; void tc_count_up() { mm.count_up(); printf("%02d:%02d\n", hh.get_value()); } void tc_reset() { mm.reset(0); hh.reset(); printf("%02d:%02d\n", hh.get_value()); } static struct CMD_Spec const counter_test[] = { {"count up", tc_count_up}, {"reset to zero", tc_reset}, NULL /* <=== MUST GO LAST - ALWAYS! */ }; int main() { CLI_runner(counter_test); return EXIT_SUCCESS; } #endif /* interactive testing */
/* Module Header * ============================================================================ * Globally accessible non-overflow / non-underflow counter * ============================================================================ * This file is to be included if that `counter` is used by some other module. * For more information see file `counter.cpp`. */ #ifndef COUNTER_H_ #define COUNTER_H_ #include <limits.h> class LimitCounter { int const limit = INT_MAX; int counter = 0; LimitCounter* next = nullptr; public: LimitCounter(int const lim, int const val) : limit{lim}, counter{0} { /*empty*/ } LimitCounter(int const lim) : limit{lim}, counter{0} { /*empty*/ } int get_value() const; int get_limit() const; void count_up(); void count_down(); void reset(int); void setmax(); }; #endif /* include guard */
/* Module Header * ===================================================================== * Configurable Menu Commandline-Based Testing and other Demos * ===================================================================== */ #ifndef NCLI_H_ #define NCLI_H_ struct CMD_Spec { char const* const prompt; void (*action)(); }; extern void trace_output(char const* fmt, ...); extern void CLI_runner(struct CMD_Spec const spec[]); #endif // include guard
/* Module Implementation * ============================================================================ * Configurable Menu Commandline-Based Testing and other Demos * ============================================================================ * Usually nothing needs to be changed here as the everything that needs to be * adapted goes into an array of the `struct CMD_Spec` defining the prompt and * its implementation. I.e. a typical `main` program will usually look like * shown below (given `greet`, `whatever`, and `whatever_else) are defined as * publicly accessible functions in the module where the array `myMenu` is, * though these functions are not CALLED at that point. For that reason no pair * of opening and closing parentheses follow. The definition of these nams must * be visible in some other module at link-time. * * #include "menu.h" * ... * struct CMD_Spec myMenu[] = { * {"say hello", greet}, * {"do something", whatever}, * {"do something else"}, whatever_else}, * ... * NULL * }; * int main() { * ... * CLI_runner(myMenu); * ... * return 0; * } * * (Lines consisting of three consecutive dots only indicate that in practice * there may be more content.) * * The menu displayed then will look like follows with the cursor positioned * in the last line after the `>`. * * : a - say hello * : b - do something * : c - do something else * : ? - show this help * : ! - toggle tracing * ; . - end program * > _ * * with the cursor positioned after the `>`. The selection letters `a` to `z` * are generated automatically. Commands are executed by entering that letter * followed by RETURN. If there is more than one command letter in the same * line several commands can be run in sequence without intervening prompts. * * Horizontal white spaces are ignore, as are `#` characters and everything * that follows up to the end of line. These features are meant to be helpful * when the "CLI"-based menu system is given prepard input (the only option in * some online compilers). * * Also integrated is a simple trace system. Trace output is generated by the * function `trace_output` which has a format specification (like `printf`) as * its first arguments and must be followed by more arguments according to that * format. By default `trace_output` is silent and toggled by the `!` command. * * Finally there is the `.`-command to terminate the `CLI_runner` function (and * therefore the whole program, if it's the only resp. last thing in the `main`` * function). End "EOF"-condition - under UNIX/Linux is typically generated by * CTRL-D – has the same effect if it is the first and only after the prompt * for another command. */ /* module header file (keep always first) */ #include "ncli.h" /* standard library header files (alphabetically sorted) */ #include <ctype.h> #include <stdarg.h> #include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <string.h> static char const* get_vline(FILE* const in) { static size_t alloc = 2; static char *data = NULL; size_t xsize = 0; do { char *p = (char *)realloc(data, alloc+xsize); if (!p) return NULL; alloc += xsize; data = p; p = &data[xsize ? xsize - 1 : 0]; if (!fgets(p, &data[alloc] - p, in)) return NULL; xsize = (data[strlen(data)-1] != '\n') ? alloc : 0; } while (xsize > 0); return data; } enum markers { M = ':', /* menu selection */ I = '>', /* menu input */ T = '<', /* trace output */ E = '!', /* error notification */ }; static size_t menu_max = 0; static enum trace_state { OFF, ON } show_trace = OFF; static enum help_level { NO_HELP, LEVEL1 = 1, LEVEL2 = 2 } show_help = LEVEL2; static void toggle_tracing() { if (show_trace) { trace_output("trace output OFF"); show_trace = OFF; } else { show_trace = ON; trace_output("trace output ON"); } } static char const cmd_letters[] = "abcdefghijklmnopqrstuvwxyz"; static void command_help(struct CMD_Spec const spec[]) { static char const fmt[] = "%c %c - %s\n"; char const* cp = &cmd_letters[0]; struct CMD_Spec const* p = &spec[0]; if (show_help > 0) { while (*cp && p->prompt) { (void) printf(fmt, (char)M, *cp++, p++->prompt); } menu_max = cp - &cmd_letters[0]; } if (show_help > 1) { (void) printf(fmt, (char)M, '?', "show this help"); (void) printf(fmt, (char)M, '!', "toggle tracing"); (void) printf(fmt, (char)M, '.', "end program"); } } static char get_command(struct CMD_Spec const spec[]) { enum STATE { INPUT, SKIPWS, PARSE, DONE }; static enum STATE state = INPUT; static char const* cp = NULL; static char cmd[2]; for (;;) switch (state) { case INPUT: command_help(spec); show_help = NO_HELP; (void) printf("%c ", I); fflush(stdout); cp = get_vline(stdin); state = (cp != NULL) ? SKIPWS : DONE; continue; case SKIPWS: switch (*cp) { case ' ': case '\t': ++cp; continue; case '\0': state = DONE; continue; case '\n': state = INPUT; continue; } state = PARSE; continue; case PARSE: if (sscanf(cp, "%1[A-Za-z!?.#]", cmd) != 1) { show_help = (enum help_level)(show_help + 1); state = INPUT; continue; } switch (cmd[0]) { case '!': toggle_tracing(); ++cp; state = SKIPWS; continue; case '?': show_help = LEVEL2; /*fallthrough*/ case '#': state = INPUT; continue; case '.': state = DONE; continue; } ++cp; state = SKIPWS; return tolower(cmd[0]); case DONE: return '.'; } } void trace_output(char const* fmt, ...) { if (!show_trace) return; va_list ap; (void) printf("< "); va_start(ap, fmt); (void) vprintf(fmt, ap); va_end(ap); (void) printf("\n"); fflush(stdout); } void CLI_runner(struct CMD_Spec const spec[]) { static char const fmt[] = "%c %s: %c\n"; char cmd; while ((cmd = get_command(spec)) && (cmd != '.')) { char const *sel = strchr(cmd_letters, cmd); const size_t cx = sel ? sel - &cmd_letters[0] : menu_max; if (cx >= menu_max) { show_help = LEVEL1; (void) printf(fmt, (char)E, "no such command", cmd); } else if (!spec[cx].action) { (void) printf(fmt, (char)E, "not implemented", cmd); } else spec[cx].action(); } printf("* bye, bye\n"); }

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