Skip to content

Instantly share code, notes, and snippets.

@JossWhittle
Last active July 22, 2020 08:09
Show Gist options
  • Save JossWhittle/6132048 to your computer and use it in GitHub Desktop.
Save JossWhittle/6132048 to your computer and use it in GitHub Desktop.
A BNF Grammar for the JOSS Programming Language. The JOHNNIAC Open Shop System (JOSS) was a programming language developed by the RAND Corporation between 1963-1964 to allow mathematicians and engineers to run simple yet time consuming calculations with little to no knowledge of computers and without access to a computer expert. JOSS was the fir…
--- Strings & Numbers ---
<String> := <Char> | <Char> <String>
<Char> := <Alpha> | <Digit> | <SpecialChar>
<Alpha> := "A..Z" | "a..z"
<SpecialChar> := "." | "," | ";" | ":" | "'" | " " | "#" | "$" | "?"
<Number> := <NumberPart> | <Sign> <NumberPart>
<NumberPart> := <IntPart> | <IntPart> "." <DecimalPart>
<IntPart> := "0" | <NZDigit> | <NZDigit> <DecimalPart>
<DecimalPart> := <Digit> | <Digit> <DecimalPart>
<Digit> := "0" | <NZDigit>
<NZDigit> := "1..9"
<Sign> := "+" | "-"
--- Dataflow ---
<PartNumber> := <NZDigit> | <NZDigit> <IntPart>
<StepNumber> := <PartNumber> "." <PartNumber>
--- Statements ---
<Statement> := <Direct> "." | <Indirect> "." | <FormCMD> | <Assignment>
<Direct> := <CancelCMD> | <DeleteCmdCMD> | <GoCMD> | <ArbitraryCMD>
<Indirect> := <StepNumber> <IndirectCMD>
<IndirectCMD> := <ToCMD> | <DoneCMD> | <StopCMD> | <DemandCMD> | <ArbitraryCMD>
<ArbitraryCMD> := <SetCMD> | <DoCMD> | <TypeCMD> | <DeleteValCMD> | <LineCMD> | <PageCMD>
--- Direct Statements ---
<GoCMD> := "Go"
<CancelCMD> := "Cancel"
<DeleteCmdCMD> := "Delete" <DelCmdSel>
<DelCmdSel> := <StepSel> | <PartSel> | <FormSel> | <DelCmdAllSel>
<DelCmdAllSel> := "all" | "all" <DelCmdAllType>
<DelCmdAllType> := "steps" | "parts" | "forms"
--- Indirect Statements ---
<DoneCMD> := "Done"
<StopCMD> := "Stop"
<DemandCMD> := "Demand" <Variable>
<ToCMD> := "To" <ToSel>
<ToSel> := <StepSel> | <PartSel>
--- Arbitrary Statements ---
<SetCMD> := "Set" <Assignment>
<DoCMD> := "Do" <DoSel> | "Do" <DoSel> <Conditional>
<DoSel> := <StepSel> | <PartSel>
<TypeCMD> := "Type" <TypeContent>
<TypeContent> := <TypeForm> | <TypeData> | <TypeSel> | <TypeSys>
<TypeSys> := "size" | "time" | "users"
<TypeForm> := <VarList> "in" <FormSel>
<TypeData> := <TypeElem> | <TypeElem> "," <TypeData>
<TypeElem> := """ <String> """ | <Variable>
<TypeSel> := <StepSel> | <PartSel> | <FormSel> | <TypeAllSel>
<TypeAllSel> := "all" | "all" <TypeAllType>
<TypeAllType> := "steps" | "parts" | "forms" | "values"
<DeleteValCMD> := <VarList> | "all" "values"
<LineCMD> := "Line"
<PageCMD> := "Page"
--- Form Statements ---
<FormCMD> := "Form" <PartNumber> ":"
<FormContent> := <FormObject> | <FormObject> <FormContent>
<FormObject> := <FormPH> | <String>
<FormPH> := <SciNotation> | <FixedNotation>
<SciNotation> := ".." <Dot>
<Dot> := "." | "." <Dot>
<FixedNotation> := "__" <UScore> ".__" <UScore>
<UScore> := "_" | "_" <UScore>
--- Select Statements ---
<StepSel> := "step" <StepNumber>
<PartSel> := "part" <PartNumber>
<FormSel> := "form" <PartNumber>
-- Conditional Statements ---
<Conditional> := <If> | <For>
<If> := "if" <BoolExp>
<BoolExp> := "(" <BoolExp> ")" | "[" <BoolExp> "]" | <Comparison> | <Comparison> <BoolOp> <BoolExp>
<BoolOp> := "and" | "or"
<Comparison> := <MathExp> <BoolComp> <MathExp>
<BoolComp> := "=" | "!=" | "<=" | ">=" | "<" | ">"
<For> := "for" <Range>
<Range> := <Variable> "=" <RangeExp>
<RangeExp> := <RangeVal> | <RangeVal> "," <RangeExp>
<RangeVal> := <MathExp> "(" <MathExp> ")" <RangeVal> | <MathExp>
--- Math Statements ---
<MathExp> := <Term> | <Term> <AddOp> <MathExp>
<Term> := <Factor> | <Factor> <MulOp> <Term>
<Factor> := "(" <MathExp> ")" | "[" <MathExp> "]" | <Value>
<Value> := <Number> | <Variable> | <Function>
<MulOp> := "*" | "/"
<AddOp> := "+" | "-"
--- Function ---
<Function> := <FuncSqrt> | <FuncLog> | <FuncExp> | <FuncSin> | <FuncCos> | <FuncIp> |
<FuncFp> | <FuncDp> | <FuncXp> | <FuncSgn> | <FuncMax> | <FuncMin>
<FuncSqrt> := "sqrt(" <MathExp> ")"
<FuncLog> := "log(" <MathExp> ")"
<FuncExp> := "exp(" <MathExp> ")"
<FuncSin> := "sin(" <MathExp> ")"
<FuncCos> := "cos(" <MathExp> ")"
<FuncIp> := "ip(" <MathExp> ")"
<FuncFp> := "fp(" <MathExp> ")"
<FuncDp> := "dp(" <MathExp> ")"
<FuncXp> := "xp(" <MathExp> ")"
<FuncSgn> := "sgn(" <MathExp> ")"
<FuncMax> := "max(" <MathExp> "," <ArgList> ")"
<FuncMin> := "min(" <MathExp> "," <ArgList> ")"
<ArgList> := <MathExp> | <MathExp> "," <ArgList>
--- Variables ---
<Variable> := <Alpha> | <Alpha> "(" <MathExp> ")"
<VarList> := <Variable> | <Variable> "," <VarList>
start
= Statement
S
= [' '\t\r\n]
Sep
= S*
{ return ""; }
Seps
= S+
{ return ""; }
/*
* Numbers
*/
Number
= sign:[+-]? num:NumberPart
{ return parseFloat(sign + num,10); }
NumberPart
= int:("0" / NZInt) dot:("." dec:Digit+ { return "." + dec.join(""); })?
{ return int + dot; }
NZInt
= lead:NZDigit int:Digit*
{ return lead + int.join(""); }
Digit
= digit:[0-9]
{ return digit; }
NZDigit
= nzdigit:[1-9]
{ return nzdigit; }
/*
* Math
*/
MathExp
= Sep l:Term Sep o:AddOp Sep r:MathExp Sep
{ return { tag: "math", val:{ op: o, left: l, right: r }}; } /
Sep l:Term Sep
{ return l; }
Term
= l:Factor Sep o:MulOp Sep r:Term
{ return { tag: "math", val:{ op: o, left: l, right: r }}; } /
l:Factor
{ return l; }
Factor
= "(" exp:MathExp ")"
{ return exp; } /
"[" exp:MathExp "]"
{ return exp; } /
v:Value
{ return v; } /
v:Function
{ return v; } /
v:Variable
{ return v; }
Value
= num:Number
{ return { tag: "num", val: num }; }
AddOp
= [+-]
MulOp
= [*/]
/*
* Strings
*/
Alpha
= char:[a-zA-Z]
{ return char; }
SpecialChar
= char:[\.,;:' #$?]
{ return char; }
Char
= char:Alpha / char:Digit / char:SpecialChar
{ return char; }
String
= chars:Char*
{ return { tag: "string", val:chars.join("") }; }
/*
* Variable
*/
Variable
= v:Alpha "(" i:MathExp ")"
{ return { tag: "var", val: { id:v, index: i }}; } /
v:Alpha
{ return { tag: "var", val: { id:v, index: { tag: "num", val: 0 } }}; }
VariableList
= v:Variable vl:(Sep "," Sep e:Variable { return e; })+
{ vl.splice(0,0,v); return vl; } /
v:Variable
{ return [v]; }
Assignment
= v:Variable Sep "=" Sep exp:MathExp
{ return { tag: "assignment", val:{var: v, exp: exp} }; }
/*
* Functions
*/
Function
= f:SingleFunction "(" exp:MathExp ")"
{ return { tag: "function", val: { func:f, param:exp } }; } /
f:MultiFunction "(" p:MathExp ps:(Sep "," Sep exp:MathExp {return exp;})+ ")"
{ ps.splice(0,0,p); return { tag: "function", val: { func:f, params: ps } }; }
SingleFunction
= "sqrt" / "log" / "exp" / "sin" / "cos" / "ip" / "fp" / "dp" / "xp" / "sgn"
MultiFunction
= "min" / "max"
/*
* Dataflow
*/
PartNumber
= part:NZInt
{ return { tag: "partnumber", val: part }; }
StepNumber
= part:NZInt "." step:NZInt
{ return { tag: "stepnumber", val: {part:part, step:step} }; }
FormNumber
= form:NZInt
{ return { tag: "formnumber", val: form }; }
/*
* Select
*/
StepSel
= "step" Seps num:StepNumber
{ return num; }
PartSel
= "part" Seps num:PartNumber
{ return num; }
FormSel
= "form" Seps num:FormNumber
{ return num; }
/*
* Statements
*/
Statement
= cmd:Direct Sep "."
{ return { tag: "directcmd", val:cmd }; } /
step:StepNumber Seps cmd:Indirect Sep "."
{ return { tag: "indirectcmd", val:{step: step, cmd:cmd} }; } /
cmd:Assignment
{ return { tag: "assignmentcmd", val:cmd }; } /
cmd:FormCMD
{ return { tag: "formcmd", val:cmd }; }
Direct
= GoCMD / CancelCMD / DeleteCmdCMD / ArbitraryCMD
Indirect
= DoneCMD / StopCMD / DemandCMD / ToCMD / ArbitraryCMD
ArbitraryCMD
= SetCMD / DoCMD / TypeCMD / DeleteValCMD / LineCMD / PageCMD
/*
* Direct
*/
GoCMD
= "Go"
{ return { tag: "go" }; }
CancelCMD
= "Cancel"
{ return { tag: "cancel" }; }
DeleteCmdCMD
= "Delete" Seps sel:DeleteCmdSel
{ return { tag: "delete", val: sel }; }
DeleteCmdSel
= StepSel / PartSel / FormSel / DeleteCmdAllSel /
vl:VariableList
{ return { tag: "vars", val:vl }; }
DeleteCmdAllSel
= "all" Seps type:DeleteCmdAllType
{ return { tag: "all", val: type }; } /
"all"
{ return { tag: "all", val: "all" }; }
DeleteCmdAllType
= "steps" / "parts" / "forms" / "values"
/*
* Indirect
*/
DoneCMD
= "Done"
{ return { tag: "done" }; }
StopCMD
= "Stop"
{ return { tag: "stop" }; }
DemandCMD
= "Demand" Seps v:Variable
{ return { tag: "demand", val: v }; }
ToCMD
= "To" Seps sel:ToSel
{ return { tag: "to", val: sel }; }
ToSel
= StepSel / PartSel
/*
* Arbitrary
*/
SetCMD
= "Set" Seps v:Assignment
{ return { tag: "set", val: v }; }
DoCMD
= "Do" Seps sel:DoSel cond:(Seps c:Conditional { return c; })?
{ return { tag: "do", val: {sel: sel, cond:cond} }; }
DoSel
= StepSel / PartSel
TypeCMD
= "Type" Seps sel:TypeContent
{ return { tag: "type", val: sel }; }
TypeContent
= TypeSys /
TypeSel /
TypeForm /
vl:TypeData
{ return { tag: "typedata", val:vl }; }
TypeSys
= "size"
{ return { tag: "typesize" }; } /
"time"
{ return { tag: "typetime" }; } /
"users"
{ return { tag: "typeusers" }; }
TypeForm
= v:VariableList Seps "in" Seps f:FormSel
{ return { tag: "typeform", val: { vars:v, form:f } }; }
TypeData
= v:TypeElem vl:(Sep "," Sep e:TypeElem { return e; })+
{ vl.splice(0,0,v); return vl; } /
v:TypeElem
{ return [v]; }
TypeElem
= "\"" str:String "\""
{ return str; } /
v:Variable
{ return v; }
TypeSel
= StepSel / PartSel / FormSel / TypeAllSel
TypeAllSel
= "all" Seps type:TypeAllType
{ return { tag: "all", val: type }; } /
"all"
{ return { tag: "all", val: "all" }; }
TypeAllType
= "steps" / "parts" / "forms" / "values"
DeleteValCMD
= "Delete" Seps sel:DeleteValSel
{ return { tag: "delete", val:sel }; }
DeleteValSel
= "all" Seps "values"
{ return { tag: "all", val: "values" }; } /
vl:VariableList
{ return { tag: "vars", val:vl }; }
LineCMD
= "Line"
{ return { tag: "line" }; }
PageCMD
= "Page"
{ return { tag: "page" }; }
/*
* Conditional
*/
Conditional
= i:IfCMD
{ return i; } /
i:ForCMD
{ return i; }
IfCMD
= "if" Seps exp:BoolExp
{ return { tag: "if", val: exp }; }
BoolExp
= c:Comparison Sep o:BoolOp Sep exp:BoolExp
{ return { tag: "boolean", val: { op:o, left:c, right:exp } }; } /
c:Comparison
{ return c; }
BoolOp
= "and" / "or"
Comparison
= "(" Sep exp:BoolExp Sep ")"
{ return exp; } /
"[" Sep exp:BoolExp Sep "]"
{ return exp; } /
l:MathExp Sep o:BoolComp Sep r:MathExp
{ return { tag: "comparison", val: { op:o, left:l, right:r } }; }
BoolComp
= "=" / "!=" / "<=" / ">=" / "<" / ">"
ForCMD
= "for" Seps r:Range
{ return { tag: "for", val: r }; }
Range
= v:Variable Sep "=" Sep r:RangeExp
{ return { var:v, range:r }; }
RangeExp
= v:RangeVal vl:(Sep "," Sep e:RangeVal { return e; })+
{ vl.splice(0,0,v); return vl; } /
v:RangeVal
{ return [v]; }
RangeVal
= exp:MathExp r:("(" inc:MathExp ")" target:MathExp { return { inc: inc, target: target }; })+
{ return { tag: "range", val: { start: exp, targets: r } }; } /
exp:MathExp
{ return { tag: "val", val: exp }; }
/*
* Forms
*/
FormCMD
= "Form" Seps form:NZInt Sep ":"
{ return form; }
FormInputCMD
= format:(plc:FormPlaceHolder {return plc;} / str:FormString { return str; })+
{ return format; }
FormString
= chars:(Char / [=\+\*\/"])+
{ return { tag: "string", val:chars.join("") }; }
FormPlaceHolder
= i:("_")+ "." f:("_")+
{ var il = (i.length); var fl = (f.length); return { tag: "fixed", val: { ip: il, fp: fl } }; } /
"@@" ("@")+
{ return { tag: "scinote" }; }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment