Nomadic People Migration

    JSCPP

    2.0.9 • Public • Published

    JSCPP

    This is a simple C++ interpreter written in JavaScript.

    Try it out on github.io!

    Travis Build Status npm version Dependency Status devDependency Status

    Purpose of the project

    As far as I know, every public online C++ excuting environment requires backend servers to compile and run the produced executable. A portable and lightweight interpreter that can be run in browsers can be a fine substitute for those who do not intend to pay for such services.

    I also want to make a strict interpreter. The reason being C++ has too many undefined and platform-dependent behaviors and popular C++ compilers tend to be an "over-caring mother" who tries to ignore or even justify the undocumented usages. The abuse of them should be avoided as much as possible IMO. For example, I do not want my students to take it as guaranteed that sizeof int produces 4, because on Arduino Uno, an int is a 2-byte value.

    Currently, it is mainly for educational uses for a MOOC course I am running (and fun).

    Prerequisites

    • NodeJS version >= 0.11
    • A modern browser

    How to use

    Installation

    npm install JSCPP
    

    or (to use lastest cutting-edge version or to contribute)

    git clone https://github.com/felixhao28/JSCPP.git
    cd JSCPP
    npm install .
    

    Or you can download the minified single JS file directly from here:

    https://raw.githubusercontent.com/felixhao28/JSCPP/gh-pages/dist/JSCPP.es5.min.js

    With NodeJS

    var JSCPP = require("JSCPP");
    var code =    "#include <iostream>"
                + "using namespace std;"
                + "int main() {"
                + "    int a;"
                + "    cin >> a;"
                + "    cout << a << endl;"
                + "    return 0;"
                + "}"
    ;
    var input = "4321";
    var exitcode = JSCPP.run(code, input);
    console.info("program exited with code " + exitcode);

    See demo/example.coffee for example.

    Use debugger

    As of 2.0.0, there is a simple but functional real debugger available.

    A list of debugger API:

    • methods
      • debugger.next(): one step further
      • debugger.continue(): continue until breakpoint
      • debugger.nextNode(): the AST node to be executed
        • sLine
        • sColumn
        • sOffset
        • eLine
        • eColumn
        • eOffset
      • debugger.nextLine()
      • debugger.type(typeName)
      • debugger.variable()
      • debugger.variable(variableName)
    • properties
      • src: preprocessed source
      • prevNode: previous AST node
      • done
      • conditions
      • stopConditions
      • rt: the internal runtime instance
      • gen: the internal generator
    var JSCPP = require("JSCPP")
    var mydebugger = JSCPP.run(code, input);
    // continue to the next interpreting operation
    var done = mydebugger.next();
    // if you have an active breakpoint condition, you can just continue
    var done = mydebugger.continue();
    // by default, debugger pauses at every new line, but you can change it
    mydebugger.setStopConditions({
        isStatement: true
        positionChanged: true
        lineChanged: false
    });
    // so that debugger only stops at a statement of a new position
    // or you can add your own condition, i.e. stops at line 10
    mydebugger.setCondition("line10", function (prevNode, nextNode) {
    	if (nextNode.sLine === 10) {
    		// disable itself so that it only triggers once on line 10
    		mydebugger.disableCondition("line10");
    		return true;
    	} else {
    		return false;
    	}
    });
    // then enable it
    mydebugger.enableCondition("line10");
    // we need to explicitly use "false" because exit code can be 0
    if (done !== false) {
    	console.log("program exited with code " + done.v);
    }
    // the AST node to be executed next
    var s = mydebugger.nextNode();
    // sometimes a breakpoint can be set without a statement to be executed next,
    // i.e. entering a function call.
    while ((s = mydebugger.nextNode()) == null) {
    	mydebugger.next();
    }
    // the content of the statement to be executed next
    var nextLine = mydebugger.nextLine();
    // it is essentially same as
    nextLine = mydebugger.getSource().slice(s.sOffset, s.eOffset).trim()
    
    console.log("from " + s.sLine + ":" + s.sColumn + "(" + s.sOffset + ")");
    console.log("to " + s.eLine + ":" + s.eColumn + "(" + s.eOffset + ")");
    console.log("==> " + nextLine);
    // examine the internal registry for a type
    mydebugger.type("int");
    // examine the value of variable "a"
    mydebugger.variable("a");
    // or list all local variables
    mydebugger.variable();

    A full interactive example is available in demo/debug.coffee. Use node -harmony demo/debug A+B -debug to debug "A+B" test.

    With a browser

    There should be a newest version of JSCPP.js or JSCPP.es5.js in dist ready for you. If not, use npm run build to generate one.

    Then you can add it to your html. The exported global name for this package is "JSCPP".

    <script src="JSCPP.es5.min.js"></script>
    <script type="text/javascript">
    	var code = 	"#include <iostream>"+
    				"using namespace std;"+
    				"int main() {"+
    				"    int a;"+
    				"    cin >> a;"+
    				"    cout << a << endl;"+
    				"    return 0;"+
    				"}"
    	;
    	var input = "4321";
    	var output = "";
    	var config = {
    		stdio: {
    			write: function(s) {
    				output += s;
    			}
    		},
    		unsigned_overflow: "error" // can be "error"(default), "warn" or "ignore"
    	};
    	var exitCode = JSCPP.run(code, input, config);
    	alert(output + "\nprogram exited with code " + exitCode);
    </script>

    If you do not provide a customized write method for stdio configuration, console output will not be correctly shown. See demo/demo.html for example.

    Running in WebWorker

    There are two Helper classes to make JSCPP easier to run in WebWorkers. One is JSCPP.WebWorkerHelper in an old callback style and JSCPP.AsyncWebWorkerHelper in a modern Promise/async-await style.

    <script src="JSCPP.es5.min.js"></script>
    <script type="text/javascript">
    	var helper = new JSCPP.WebWorkerHelper("./JSCPP.es5.min.js"); // it is a class
    	var output = "";
    	helper.run(`#include <iostream>
    		using namespace std;
    		int main() {
    		int a;
    		cin >> a;
    		a += 7;
    		cout << a*10 << endl;
    		return 0;
    	}`, "5", {
    		stdio: {
    			write: function(s) {
    				output += s;
    			}
    		}
    	}, function (err, returnCode) {
    		if (err) {
    			alert("An error occurred: " + (err.message || err));
    		} else {
    			alert("Program exited with code " + returnCode);
    		}
    	});
    
    	helper.worker.terminate(); // directly control the Worker instance
    </script>
    <script src="JSCPP.es5.min.js"></script>
    <script type="text/javascript">
    	async function asyncWrapper() {
    		var helper = new JSCPP.AsyncWebWorkerHelper("./JSCPP.es5.min.js"); // it is a class
    		var output = "";
    		try {
    			var returnCode = await helper.run(`#include <iostream>
    				using namespace std;
    				int main() {
    				int a;
    				cin >> a;
    				a += 7;
    				cout << a*10 << endl;
    				return 0;
    			}`, "5", {
    				stdio: {
    					write: function(s) {
    						output += s;
    					}
    				}
    			});
    			alert("Program exited with code " + returnCode);
    		} catch (err) {
    			alert("An error occurred: " + (err.message || err));
    		}
    		helper.worker.terminate(); // directly control the Worker instance
    	}
    	asyncWrapper();
    </script>

    The helper classes are implemented in src/index.js, and a test page is available in dist/index.html.

    Run tests

    npm run test
    

    Q&A

    Which features are implemented?

    • (Most) operators
    • Primitive types
    • Variables
    • Arrays
      • Multidimensional array with initializers.
    • Pointers
    • If...else control flow
    • Switch...case control flow
      • Declarations inside switch block.
    • For loop
    • While loop
    • Do...while loop
    • Functions
    • Variable scopes
    • Preprocessor directives
      • Macro
      • Include

    Which notable features are not implemented yet?

    • Goto statements
    • Object-oriented features
    • Namespaces
    • Multiple files support

    How is the performance?

    If you want to run C++ programs effciently, compile your C++ code to LLVM-bitcode and then use Emscripten.

    Which libraries are supported?

    See current progress in includes folder.

    • iostream (only cin and cout and endl)
    • cmath
    • cctype
    • cstring
    • cstdio (partial)
    • cstdlib (partial)

    Bug report? Feedback?

    Post it on Issues.

    Changelog

    • v2.0.9 (2021.1.27)

      • New
        • WebWorker support (check dist/index.html for examples).
      • Fix
        • Fixed an error message
    • v2.0.7

      • New
        • Support some basic class usages (see test\class_basics.cpp).
        • Uses special uninitialized numeric and poitner value.
        • Adds an "unsigned_overflow" option to treat unsigned numeric overflow as "error"(default), "warn" or "ignore". Overflow on signed types will always throw an error.
      • Fix
        • Fixed some string-related methods.
        • Fixed pow in <cmath>, thanks to Clemenard.
        • Fixed multi-dimensional array declaration with initializers, thanks to rodrigorgs.
    • v2.0.6 (9.29)

      • New
        • Implemented following methods from cstdlib, thanks to victorrseloy:
          • int getchar(void)
          • char *gets(char *str)
          • int putchar(int char)
          • int puts(const char *str)
          • int scanf(const char *format, ...)
          • int sscanf(const char *str, const char *format, ...)
      • Fix
        • Fixed printf function
      • Dev
        • Update dependencies to latest
    • v2.0.5 (4.6)

      • New
        • ctime library
      • Fix
        • Supports functions returning pointer type
    • v2.0.4 (12.10)

      • New
        • Function default arguments support
      • Fix
        • cin.get now works as expected
      • Dev
        • Update dev dependencies
    • v2.0.3 (10.15)

      • New
        • Function pointer support
        • typedef support
      • Dev
        • Testing now uses test/test.coffee directly
        • Update PEG.js from 0.8.0 to 0.9.0
        • Please use NodeJS v4.0.0+
    • v2.0.2 (7.31)

      • New
        • Wide char support (русский язык)
      • Fix
        • Truncating negative number to positive
        • Error message when overflow
        • Error when using function prototypes
      • Dev
        • test.json -> test.yaml
        • Transpile to es5 properly (dist/JSCPP.es5.js)
        • Minified version (dist/JSCPP.es5.min.js)
        • Online site uses minified es5 version now
        • A few dependencies have been updated
        • Added linux helper for running and debugging (bin/run & bin/debug)
    • v2.0.1 (6.24)

      • Fix
        • Debugger variable scope issue
        • Readme example
        • An issue on Chrome Canary
        • Integer type promotion issue
        • Many small fixes
    • v2.0.0 (4.11)

      • New
        • Real debugger!
      • Change
        • API: Now JSCPP.run is all you need
        • Runtime: The project uses es6, please use V8 with harmony flag
        • Deprecated: Removed old legacy profiling-replay debugging
        • Misc: Many other small changes
      • Dev
        • Major refactoring on interpreter using es6
    • v1.1.1 (4.3)

      • Split debugger from example
      • (dev-side) Grunt only watches newer
      • Fix debug prev command
    • v1.1.0 (4.2)

      • Fixed array initialization with 0 issue
      • Added support for reading string with cin
      • Member function should not be registered globally
      • Added new tests
      • Basic debugging support
    • v1.0.3 (4.1)

      • (dev-side) Fix dev-dependency on coffee-script.
      • (dev-side) Grunt watches.
      • (dev-side) Port to coffeescript
      • (dev-side) Refactoring
      • (dev-side) Reworked testing, now all tests are defined in test.json
      • Fixed a bug related to a.push(b).concat(c) in syntax parser (#1).
      • Added new tests
    • v1.0.2 (3.31)

      • New examples.
      • Update README.
      • Renamed runtime and interpreter to start with upper case.
      • (dev-side) Grunt.
    • v1.0.1 (3.31)

      • This release is a mistake.
    • v1.0.0 (2015.3.31)

      • Formal release of this project.

    Install

    npm i JSCPP

    DownloadsWeekly Downloads

    1,734

    Version

    2.0.9

    License

    MIT

    Unpacked Size

    20.7 MB

    Total Files

    96

    Last publish

    Collaborators

    • felixhao28