felixhao28 / jscpp Goto Github PK
View Code? Open in Web Editor NEWA simple C++ interpreter written in JavaScript
Home Page: https://felixhao28.github.io/JSCPP/
License: MIT License
A simple C++ interpreter written in JavaScript
Home Page: https://felixhao28.github.io/JSCPP/
License: MIT License
I tried the following and it works, but m should not be in scope
#include
using namespace std;
int g=1;
int main() {
int m = 2;
cout << "scope test" << endl;
func1();
return 0;
}
void func1(){
int f1 = 10;
cout << g << endl;
cout << f1 << endl;
cout << m << endl; //should not be in scope but is?
}
Rather than an input box and output box can we make a cli?
I would like to ask if there could be published a single file/minified version of this lib with every update, because i'm trying to use it on the web, and installing/finding a way to unify the whole lib into a single file, using node, always causes problems to me, for some reason.
That if the online demo doesn't already use the last version avaliable(Could someone inform me about that?). In that case, I might just use it.
I refactored code from ES5 JS to CoffeeScript a while ago because at that time ES6 is not that popular and without babel and eslint supporting ES6, CoffeeScript was much more appealing.
Now that ES6 JS is on par (actually surpassing) with CoffeeScript in terms of readability, maintanability and popularity. I think it is time to switch back to JS.
It is also a good opportunity to review and refactor the legacy code.
Update in 2020: Now Typescript is better than ES6 JS.
Here is my correction
rt.regFunc ((rt, _this, x, y) ->
rt.val(tDouble,x.v ** y.v)
), g, "pow", [ tDouble,tDouble ], tDouble
Consider the following code:
int main() {
int matrix[2][2] = {{1, 2}, {3, 4}};
return 0;
}
I should init the matrix with the values 1, 2, 3, and 4; however, the following error is issued: 2:5 dimensions do not agree, 2 != 2
Hi Felix
been busy with other work, back to testing some code and found something not quite right with bit inversion,
noticed it first with this
unsigned char A=0;
unsigned char B=0x80;
int main() {
A = ~B;
return 0;
}
returns: TypeError: type is undefined (also the error doesn't show a line number)
also this
unsigned int A=0;
unsigned int B=0x0080; //also B=0x80 or B=128;
int main() {
A = ~B;
return 0;
}
returns: 4:5 cannot cast negative value to unsigned int
in defaults.coffee line 308 ...
ret = ~l.v
appears to invert everything using signed 64bit(?) int and therefore always thinks its a negative number
Also will you support binary literals 0b01010111 ?
thanks
Bill
I'm looking for a C/C++ compiler written in Javascript capable of generate Linux x86 .so files, something similar to LLVM.js + clangor and ccjs (unluckily all of them abandoned :-( ). My intention is to generate Node.js compiled modules from inside NodeOS. Do you think JsCpp is capable of doing this, or do you know of any other alternative?
I am wondering if this would be safe to run user-provided code. Excluding denial-of-service attacks e.g. while(1){}
it doesn't look like network requests could be made so I'm wondering if this would serve as a safe "sandbox" for running C++ based code.
Felix, not sure if this should flag an error or not.
#include
using namespace std;
int main() {
unsigned char a = 23;
a << 4;
return a;
}
returns 5:5 overflow of 368(unsigned char)
I am using this as a C simulator, where I would expect it to just do the shift and loose the bits and not create an error.
I guess I could modify CRuntime::val in rt.coffee to change this behaviour
thanks
The JSCPP distribution has exactly one error when being loaded into a WebWorker via importScripts()
. That error has to do with the way window.JSCPP
is assigned in index.js. WebWorkers don't have access to the window object. I was able to fix it in the context of my project by doing the following replacement.
Before:
window.JSCPP = require('./launcher').default;
After:
var JSCPP = require('./launcher').default;
This completely fixes the issue and I'm able to run C++ via a worker. However, I am not familiar enough with NodeJS to determine whether this is a reasonable solution. Just wanted to bring this to your attention.
Thank you for this project, it has been extremely helpful so far.
To use your wonderful library in production (yes, we are going to!), we should use minified files. Of course, we can minify any file ourself, but the fact that uglify task is mentioned in Gruntfile.js but not used is quite strange.
Is it possible not to execute C++ code but only translate it to JS, which could be written to a file and then executed?
I am working with JSCPP within browser. The demo has a debug.js
. Not sure how to use it.
I visited https://felixhao28.github.io/JSCPP/ and try to input the code as:
#include <iostream>
#include <string.h>
using namespace std;
int main () {
char str1[10] = "111";
char str2[10] = "222";
char str3[10];
// concatenates str1 and str2
strcat( str1, str2);
cout << "strcat( str1, str2): " << str1 << endl;
return 0;
}
However, it's error as:
"TypeError: Cannot read property 'type' of undefined"
It seems to me that there is an error with uninitialized arrays. Elements should not be initialized to 0 as is currently the case seems to me.
For example :
#include <stdio.h>
int main() {
float tab[2];
for(int i = 0; i < 2; i++){
printf("%f, ", tab[i]);
}
return 0;
}
gives 0.00000, 0.00000 instead of NaN, NaN.
The C99 standard says that "if an object that has an automatic storage duration is not explicitly initialized, its value is undetermined." I think it's the same in C++ (or not ?).
Hi you have a wonderful piece of code here. Just fantastic,Where do you teach?
Anyway,
I noticed that the scope of debugger.variable() only returns variables within the current scope e.g. in this code
#include <iostream>
int main() {
int addtome;
cin >> addtome;
for (int index=0; index<3; index++)
{
addtome+=index;
}
cout<< addme << endl;
return 0;
}
addtome does not show until it has exited the for loop.
I will have a look at 'Debugger.prototype.variable' myself to see if I can change it.
I would like to be able to return a list of the scopes and the vars in each scope as well.
3 years ago I wrote C and BASIC interpreters in C# as part of a visualizer for ATMEL microcontrollers and am now porting it to the web using javascript. I am a newbie with Javascript and was building a peg for C using pegjs and ACE and was looking for information on Generators and Yield and found your code. It's so much better than the recursive parser I wrote in C#! I think I will stop my own port! Now I just need to get my head around nodejs, exports, require, react, coffee, generators....
I would like to make small chunks of my JS code faster (short functions, which perform heavy computation). I was thinking about writing them in WebAssembly manually, but writing them in C would be much more comfortable.
Would you like to extend your tool, so it can compile the C code into WebAssembly? I don't want to make a mess in my computer by installing heavy native compilers, just to translate several lines of C code into WebAssembly.
I was wondering if we could provide better display values, after having a look on the code I think there could be done with small adjustments.
grunt test output includes this:
AssertionError: false == true
+ expected - actual
-false
+true
at Context.<anonymous> (test/test.js:109:14)
AssertionError: expected '' to equal '1.234\n1234\n1234\n1234\n2\n1\n1234\n2\n1'
+ expected - actual
+1.234
+1234
+1234
+1234
+2
+1
+1234
+2
+1
at Context.<anonymous> (test/test.js:117:25)
in the following code if the while loop is empty the debugger goes into a loop and cannot be stopped,
I know its not really a big issue but students writing this in their code while learning will find it hangs their browser, if there is anything in the while loop it wont of course hang up
`#include
using namespace std;
int main() {
int a=0;
while(1){
}
}`
I get "Error: Cannot find module 'JSCPP'" after npm install JSCPP, and even at the NPM repo online https://npm.runkit.com/JSCPP am I doing something wrong?
Hi Felix
does typedef work correctly?
I get an error with
typedef unsigned int WORD;
thanks
Bill
as per CONTRIBUTE.md I'm creating this issue to let others know that I'm working on this.
The following functions from cstdio are uninplemented:
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, ...)
I'll implement them.
Hi,
On my mac os, after checking out and npm install, it shows the errors:
`Running "browserify:dist" (browserify) task
Error: Can't walk dependency graph: Cannot find module './ast' from '/Users/binchen/git/JSCPP/lib/launcher.js'
required by /Users/binchen/git/JSCPP/lib/launcher.js
Warning: Error running grunt-browserify. Use --force to continue.
Aborted due to warnings.
npm ERR! code ELIFECYCLE
npm ERR! errno 6
npm ERR! [email protected] prepublish: grunt build
npm ERR! Exit status 6
npm ERR!
npm ERR! Failed at the [email protected] prepublish script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! /Users/binchen/.npm/_logs/2020-10-20T00_39_14_925Z-debug.log
`
Can you take a look?
Thanks.
Hi Felix
I noticed today that globals were not being shown by debugger.variable
e.g.
//vars in scopes
int g=3;
int y=10;
int main()
{
int x = 2;
x = func(x);
x += y;
return x;
}
int func(int a)
{
int b =a;
b = a * a;
return b;
}
Debugging in firefox I realised that in debugger.prototype.variable
the line
for scopeIndex in [@rt.scope.length - 1...0] by -1
has three dots so I think it doesn't go down to the global scope '0'
I altered debugger.js
for (scopeIndex = i = ref = this.rt.scope.length - 1; i > 0; scopeIndex = i += -1) {
to
for (scopeIndex = i = ref = this.rt.scope.length - 1; i >= 0; scopeIndex = i += -1) {
changing this meant I also had to change the line in the JS
if (typeof val === "object" && "t" in val && "v" in val)
to
if (typeof val === "object" && "t" in val && 'name' in val.t && "v" in val)
you do of course have a fuller perspective on my alteration to the code and know its wider effects
cheers
Bill
As referred to from: viebel/klipse#300
Code that is invalid and should not compile is instead being executed and run up until the point in the source code that it fails.
The linked issue contains of note:
I was attempting to demonstrate C++ type errors that happen at compile time in a demonstration post using klipse, however the typing error seemed to happen at run-time instead of parsing/compilation time as prior lines of code were run and output information before the typing error was hit, which completely destroyed my argument for C++ that catching type errors at compile-time prior to run-time helped prevent classes of errors before the code is executed. ^.^;
Just go to any of the C++ fields at: http://blog.overminddl1.com/posts/programming-language-differences-compilation/
Then input:
#include <iostream> using namespace std; int main() { char *hw = "Hello World!"; cout << hw << endl; cout << 2 * hw << endl; return 0; }I'd expect it to just print out:
6:11 unsigned int does not support * on char[13]
Instead it prints:
Hello World! 6:11 unsigned int does not support * on char[13]
Very interesting project and good work.
It would be great if an pre-compiled "dist/JSCPP.js" version could be checked in into GitHub as well.
This makes the testing and integration with other project much easier, because the file could be simple include as library instead of compiling the hole project first.
Thanks and Greetings,
Hi Felix
In the code below there should be an overflow as the type used is a short, but it appears that the calculation is done as an int?
thanks
Bill
#include <iostream>
using namespace std;
#include <stdio.h>
unsigned short a = 900; //short is a 16bit type
unsigned char p =0;
int main() {
p = (a*100)/1000;
printf("a:%d\n",a);
printf("p:%d\n",p);
return 0;
}
Greetings from Russia, comrads!
Thanks a lot for your work, it seems to be very useful for partial replacing MS Visual Studio in studying (at least for basics). Unfortunately, our students are useful to make cyrillic annotations for output... which don't work. Here is MWE:
#include <iostream>
using namespace std;
int main() {
cout << "some cyrillic text: кириллический текст" << endl;
return 0;
}
It seems like I can't send non-ASCII characters to cout:
#include <iostream>
using namespace std;
int main() {
cout << "\u0080" << endl;
return 0;
}
TypeError: Cannot read property 'type' of undefined
Of course, this limitaion could be easily worked around with a kostyl like punycode, but it seems to be very unpleasant.
Text below is in Russian
Доброго времени суток, товарищи!
Текст выше - на английском. Спасибо за проделанную работу, либа годная, частично может заменить проклятую проприетарную MS Visual Studio для совсем уж первокурсников (хотя бы на время, пока они её крякают). И вообще, да здравствует импортозамещение!
Однако, незадача: кириллический текст запихнуть в cout не получается. Да вообще ничего, кроме ASCII, не получается. Примеры выше. Нет, конечно, мы, суровые русские программисты, ко всяким санкциям привычны, костылей-то напаяем (хоть punycode), но всё равно неприятно.
Is there a way to stop code that has infinite loops?
Maybe something like counting steps in https://github.com/NeilFraser/JS-Interpreter, so if the number of steps is exceeded an error can be shown instead of freezing the browser, or the execution limit in https://github.com/codecombat/esper.js which sets a limit # of execution nodes.
if you include cstdio and cstring on same cpp file you get an exception saying that some methods are already defined, this is happening because during the load of cstdio cstring is being implicit loaded by this line
rt.include "cstring"
I've already started working on a fix to this, bellow follows a test case to see the problem happening:
#include <stdio.h>
#include <string.h>
int main()
{
printf("test - ok");
return 0;
}
Hi,
I'm trying to create a custom class in ts
but I'm running into a couple of issues, this is one...
If I add a second method, by simply modifying dummy_class_foo.ts
like this:
rt.regFunc(_plusX, type, "plusX", [rt.intTypeLiteral], rt.intTypeLiteral);
rt.regFunc(_plusX, type, "plusX2", [rt.intTypeLiteral], rt.intTypeLiteral);
Using the class_basics
in an HTML file:
var code = "#include <iostream>"+
"#include <foo>"+
"using namespace std;"+
"int main() {"+
" Foo foo;"+
" cout << foo.x << ',' << foo.y << endl;"+
" cout << foo.plusX(5) << endl;"+
" cout << foo.plusX2(5) << endl;"+
" return 0;"+
"}";
I get this error:
[Error] TypeError: undefined is not an object (evaluating 't.v')
dispatchException (JSCPP.es5.min.js:1:334009)
(anonymous function) (JSCPP.es5.min.js:1:330361)
run (JSCPP.es5.min.js:1:220827)
Global Code (class.html:32)
Any help would be greatly appreciated. Thanks.
Hi Felix
I am beginning to look more deeply at your code and have begun integrating it into a javascript version of my microcontroller visualiser
I notice that the following does not work quite right,
int main()
{
unsigned char x = 126;
x++; //127
x++; //128
x++; //129
x++; //130
x=x+1; //result is unknown:unknown overflow of 128(signed char)
return 0;
}
// signed char does the same
I am very interested in 8 and 16 bit types as I would like to use this as the basis for a microcontroller simulator.
I see defaults.coffee handles the sizes of these, but in rt.coffee only 7bit char and 32bit ints appear to be used? I really do not understand your code so I am sorry i am not to be able to contribute to this very much at this stage.
thanks
Bill
this should do it ....
<AceEditor
onLoad={editorInstance => {
editorInstance.container.style.resize = "both";
// mouseup = css resize end
document.addEventListener("mouseup", e => (
editorInstance.resize()
));
}}
/>
here is a demo fiddle
我想用pegjs解析模板语法,比如 vecotr v; 改了一下文法文件但是 < 始终被识别为小于符号。可以大概提供下思路吗,谢谢🙏
please include this feature on the demo page, so we can link to demo code
sample implementation:
Main = React.createClass({
// ....
saveToUrl: function(e) {
if (e != null) {
e.preventDefault();
}
return setFragmentFromState(this.state);
},
loadFromUrl: function(e) {
if (e != null) {
e.preventDefault();
}
return this.setState(
getStateDiffFromFragment()
);
},
var parseQueryString = function(input) {
// similar to PHP $_GET[key]
// return array of values if key is repeated in query string
let queryObject = {};
const re = /([^?&=]+)(?:=([^&]+))?/g;
let match;
while (match = re.exec(input)) {
const [k, v] = [
decodeURIComponent(match[1]),
// empty value = true
(decodeURIComponent(match[2]) || true)
];
if (k in queryObject) {
if (Array.isArray(queryObject[k])) {
queryObject[k].push(v);
} else {
queryObject[k] = [queryObject[k], v];
}} else {
queryObject[k] = v;
}
}
return queryObject;
};
// keys shared between state and fragment query string
// key "code" is always shared
const fragmentKeys = ["input"];
var getStateDiffFromFragment = function() {
// fragment string format: key=val&key2=val2/codeString
// val, val2, ... must be encoded with encodeURIComponent
// codeString can be encoded with encodeURI
// which is more compact than encodeURIComponent
const idxCode = document.location.hash.indexOf("/");
const query = parseQueryString(
document.location.hash.substring(1, idxCode));
let stateDiff = Object.keys(query).reduce((acc, key) => {
if (fragmentKeys.includes(key)) {
acc[key] = query[key];
}
return acc;
}, {});
const code = decodeURI(document.location.hash.substring(idxCode + 1));
if (code) {
stateDiff.code = code;
}
return stateDiff;
};
var setFragmentFromState = function(state) {
document.location.hash = fragmentKeys.reduce((acc, key) => {
if (state[key]) {
acc.push(`${key}=${encodeURIComponent(state[key])}`)
}
return acc;
}, []).join("&") + "/" + encodeURI(state.code);
};
javascript says document.location.hash
, the official name is fragment identifier
limitation: old browsers limit URL length
license is creative-commons-zero, so feel free to steal my code
ps: can you make /gh-pages
public? (including jsx files)
It would be great if users (students) could save and load *.cpp via GH-pages shell.
As you've asked, I am submitting the issue that I'll try to implement the time
function from ctime
.
I'm going to try this because I don't know how to use srand
without time
.
Any less than trivial program stops (for me) at
function(a, b, c) {
return a.push(b).concat(c);
},
where a is an Array, which, at least if you didn't do any magic to Array, would have a.push(b) return a number (the new length of the array) and then try to run .concat(c) on that number, which does not work. Am I doing something wrong?
Way to reproduce: make a new C source with only;
extern const byte title[];
and execute. I use the latest master jscpp_page.js file from github.
In usual C++, srand() function is often used to really randomize rand() (or else rand() will return one random but fixed number - to help with debug).
In JSCPP, rand() returns different numbers each time. I don't know is it correct or not, but I'll be very glad if srand() function (maybe, empty?) will exist.
Thanks for this great little interpreter!
I'd like to allow instantiation of a class defined in javascript. Even though it isn't supported, I'm curious to know what would roughly be needed to achieve this. Easy or hard? Any steps I'd need to take?
A simple include defining the Foo class, would be (hope you're ok with ES6):
// foo.js
export function load(rt) {
const type = rt.newClass('Foo', []);
const Foo = {
t: type,
v: {
members: {},
},
};
rt.scope[0]['Foo'] = Foo;
rt.types[rt.getTypeSignature(Foo.t)] = {
'#father': 'object',
};
};
When instantiating an object with Foo myFoo
, I get the error No default value for object.
Changing this to Foo myFoo()
tells me value is undefined in CRuntime::cast
.
Would you be able to give any pointers?
Felix, have you / will you implemented function prototypes?
#include <iostream>
int func(int x);
int main() {
int a = 10;
int b = 0;
b = func(a);
return 0;
}
int func(int x){
//some code
return 2 * x;
}
tried this with the latest version of gh-pages
throws an error with function prototype both int func(int x); and int func(int);
error = 4:1 is interp really an array initialization?
thanks
Bill
#include <iostream>
int main() {
std::cout << "hello world" << std::endl;
return 0;
}
error info:
Error: ERROR: Parsing Failure:
line 4 (column 8): int main() {\n std::cout << "hello wor
----------------------------------------^
Expected "!=", "%", "%=", "&", "&&", "&=", "(", "*", "*=", "+", "++", "+=", ",", "-", "--", "-=", "->", ".", "/", "/*", "//", "/=", ";", "<", "<<", "<<=", "<=", "=", "==", ">", ">=", ">>", ">>=", "?", "[", "\\U", "\\u", "^", "^=", "__attribute__", "_stdcall", "auto", "const", "extern", "inline", "register", "static", "|", "|=", "||", [ \n\r\t\u000B\u000C], [0-9], [A-Z], [_] or [a-z] but ":" found.
HI,
I'm trying to create a method that accepts a string but can't get it to work.
I've tweaked dummy_class_foo.ts
like this:
/* eslint-disable no-shadow */
import {ArrayVariable, CRuntime, IntVariable, ObjectVariable, Variable} from "../rt";
export = {
load(rt: CRuntime) {
const type = rt.newClass("Foo", [{
name: "x",
type: rt.intTypeLiteral,
initialize(rt, _this) { return rt.val(rt.intTypeLiteral, 2, true); }
}, {
name: "y",
type: rt.intTypeLiteral,
initialize(rt, _this) { return rt.val(rt.intTypeLiteral, -2, true); }
}
]);
const typeSig = rt.getTypeSignature(type);
rt.types[typeSig].father = "object";
// *********** My modifications are from here down...
const pchar = rt.normalPointerType(rt.charTypeLiteral);
const _plusX = function (rt: CRuntime, _this: ObjectVariable, t: ArrayVariable) {
const newValue = 0;
// do something with `t`
return rt.val(rt.intTypeLiteral, newValue, false);
};
return rt.regFunc(_plusX, type, "plusX", [pchar], rt.intTypeLiteral);
}
};
The test code is:
var code = "#include <iostream>"+
"#include <foo>"+
"using namespace std;"+
"int main() {"+
" Foo foo;"+
" cout << foo.x << ',' << foo.y << endl;"+
' cout << foo.plusX("hello") << endl;'+
" return 0;"+
"}";
The error is:
[Error] Error: 1:99 no method plusX in [object Object] accepts char[6]
dispatchException (JSCPP.es5.min.js:1:334009)
(anonymous function) (JSCPP.es5.min.js:1:330361)
run (JSCPP.es5.min.js:1:220827)
Global Code (class.html:31)
Any help would be great, thanks.
This code works fine , however the value of the ptr p_arr returned from the debugger, shows the array and not the value pointed to as per the attached image I would have expected the value of p_arr to display as ->11
Looking at the code it seems to me that there is only a pointer type and not an array type, so arrays are subset of pointers?
In the following code a function prototype is used and an error is thrown
`#include
using namespace std;
int func(int x);
int main() {
int a;
cin >> a;
a = func(5); //fails
//a = func(a); //works
cout << a << endl;
return 0;
}
int func(int x){
x*= 10 ;
return x;
}`
it appears that the number '5' is of type 'unsigned int' so when getCompatibleFunction sees two possible functions (the prototype and the actual function) it throws the error.
I am looking into using your interpreter to visualise interrupt processing of an embedded system
Having a goto type function that is under external control might make it possible,
Which parts of your code should I begin to think about to implement this
thanks
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.