ha-chicken
Version:
An explanation of the interpreter of the programming language Chicken.
157 lines (148 loc) • 6.09 kB
JavaScript
// synopsis:
// (input , code ): direct call
// (index , 0 ): first internal call, called at beginning of a line
// (index ): successive internal call
// ( ): ending internal call
function chicken(CHICKEN, Chicken) {
// --------------- Prologue ---------------
// if the function is called directly (`code` exists),
// do the parsing job and execute itself recursively
Chicken && (
// parsing
// the environment is attached to the function itself
// `.chicken`: the stack
// `.Chicken`: either the code or the output
// `.CHICKEN`: the stack pointer
// `.$Chicken`: the input pointer (0 for stack, 1 for output)
chicken.chicken = [
// 0th - placeholder of error message
,
// 1st - input
CHICKEN,
// 2nd - the top of the stack
// save the code to `chicken.Chicken`
// then reuse `CHICKEN` to store the state
// and set all other stuffs to 0
// NOTE: the code will breaak when the code and the input is the same!!
// but if we regard the condition as an injection
// then the expression is indeed zero
CHICKEN = Chicken = chicken.$Chicken = -( CHICKEN == ( chicken.Chicken = Chicken ) )
],
// set the 0th item to reference the stack itself
// if a syntax error occurs,
// then the field will be replaced to that message
chicken.chicken[Chicken++] = chicken.chicken,
// initiate the stack pointer to 2
chicken.CHICKEN = ++Chicken,
// start parsing the program
chicken(--Chicken),
// set the input pointer to 2, the stack pointer
chicken.$Chicken = ++Chicken,
// increment the stack pointer and be ready to run the program
// from the top-most stack frame
chicken.CHICKEN++
);
// consume a number from stack and interpret it
// it is either from input or from the code,
// depending on the input pointer
Chicken = chicken.Chicken[chicken.$Chicken++];
// increment input counter
// the operation is depending on whether the function
// is called as ending call (by the first argument)
//
// * if it is called directly, (CHICKEN is truthy)
// then read code, get it parsed and continue recursively
// where `Chicken` is from the code
// * if it is called as ending call, (CHICKEN is 0 or undefined)
// then run the instruction
// where `Chicken` is from the stack
chicken.Chicken = CHICKEN ?
// --------------- Parsing ---------------
// if undefined, we are reading past the end of the code
Chicken ?
// `\n`, if there is no tokens left in the current line
'\012' == Chicken ?
// pass the second argument indicating the first call of line
// but not confused with the direct call (since it's zero and is falsy)
chicken(++CHICKEN, chicken.chicken[++chicken.CHICKEN] = CHICKEN - CHICKEN)
:
// check if we meet the separator...
Chicken == ' ' |
// ignoring any `\r` (for compatibility with Windows),
'\015' == Chicken ||
// or a token `chicken`
(Chicken) == "c" &
chicken.Chicken[chicken.$Chicken++] == "h" &
chicken.Chicken[chicken.$Chicken++] == "i" &
chicken.Chicken[chicken.$Chicken++] == "c" &
chicken.Chicken[chicken.$Chicken++] == "k" &
chicken.Chicken[chicken.$Chicken++] == "e" &
chicken.Chicken[chicken.$Chicken++] == "n" &&
// increment the current number of chicken
// for a successful read
++chicken.chicken[chicken.CHICKEN] ?
// if it is, continue reading
chicken(CHICKEN)
:
// if not, stop reading,
// clear the stack and output
[
// throw an error
"Error on line " + CHICKEN + ": expected 'chicken'",
// set the line number to `-1` as an exception
chicken.CHICKEN = (CHICKEN++) - CHICKEN
]
:
// store the stack, which is ready to be executed
chicken.chicken
: (
// --------------- Running instruction ---------------
CHICKEN = chicken.Chicken[chicken.CHICKEN],
Chicken ? (
Chicken =
--Chicken? --Chicken? --Chicken? --Chicken? --Chicken?
--Chicken? --Chicken? --Chicken? --Chicken?
// n (n > 9), push a number (n - 10) onto stack
chicken.CHICKEN++ && --Chicken:
// 9, BBQ, pop, interpret the value as ASCII and output it
'&#' + CHICKEN + ';':
// 8, fr, pop twice, if the second value is truthy
// then jump by the offset of the first value
chicken.Chicken[
chicken.Chicken[--chicken.CHICKEN] &&
(chicken. $Chicken += CHICKEN),
--chicken.CHICKEN
]:
// 7, peck, pop twice, store the second value to the stack address where
// the first value points to
chicken.Chicken[
chicken.Chicken[CHICKEN] = chicken.Chicken[--chicken.CHICKEN],
--chicken.CHICKEN
]:
// 6, pick, pop and load the value pointed to,
// where the source is specified from the next instruction
// (as input pointer)
chicken.Chicken[chicken.Chicken[chicken.$Chicken++]][CHICKEN]:
// 5, compare, pop twice and push `true` if they are equal; `false` otherwise
CHICKEN == chicken.Chicken[--chicken.CHICKEN]:
// 4, rooster, pop twice and push the product
CHICKEN * chicken.Chicken[--chicken.CHICKEN]:
// 3, fox, pop twice and push the difference (second - first)
chicken.Chicken[--chicken.CHICKEN] - CHICKEN:
// 2, add, pop twice and push the sum
chicken.Chicken[--chicken.CHICKEN] + CHICKEN:
// 1, chicken, push "chicken" onto stack
chicken.CHICKEN++ && "chicken",
// store the result
chicken.Chicken[chicken.CHICKEN] = Chicken,
// move to next instruction
chicken()
)
:
// 0, axe, terminating
CHICKEN
);
// return the output string
return chicken.Chicken;
}
module.exports = chicken;