Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2916536
stack.js
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
5 KB
Referenced Files
None
Subscribers
None
stack.js
View Options
const
STACK_SIZE
=
256
;
const
PROGRAM_SIZE
=
1024
;
const
Opcode
=
{
OP_PUSH
:
0
,
OP_POP
:
1
,
OP_ADD
:
2
,
OP_SUB
:
3
,
OP_MUL
:
4
,
OP_DIV
:
5
,
OP_PRINT
:
6
,
OP_JMP
:
7
,
OP_JZ
:
8
,
OP_LT
:
9
,
OP_EQ
:
10
,
OP_NEG
:
11
,
OP_HALT
:
12
};
const
opcodeNames
=
{
[
Opcode
.
OP_PUSH
]
:
'OP_PUSH'
,
[
Opcode
.
OP_POP
]
:
'OP_POP'
,
[
Opcode
.
OP_ADD
]
:
'OP_ADD'
,
[
Opcode
.
OP_SUB
]
:
'OP_SUB'
,
[
Opcode
.
OP_MUL
]
:
'OP_MUL'
,
[
Opcode
.
OP_DIV
]
:
'OP_DIV'
,
[
Opcode
.
OP_PRINT
]
:
'OP_PRINT'
,
[
Opcode
.
OP_JMP
]
:
'OP_JMP'
,
[
Opcode
.
OP_JZ
]
:
'OP_JZ'
,
[
Opcode
.
OP_LT
]
:
'OP_LT'
,
[
Opcode
.
OP_EQ
]
:
'OP_EQ'
,
[
Opcode
.
OP_NEG
]
:
'OP_NEG'
,
[
Opcode
.
OP_HALT
]
:
'OP_HALT'
};
// Debug settings
const
DEBUG_ENABLED
=
true
;
class
VM
{
constructor
()
{
this
.
sp
=
-
1
;
this
.
pc
=
0
;
this
.
stack
=
new
Array
(
STACK_SIZE
).
fill
(
0
);
this
.
program
=
new
Uint8Array
(
PROGRAM_SIZE
);
}
free
()
{
this
.
sp
=
-
1
;
this
.
pc
=
0
;
}
checkStackHasValues
(
count
)
{
if
(
this
.
sp
<
count
-
1
)
{
throw
new
Error
(
`Stack Underflow! Need
${
count
}
value(s), but stack has
${
this
.
sp
+
1
}
`
);
}
}
push
(
value
)
{
if
(
this
.
sp
>=
STACK_SIZE
-
1
)
{
throw
new
Error
(
'Stack Overflow!'
);
}
this
.
sp
++
;
this
.
stack
[
this
.
sp
]
=
value
;
this
.
tracePush
(
value
);
}
pop
()
{
this
.
checkStackHasValues
(
1
);
const
result
=
this
.
stack
[
this
.
sp
];
this
.
sp
--
;
this
.
tracePop
(
result
);
return
result
;
}
performBinary
(
op
)
{
this
.
checkStackHasValues
(
2
);
const
b
=
this
.
pop
();
const
a
=
this
.
pop
();
let
result
;
switch
(
op
)
{
case
'+'
:
result
=
a
+
b
;
break
;
case
'-'
:
result
=
a
-
b
;
break
;
case
'*'
:
result
=
a
*
b
;
break
;
case
'/'
:
result
=
Math
.
trunc
(
a
/
b
);
break
;
}
this
.
push
(
result
);
}
performUnary
(
op
)
{
this
.
checkStackHasValues
(
1
);
const
a
=
this
.
pop
();
let
result
;
switch
(
op
)
{
case
'-'
:
result
=
-
a
;
break
;
}
this
.
push
(
result
);
}
execute
()
{
this
.
traceHeader
();
while
(
true
)
{
const
op
=
this
.
program
[
this
.
pc
];
this
.
traceInstruction
(
this
.
pc
,
op
);
this
.
pc
++
;
switch
(
op
)
{
case
Opcode
.
OP_PUSH
:
{
const
val
=
this
.
readInt64
();
this
.
push
(
val
);
break
;
}
case
Opcode
.
OP_POP
:
this
.
pop
();
break
;
case
Opcode
.
OP_HALT
:
this
.
traceHalt
();
return
;
case
Opcode
.
OP_PRINT
:
this
.
checkStackHasValues
(
1
);
console
.
log
(
this
.
stack
[
this
.
sp
]);
break
;
case
Opcode
.
OP_ADD
:
this
.
performBinary
(
'+'
);
break
;
case
Opcode
.
OP_SUB
:
this
.
performBinary
(
'-'
);
break
;
case
Opcode
.
OP_MUL
:
this
.
performBinary
(
'*'
);
break
;
case
Opcode
.
OP_DIV
:
this
.
performBinary
(
'/'
);
break
;
case
Opcode
.
OP_NEG
:
this
.
performUnary
(
'-'
);
break
;
default
:
throw
new
Error
(
'Unknown Opcode!'
);
}
this
.
printStack
();
this
.
traceSeparator
();
}
}
readInt64
()
{
// Read 8 bytes as little-endian 64-bit integer
// JS doesn't handle 64-bit ints natively, but for small values this works
let
val
=
0
;
for
(
let
i
=
0
;
i
<
8
;
i
++
)
{
val
|=
this
.
program
[
this
.
pc
+
i
]
<<
(
i
*
8
);
}
this
.
pc
+=
8
;
return
val
;
}
// Debug/trace methods
traceHeader
()
{
if
(
!
DEBUG_ENABLED
)
return
;
console
.
log
(
'\n\x1b[96m\x1b[1m=== VM Execution Trace ===\x1b[0m\n'
);
}
traceInstruction
(
pc
,
opcode
)
{
if
(
!
DEBUG_ENABLED
)
return
;
const
name
=
opcodeNames
[
opcode
]
||
'UNKNOWN'
;
console
.
log
(
`\x1b[94m[PC=
${
pc
}
]\x1b[0m \x1b[32m\x1b[1m
${
name
}
\x1b[0m`
);
}
tracePush
(
value
)
{
if
(
!
DEBUG_ENABLED
)
return
;
console
.
log
(
`\x1b[2m \x1b[35mPUSH\x1b[0m \x1b[93m
${
value
}
\x1b[0m`
);
}
tracePop
(
value
)
{
if
(
!
DEBUG_ENABLED
)
return
;
console
.
log
(
`\x1b[2m \x1b[31mPOP \x1b[0m \x1b[93m
${
value
}
\x1b[0m`
);
}
traceHalt
()
{
if
(
!
DEBUG_ENABLED
)
return
;
console
.
log
(
'\n\x1b[91m\x1b[1m=== Execution Halted ===\x1b[0m'
);
}
traceSeparator
()
{
if
(
!
DEBUG_ENABLED
)
return
;
console
.
log
();
}
printStack
()
{
if
(
!
DEBUG_ENABLED
)
return
;
let
stackStr
=
this
.
stack
.
slice
(
0
,
this
.
sp
+
1
).
join
(
' '
);
console
.
log
(
`\x1b[2m Stack \x1b[36m[sp=
${
this
.
sp
}
]\x1b[0m: [ \x1b[33m
${
stackStr
}
\x1b[0m ]`
);
}
}
// Helper to write int64 to program
function
writeInt
(
program
,
pc
,
val
)
{
for
(
let
i
=
0
;
i
<
8
;
i
++
)
{
program
[
pc
.
value
]
=
(
val
>>
(
i
*
8
))
&
0xff
;
pc
.
value
++
;
}
}
// Main
function
main
()
{
const
v
=
new
VM
();
const
values
=
[
10
,
13
,
6
,
25
,
42
];
const
pc
=
{
value
:
0
};
for
(
const
val
of
values
)
{
v
.
program
[
pc
.
value
++
]
=
Opcode
.
OP_PUSH
;
writeInt
(
v
.
program
,
pc
,
val
);
}
v
.
program
[
pc
.
value
++
]
=
Opcode
.
OP_MUL
;
v
.
program
[
pc
.
value
++
]
=
Opcode
.
OP_ADD
;
v
.
program
[
pc
.
value
++
]
=
Opcode
.
OP_NEG
;
v
.
program
[
pc
.
value
++
]
=
Opcode
.
OP_DIV
;
v
.
program
[
pc
.
value
++
]
=
Opcode
.
OP_SUB
;
v
.
program
[
pc
.
value
++
]
=
Opcode
.
OP_PRINT
;
v
.
program
[
pc
.
value
++
]
=
Opcode
.
OP_HALT
;
v
.
execute
();
v
.
free
();
}
main
();
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Thu, Mar 26, 5:50 PM (2 d)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
512026
Default Alt Text
stack.js (5 KB)
Attached To
Mode
rANT Ant
Attached
Detach File
Event Timeline
Log In to Comment