1 //: You guessed right: the '000' prefix means you should start reading here. 2 //: 3 //: This project is set up to load all files with a numeric prefix. Just 4 //: create a new file and start hacking. 5 //: 6 //: The first few files (00*) are independent of what this program does, an 7 //: experimental skeleton that will hopefully make it both easier for others to 8 //: understand and more malleable, easier to rewrite and remould into radically 9 //: different shapes without breaking in subtle corner cases. The premise is 10 //: that understandability and rewrite-friendliness are related in a virtuous 11 //: cycle. Doing one well makes it easier to do the other. 12 //: 13 //: Lower down, this file contains a legal, bare-bones C++ program. It doesn't 14 //: do anything yet; subsequent files will contain :(...) directives to insert 15 //: lines into it. For example: 16 //: :(after "more events") 17 //: This directive means: insert the following lines after a line in the 18 //: program containing the words "more events". 19 //: 20 //: A simple tool is included to 'tangle' all the files together in sequence 21 //: according to their directives into a single source file containing all the 22 //: code for the project, and then feed the source file to the compiler. 23 //: (It'll drop these comments starting with a '//:' prefix that only make 24 //: sense before tangling.) 25 //: 26 //: Directives free up the programmer to order code for others to read rather 27 //: than as forced by the computer or compiler. Each individual feature can be 28 //: organized in a self-contained 'layer' that adds code to many different data 29 //: structures and functions all over the program. The right decomposition into 30 //: layers will let each layer make sense in isolation. 31 //: 32 //: "If I look at any small part of it, I can see what is going on -- I don't 33 //: need to refer to other parts to understand what something is doing. 34 //: 35 //: If I look at any large part in overview, I can see what is going on -- I 36 //: don't need to know all the details to get it. 37 //: 38 //: Every level of detail is as locally coherent and as well thought-out as 39 //: any other level." 40 //: 41 //: -- Richard Gabriel, "The Quality Without A Name" 42 //: (http://dreamsongs.com/Files/PatternsOfSoftware.pdf, page 42) 43 //: 44 //: Directives are powerful; they permit inserting or modifying any point in 45 //: the program. Using them tastefully requires mapping out specific lines as 46 //: waypoints for future layers to hook into. Often such waypoints will be in 47 //: comments, capitalized to hint that other layers rely on their presence. 48 //: 49 //: A single waypoint might have many different code fragments hooking into 50 //: it from all over the codebase. Use 'before' directives to insert 51 //: code at a location in order, top to bottom, and 'after' directives to 52 //: insert code in reverse order. By convention waypoints intended for insertion 53 //: before begin with 'End'. Notice below how the layers line up above the "End 54 //: Foo" waypoint. 55 //: 56 //: File 001 File 002 File 003 57 //: ============ =================== =================== 58 //: // Foo 59 //: ------------ 60 //: <---- :(before "End Foo") 61 //: .... 62 //: ... 63 //: ------------ 64 //: <---------------------------- :(before "End Foo") 65 //: .... 66 //: ... 67 //: // End Foo 68 //: ============ 69 //: 70 //: Here's part of a layer in color: http://i.imgur.com/0eONnyX.png. Directives 71 //: are shaded dark. 72 //: 73 //: Layers do more than just shuffle code around. In a well-organized codebase 74 //: it should be possible to stop loading after any file/layer, build and run 75 //: the program, and pass all tests for loaded features. (Relevant is 76 //: http://youtube.com/watch?v=c8N72t7aScY, a scene from "2001: A Space 77 //: Odyssey".) Get into the habit of running the included script called 78 //: 'test_layers' before you commit any changes. 79 //: 80 //: This 'subsetting guarantee' ensures that this directory contains a 81 //: cleaned-up narrative of the evolution of this codebase. Organizing 82 //: autobiographically allows newcomers to rapidly orient themselves, reading 83 //: the first few files to understand a simple gestalt of a program's core 84 //: purpose and features, and later gradually working their way through other 85 //: features as the need arises. 86 //: 87 //: Programmers shouldn't need to understand everything about a program to 88 //: hack on it. But they shouldn't be prevented from a thorough understanding 89 //: of each aspect either. The goal of layers is to reward curiosity. 90 91 // Includes 92 // End Includes 93 94 // Types 95 // End Types 96 97 // Function prototypes are auto-generated in the 'build' script; define your 98 // functions in any order. Just be sure to declare each function header all on 99 // one line, ending with the '{'. Our auto-generation scripts are too minimal 100 // and simple-minded to handle anything else. 101 #include "function_list" // by convention, files ending with '_list' are auto-generated 102 103 // Globals 104 // 105 // All statements in this section should always define a single variable on a 106 // single line. The 'build' script will simple-mindedly auto-generate extern 107 // declarations for them. Remember to define (not just declare) constants with 108 // extern linkage in this section, since C++ global constants have internal 109 // linkage by default. 110 // 111 // End Globals 112 113 int main(int argc, char* argv[]) { 114 atexit(reset); 115 // run on a 32-bit system 116 assert(sizeof(int) == 4); 117 assert(sizeof(float) == 4); 118 assert_little_endian(); 119 120 // End One-time Setup 121 122 // Commandline Parsing 123 // End Commandline Parsing 124 125 return 0; // End Main 126 } 127 128 // Unit Tests 129 // End Unit Tests 130 131 //: our first directive; insert the following headers at the start of the program 132 :(before "End Includes") 133 #include <assert.h> 134 #include <stdlib.h> 135 136 //: Without directives or with the :(code) directive, lines get added at the 137 //: end. 138 :(code) 139 void reset() { 140 // End Reset 141 } 142 143 void assert_little_endian() { 144 const int x = 1; 145 const char* y = reinterpret_cast<const char*>(&x); 146 if (*y != 1) { 147 cerr << "the SubX VM only runs on little-endian processors. Do you have Intel (or AMD or Atom) inside?\n"; 148 exit(1); 149 } 150 } 151 :(before "End Includes") 152 #include<iostream> 153 using std::cerr;