Added first real test.
This commit is contained in:
parent
1c69cbf70e
commit
f382f8d575
|
@ -10,6 +10,6 @@ result can be more easily precompiled for native execution.
|
||||||
- overall philosophy
|
- overall philosophy
|
||||||
- easy to target for compilers
|
- easy to target for compilers
|
||||||
- easy to implement with overhead
|
- easy to implement with overhead
|
||||||
- possible to implement with no overhead
|
- possible to implement with no/low overhead
|
||||||
- can use easy but "slow" or DIY
|
- can use easy but "slow" or DIY?
|
||||||
- e.g. MALL vs static memory and custom allocation
|
- e.g. MALL vs static memory and custom allocation
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
\documentclass{article}
|
\documentclass{article}
|
||||||
|
|
||||||
\usepackage[letterpaper, landscape, margin=1cm]{geometry}
|
\usepackage[letterpaper, landscape, margin=0.7cm]{geometry}
|
||||||
|
|
||||||
\usepackage{tabularx}
|
\usepackage{tabularx}
|
||||||
\usepackage{tabulary}
|
\usepackage{tabulary}
|
||||||
|
@ -48,6 +48,8 @@
|
||||||
\newif\ifnoopdef
|
\newif\ifnoopdef
|
||||||
\newif\ifopisfun
|
\newif\ifopisfun
|
||||||
\newif\ifopisimm
|
\newif\ifopisimm
|
||||||
|
\newif\ifopisgud
|
||||||
|
\newif\ifopisbad
|
||||||
\newcommand{\optextdescr}{}
|
\newcommand{\optextdescr}{}
|
||||||
\newcommand{\optext}[1]{\renewcommand{\optextdescr}{#1}\noopdeffalse}
|
\newcommand{\optext}[1]{\renewcommand{\optextdescr}{#1}\noopdeffalse}
|
||||||
|
|
||||||
|
@ -56,158 +58,223 @@
|
||||||
\noopdeftrue
|
\noopdeftrue
|
||||||
\opisfunfalse
|
\opisfunfalse
|
||||||
\opisimmfalse
|
\opisimmfalse
|
||||||
|
\opisgudfalse
|
||||||
|
\opisbadfalse
|
||||||
|
|
||||||
% TODO: document and add more metasyntactic variables/functions
|
% TODO: document and add more metasyntactic variables/functions?
|
||||||
|
|
||||||
% So far uncategorized instructions
|
% So far uncategorized instructions
|
||||||
\if0#1
|
|
||||||
\optext{branch to immediate if x is not zero}
|
|
||||||
\stackdiagram{x,\ldots}{\ldots}
|
|
||||||
\fi
|
|
||||||
\if9#1
|
|
||||||
\optext{compare and swap x and y at p, push success}
|
|
||||||
\stackdiagram{y,x,p,\ldots}{z,\ldots}
|
|
||||||
\fi
|
|
||||||
\if E#1
|
|
||||||
\optext{round a to integer and store in x}
|
|
||||||
\stackdiagram{a,\ldots}{x,\ldots}
|
|
||||||
\fi
|
|
||||||
\if L#1
|
|
||||||
\optext{roll stack by immediate places}
|
|
||||||
\stackdiagram{z,\cdots,y,x,\ldots}{x,z,\cdots,y,\ldots}
|
|
||||||
\opisimmtrue
|
|
||||||
\fi
|
|
||||||
\if U#1
|
|
||||||
\optext{compare x to y unsigned and set z such that x o y is z o 0}
|
|
||||||
\stackdiagram{y,x,\ldots}{z,\ldots}
|
|
||||||
\fi
|
|
||||||
\if V#1
|
|
||||||
\optext{bitwise OR x and y}
|
|
||||||
\stackdiagram{y,x,\ldots}{x\vee{}y,\ldots}
|
|
||||||
\fi
|
|
||||||
\if W#1
|
|
||||||
\optext{truncate x to 32 bits, then sign extend}
|
|
||||||
\stackdiagram{x,\ldots}{x,\ldots}
|
|
||||||
\fi
|
|
||||||
\if d#1
|
\if d#1
|
||||||
\optext{set x bytes of memory to immediate value at p}
|
\optext{set x bytes of memory to immediate value at p}
|
||||||
|
\opisbadtrue
|
||||||
\stackdiagram{x,p,\ldots}{\ldots}
|
\stackdiagram{x,p,\ldots}{\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if e#1
|
|
||||||
\optext{rotate stack}
|
|
||||||
\stackdiagram{z,y,x,\ldots}{x,z,y,\ldots}
|
|
||||||
\fi
|
|
||||||
\if f#1
|
\if f#1
|
||||||
\optext{invoke f, saving return address on stack}
|
\optext{invoke f, saving return address on stack}
|
||||||
\opisfuntrue
|
\opisfuntrue
|
||||||
\stackdiagram{f,\ldots}{g,\ldots}
|
\stackdiagram{f,\ldots}{g,\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if h#1
|
|
||||||
\optext{stack over}
|
|
||||||
\stackdiagram{y,x,\ldots}{x,y,x,\ldots}
|
|
||||||
\fi
|
|
||||||
\if j#1
|
|
||||||
\optext{negate a}
|
|
||||||
\stackdiagram{a,\ldots}{-a,\ldots}
|
|
||||||
\fi
|
|
||||||
\if k#1
|
|
||||||
\optext{stack pop}
|
|
||||||
\stackdiagram{x,\ldots}{\ldots}
|
|
||||||
\fi
|
|
||||||
\if l#1
|
|
||||||
\optext{bit clear y from x to z}
|
|
||||||
\stackdiagram{y,x,\ldots}{(x\wedge\neg{}y}
|
|
||||||
\fi
|
|
||||||
\if m#1
|
|
||||||
\optext{floating point difference}
|
|
||||||
\stackdiagram{b,a,\ldots}{a-b}
|
|
||||||
\fi
|
|
||||||
\if p#1
|
|
||||||
\optext{floating point multiply}
|
|
||||||
\stackdiagram{b,a,\ldots}{a\times{}b,\ldots}
|
|
||||||
\fi
|
|
||||||
\if q#1
|
|
||||||
\optext{floating point divide}
|
|
||||||
\stackdiagram{b,a,\ldots}{b\over{}a,\ldots}
|
|
||||||
\fi
|
|
||||||
\if s#1
|
|
||||||
\optext{floating point add}
|
|
||||||
\stackdiagram{b,a,\ldots}{b+a,\ldots}
|
|
||||||
\fi
|
|
||||||
\if t#1
|
|
||||||
\optext{stack swap}
|
|
||||||
\stackdiagram{y,x,\ldots}{x,y,\ldots}
|
|
||||||
\fi
|
|
||||||
\if u#1
|
|
||||||
\optext{logical shift x by immediate bits right}
|
|
||||||
\opisimmtrue
|
|
||||||
\stackdiagram{x,\ldots}{x,\ldots}
|
|
||||||
\fi
|
|
||||||
\if v#1
|
|
||||||
\optext{floating point absolute value}
|
|
||||||
\stackdiagram{a,\ldots}{|a|,\ldots}
|
|
||||||
\fi
|
|
||||||
\if w#1
|
|
||||||
\optext{stack duplicate}
|
|
||||||
\stackdiagram{x,\ldots}{x,x,\ldots}
|
|
||||||
\fi
|
|
||||||
\ifx#1\_
|
|
||||||
\optext{negate x}
|
|
||||||
\stackdiagram{x,\ldots}{-x,\ldots}
|
|
||||||
\fi
|
|
||||||
\if .#1
|
|
||||||
\optext{convert x to a float}
|
|
||||||
\stackdiagram{x,\ldots}{a,\ldots}
|
|
||||||
\fi
|
|
||||||
\if +#1
|
|
||||||
\optext{integer add}
|
|
||||||
\stackdiagram{y,x,\ldots}{x+y,\ldots}
|
|
||||||
\fi
|
|
||||||
\if -#1
|
|
||||||
\optext{integer subtract}
|
|
||||||
\stackdiagram{y,x,\ldots}{x-y,\ldots}
|
|
||||||
\fi
|
|
||||||
\if *#1
|
|
||||||
\optext{integer multiply}
|
|
||||||
\stackdiagram{y,x,\ldots}{x\times{}y,\ldots}
|
|
||||||
\fi
|
|
||||||
\if /#1
|
|
||||||
\optext{integer divide}
|
|
||||||
\stackdiagram{y,x,\ldots}{x\div{}y,\ldots}
|
|
||||||
\fi
|
|
||||||
\ifx#1\%
|
|
||||||
\optext{integer modulo}
|
|
||||||
\stackdiagram{y,x,\ldots}{x\ \textrm{mod}\ y,\ldots}
|
|
||||||
\fi
|
|
||||||
\ifx#1\textbackslash
|
|
||||||
\optext{integer remainder}
|
|
||||||
\stackdiagram{y,x,\ldots}{x\%y,\ldots}
|
|
||||||
\fi
|
|
||||||
\if |#1
|
|
||||||
\optext{integer absolute value}
|
|
||||||
\stackdiagram{x,\ldots}{|x|,\ldots}
|
|
||||||
\fi
|
|
||||||
\ifx#1\$
|
|
||||||
\optext{load constant value}
|
|
||||||
\opisimmtrue
|
|
||||||
\stackdiagram{\ldots}{\star{},\ldots}
|
|
||||||
\fi
|
|
||||||
\if @#1
|
\if @#1
|
||||||
\optext{call immediate name}
|
\optext{call immediate name}
|
||||||
\opisimmtrue
|
\opisimmtrue
|
||||||
\opisfuntrue
|
\opisfuntrue
|
||||||
|
\opisgudtrue
|
||||||
\stackdiagram{\ldots}{f,\ldots}
|
\stackdiagram{\ldots}{f,\ldots}
|
||||||
\fi
|
\fi
|
||||||
|
\if `#1
|
||||||
|
\optext{call builtin with given name/value}
|
||||||
|
\opisimmtrue
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{?,\ldots}{?,\ldots}
|
||||||
|
\fi
|
||||||
|
\if M#1
|
||||||
|
\optext{call math operation with given name/value}
|
||||||
|
\opisimmtrue
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{?,\ldots}{?,\ldots}
|
||||||
|
\fi
|
||||||
|
|
||||||
|
% Memory management functions
|
||||||
|
\if F#1
|
||||||
|
\optext{free x bytes from p}
|
||||||
|
\stackdiagram{x,p,\ldots}{\ldots}
|
||||||
|
\fi
|
||||||
|
\if R#1
|
||||||
|
\optext{reallocate p to x bytes}
|
||||||
|
\stackdiagram{x,p,\ldots}{p,\ldots}
|
||||||
|
\fi
|
||||||
|
|
||||||
|
% Comparisons
|
||||||
|
\if9#1
|
||||||
|
\optext{compare and swap x and y at p, push success}
|
||||||
|
\stackdiagram{y,x,p,\ldots}{z,\ldots}
|
||||||
|
\fi
|
||||||
|
\if U#1
|
||||||
|
\optext{compare x to y unsigned and set z such that x o y is z o 0}
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{y,x,\ldots}{z,\ldots}
|
||||||
|
\fi
|
||||||
|
\if ?#1
|
||||||
|
\optext{compare x to y and set z such that x o y is z o 0}
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{x,y,\ldots}{z,\ldots}
|
||||||
|
\fi
|
||||||
|
\ifx#1\textasciitilde
|
||||||
|
\optext{compare a to b within an immediate error}
|
||||||
|
\opisgudtrue
|
||||||
|
\opisimmtrue
|
||||||
|
\stackdiagram{a,b,\ldots}{c,\ldots}
|
||||||
|
\fi
|
||||||
|
|
||||||
|
% Syntactical "instructions"
|
||||||
|
\ifx#1\textvisiblespace
|
||||||
|
\optext{do nothing}
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{\ldots}{\ldots}
|
||||||
|
\fi
|
||||||
|
\ifx#1\#
|
||||||
|
\optext{comment}
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{ }{ }
|
||||||
|
\fi
|
||||||
|
\ifx#1\P
|
||||||
|
\optext{mark a beat for relative branching}
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{\ldots}{\ldots}
|
||||||
|
\fi
|
||||||
|
\if :#1
|
||||||
|
\optext{label line}
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{\ldots}{\ldots}
|
||||||
|
\fi
|
||||||
|
\if '#1
|
||||||
|
\optext{breakpoint}
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{ }{ }
|
||||||
|
\fi
|
||||||
|
\if "#1
|
||||||
|
\optext{change section}
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{ }{ }
|
||||||
|
\fi
|
||||||
|
\ifx#1\$
|
||||||
|
\optext{push constant value}
|
||||||
|
\opisimmtrue
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{\ldots}{\star{},\ldots}
|
||||||
|
\fi
|
||||||
|
|
||||||
|
% Stack manipulation instructions
|
||||||
|
\if L#1
|
||||||
|
\optext{roll stack by immediate places}
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{z,\cdots,y,x,\ldots}{x,z,\cdots,y,\ldots}
|
||||||
|
\opisimmtrue
|
||||||
|
\fi
|
||||||
|
\if T#1
|
||||||
|
\optext{push top of stack down by immediate places}
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{z,y,\cdots,x,\ldots}{z,\cdots,x,y,\ldots}
|
||||||
|
\opisimmtrue
|
||||||
|
\fi
|
||||||
|
\if e#1
|
||||||
|
\optext{rotate stack}
|
||||||
|
\opisgudtrue % named based on shape (take bottom to top)
|
||||||
|
\stackdiagram{z,y,x,\ldots}{x,z,y,\ldots}
|
||||||
|
\fi
|
||||||
|
\if h#1
|
||||||
|
\optext{stack over}
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{y,x,\ldots}{x,y,x,\ldots}
|
||||||
|
\fi
|
||||||
|
\if k#1
|
||||||
|
\optext{stack pop}
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{x,\ldots}{\ldots}
|
||||||
|
\fi
|
||||||
|
\if t#1
|
||||||
|
\optext{stack swap}
|
||||||
|
\opisgudtrue % named after the Thrush combinator
|
||||||
|
\stackdiagram{y,x,\ldots}{x,y,\ldots}
|
||||||
|
\fi
|
||||||
|
\if w#1
|
||||||
|
\optext{stack duplicate}
|
||||||
|
\opisgudtrue % named after the Warbler combinator
|
||||||
|
\stackdiagram{x,\ldots}{x,x,\ldots}
|
||||||
|
\fi
|
||||||
|
\if (#1
|
||||||
|
\optext{set x to depth of stack}
|
||||||
|
\stackdiagram{\ldots}{x,\ldots}
|
||||||
|
\fi
|
||||||
|
\if )#1
|
||||||
|
\optext{pack x elements of stack into array p}
|
||||||
|
\stackdiagram{x,p,\ldots}{p,\ldots}
|
||||||
|
\fi
|
||||||
|
|
||||||
|
% Integer operations
|
||||||
|
\if V#1
|
||||||
|
\optext{bitwise OR x and y}
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{y,x,\ldots}{x\vee{}y,\ldots}
|
||||||
|
\fi
|
||||||
|
\if l#1
|
||||||
|
\optext{bit clear y from x to z}
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{y,x,\ldots}{(x\wedge\neg{}y)}
|
||||||
|
\fi
|
||||||
|
\ifx#1\_
|
||||||
|
\optext{negate x}
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{x,\ldots}{-x,\ldots}
|
||||||
|
\fi
|
||||||
|
\if +#1
|
||||||
|
\optext{integer add}
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{y,x,\ldots}{x+y,\ldots}
|
||||||
|
\fi
|
||||||
|
\if -#1
|
||||||
|
\optext{integer subtract}
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{y,x,\ldots}{x-y,\ldots}
|
||||||
|
\fi
|
||||||
|
\if *#1
|
||||||
|
\optext{integer multiply}
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{y,x,\ldots}{x\times{}y,\ldots}
|
||||||
|
\fi
|
||||||
|
\if /#1
|
||||||
|
\optext{integer divide}
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{y,x,\ldots}{x\div{}y,\ldots}
|
||||||
|
\fi
|
||||||
|
\ifx#1\%
|
||||||
|
\optext{integer modulo}
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{y,x,\ldots}{x\ \textrm{mod}\ y,\ldots}
|
||||||
|
\fi
|
||||||
|
\ifx#1\textbackslash
|
||||||
|
\optext{integer remainder}
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{y,x,\ldots}{x\%y,\ldots}
|
||||||
|
\fi
|
||||||
|
\if |#1
|
||||||
|
\optext{integer absolute value}
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{x,\ldots}{|x|,\ldots}
|
||||||
|
\fi
|
||||||
\ifx#1\&
|
\ifx#1\&
|
||||||
\optext{set z to the bitwise and of x and y}
|
\optext{set z to the bitwise and of x and y}
|
||||||
|
\opisgudtrue
|
||||||
\stackdiagram{x,y,\ldots}{x\wedge{}y}
|
\stackdiagram{x,y,\ldots}{x\wedge{}y}
|
||||||
\fi
|
\fi
|
||||||
\ifx#1\textasciicircum
|
\ifx#1\textasciicircum
|
||||||
\optext{set z to the bitwise xor of x and y}
|
\optext{set z to the bitwise xor of x and y}
|
||||||
|
\opisgudtrue
|
||||||
\stackdiagram{x,y,\ldots}{x\oplus{}y}
|
\stackdiagram{x,y,\ldots}{x\oplus{}y}
|
||||||
\fi
|
\fi
|
||||||
\if !#1
|
\if !#1
|
||||||
\optext{set y to the bitwise not of x}
|
\optext{set y to the bitwise not of x}
|
||||||
|
\opisgudtrue
|
||||||
\stackdiagram{x,\ldots}{y,\ldots}
|
\stackdiagram{x,\ldots}{y,\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if [#1
|
\if [#1
|
||||||
|
@ -220,68 +287,90 @@
|
||||||
\opisimmtrue
|
\opisimmtrue
|
||||||
\stackdiagram{x,\ldots}{x,\ldots}
|
\stackdiagram{x,\ldots}{x,\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if ?#1
|
\if u#1
|
||||||
\optext{compare x to y and set z such that x o y is z o 0}
|
\optext{logical shift x by immediate bits right}
|
||||||
\stackdiagram{x,y,\ldots}{z,\ldots}
|
|
||||||
\fi
|
|
||||||
\ifx#1\textasciitilde
|
|
||||||
\optext{compare a to b within an immediate error}
|
|
||||||
\opisimmtrue
|
\opisimmtrue
|
||||||
\stackdiagram{a,b,\ldots}{c,\ldots}
|
\stackdiagram{x,\ldots}{x,\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if :#1
|
|
||||||
\optext{label code location}
|
% Float operations
|
||||||
\stackdiagram{\ldots}{\ldots}
|
\if j#1
|
||||||
|
\optext{negate a}
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{a,\ldots}{-a,\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if (#1
|
\if m#1
|
||||||
\optext{set x to depth of stack}
|
\optext{floating point difference}
|
||||||
\stackdiagram{\ldots}{x,\ldots}
|
\opisgudtrue
|
||||||
|
\stackdiagram{b,a,\ldots}{a-b}
|
||||||
\fi
|
\fi
|
||||||
\if )#1
|
\if p#1
|
||||||
\optext{pack x elements of stack into array p}
|
\optext{floating point multiply}
|
||||||
\stackdiagram{x,p,\ldots}{p,\ldots}
|
\opisgudtrue
|
||||||
|
\stackdiagram{b,a,\ldots}{a\times{}b,\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if '#1
|
\if q#1
|
||||||
\optext{embed data}
|
\optext{floating point divide}
|
||||||
\stackdiagram{ }{ }
|
\opisgudtrue
|
||||||
|
\stackdiagram{b,a,\ldots}{b\over{}a,\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if "#1
|
\if s#1
|
||||||
\optext{change section}
|
\optext{floating point add}
|
||||||
\stackdiagram{ }{ }
|
\opisgudtrue
|
||||||
|
\stackdiagram{b,a,\ldots}{b+a,\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if `#1
|
\if v#1
|
||||||
\optext{call builtin with given name/value}
|
\optext{floating point absolute value}
|
||||||
\opisimmtrue
|
\opisgudtrue
|
||||||
\stackdiagram{?,\ldots}{?,\ldots}
|
\stackdiagram{a,\ldots}{|a|,\ldots}
|
||||||
\fi
|
\fi
|
||||||
\ifx#1\textvisiblespace
|
|
||||||
\optext{do nothing}
|
% Conversion instructions
|
||||||
\stackdiagram{\ldots}{\ldots}
|
\if .#1
|
||||||
|
\optext{convert x to a float}
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{x,\ldots}{a,\ldots}
|
||||||
\fi
|
\fi
|
||||||
\ifx#1\#
|
\if E#1
|
||||||
\optext{comment}
|
\optext{round a to integer and store in x}
|
||||||
\stackdiagram{ }{ }
|
\opisgudtrue
|
||||||
|
\stackdiagram{a,\ldots}{x,\ldots}
|
||||||
\fi
|
\fi
|
||||||
\ifx#1\P
|
\if W#1
|
||||||
\optext{mark a beat for relative branching}
|
\optext{truncate x to 32 bits, then sign extend}
|
||||||
\stackdiagram{\ldots}{\ldots}
|
\opisgudtrue
|
||||||
|
\stackdiagram{x,\ldots}{x,\ldots}
|
||||||
|
\fi
|
||||||
|
\if S#1
|
||||||
|
\optext{truncate x to 16 bits, then sign extend}
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{x,\ldots}{x,\ldots}
|
||||||
|
\fi
|
||||||
|
\if O#1
|
||||||
|
\optext{truncate x to 8 bits, then sign extend}
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{x,\ldots}{x,\ldots}
|
||||||
\fi
|
\fi
|
||||||
|
|
||||||
% Load instructions
|
% Load instructions
|
||||||
\if1#1
|
\if1#1
|
||||||
\optext{load byte x from p}
|
\optext{load byte x from p}
|
||||||
|
\opisgudtrue
|
||||||
\stackdiagram{p,\ldots}{x,\ldots}
|
\stackdiagram{p,\ldots}{x,\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if2#1
|
\if2#1
|
||||||
\optext{load short x from p}
|
\optext{load short x from p}
|
||||||
|
\opisgudtrue
|
||||||
\stackdiagram{p,\ldots}{x,\ldots}
|
\stackdiagram{p,\ldots}{x,\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if3#1
|
\if3#1
|
||||||
\optext{load int x from p}
|
\optext{load int x from p}
|
||||||
|
\opisgudtrue
|
||||||
\stackdiagram{p,\ldots}{x,\ldots}
|
\stackdiagram{p,\ldots}{x,\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if4#1
|
\if4#1
|
||||||
\optext{load word x from p}
|
\optext{load word x from p}
|
||||||
|
\opisgudtrue
|
||||||
\stackdiagram{p,\ldots}{x,\ldots}
|
\stackdiagram{p,\ldots}{x,\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if G#1
|
\if G#1
|
||||||
|
@ -303,122 +392,158 @@
|
||||||
% Store instructions
|
% Store instructions
|
||||||
\if5#1
|
\if5#1
|
||||||
\optext{store byte x to p}
|
\optext{store byte x to p}
|
||||||
|
\opisgudtrue
|
||||||
\stackdiagram{x,p,\ldots}{\ldots}
|
\stackdiagram{x,p,\ldots}{\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if6#1
|
\if6#1
|
||||||
\optext{store short x to p}
|
\optext{store short x to p}
|
||||||
|
\opisgudtrue
|
||||||
\stackdiagram{x,p,\ldots}{\ldots}
|
\stackdiagram{x,p,\ldots}{\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if7#1
|
\if7#1
|
||||||
\optext{store int x to p}
|
\optext{store int x to p}
|
||||||
|
\opisgudtrue
|
||||||
\stackdiagram{x,p,\ldots}{\ldots}
|
\stackdiagram{x,p,\ldots}{\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if8#1
|
\if8#1
|
||||||
\optext{store word x to p}
|
\optext{store word x to p}
|
||||||
|
\opisgudtrue
|
||||||
\stackdiagram{x,p,\ldots}{\ldots}
|
\stackdiagram{x,p,\ldots}{\ldots}
|
||||||
\fi
|
\fi
|
||||||
|
|
||||||
% Register instructions
|
% Register instructions
|
||||||
\if A#1
|
\if A#1
|
||||||
\optext{store x in rA}
|
\optext{store x in rA}
|
||||||
|
\opisgudtrue
|
||||||
\stackdiagram{x,\ldots}{\ldots}
|
\stackdiagram{x,\ldots}{\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if B#1
|
\if B#1
|
||||||
\optext{store x in rB}
|
\optext{store x in rB}
|
||||||
|
\opisgudtrue
|
||||||
\stackdiagram{x,\ldots}{\ldots}
|
\stackdiagram{x,\ldots}{\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if C#1
|
\if C#1
|
||||||
\optext{store x in rC}
|
\optext{store x in rC}
|
||||||
|
\opisgudtrue
|
||||||
\stackdiagram{x,\ldots}{\ldots}
|
\stackdiagram{x,\ldots}{\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if I#1
|
\if I#1
|
||||||
\optext{store x in rI}
|
\optext{store x in rI}
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{x,\ldots}{\ldots}
|
||||||
|
\fi
|
||||||
|
\if N#1
|
||||||
|
\optext{store x in rN}
|
||||||
|
\opisgudtrue
|
||||||
\stackdiagram{x,\ldots}{\ldots}
|
\stackdiagram{x,\ldots}{\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if X#1
|
\if X#1
|
||||||
\optext{store x in rX}
|
\optext{store x in rX}
|
||||||
|
\opisgudtrue
|
||||||
\stackdiagram{x,\ldots}{\ldots}
|
\stackdiagram{x,\ldots}{\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if Y#1
|
\if Y#1
|
||||||
\optext{store x in rY}
|
\optext{store x in rY}
|
||||||
|
\opisgudtrue
|
||||||
\stackdiagram{x,\ldots}{\ldots}
|
\stackdiagram{x,\ldots}{\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if Z#1
|
\if Z#1
|
||||||
\optext{store x in rZ}
|
\optext{store x in rZ}
|
||||||
|
\opisgudtrue
|
||||||
\stackdiagram{x,\ldots}{\ldots}
|
\stackdiagram{x,\ldots}{\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if a#1
|
\if a#1
|
||||||
\optext{load x from rA}
|
\optext{load x from rA}
|
||||||
|
\opisgudtrue
|
||||||
\stackdiagram{\ldots}{x,\ldots}
|
\stackdiagram{\ldots}{x,\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if b#1
|
\if b#1
|
||||||
\optext{load x from rB}
|
\optext{load x from rB}
|
||||||
|
\opisgudtrue
|
||||||
\stackdiagram{\ldots}{x,\ldots}
|
\stackdiagram{\ldots}{x,\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if c#1
|
\if c#1
|
||||||
\optext{load x from rC}
|
\optext{load x from rC}
|
||||||
|
\opisgudtrue
|
||||||
\stackdiagram{\ldots}{x,\ldots}
|
\stackdiagram{\ldots}{x,\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if i#1
|
\if i#1
|
||||||
\optext{load x from rI}
|
\optext{load x from rI}
|
||||||
|
\opisgudtrue
|
||||||
\stackdiagram{\ldots}{x,\ldots}
|
\stackdiagram{\ldots}{x,\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if n#1
|
\if n#1
|
||||||
\optext{load x from rN}
|
\optext{load x from rN}
|
||||||
|
\opisgudtrue
|
||||||
\stackdiagram{\ldots}{x,\ldots}
|
\stackdiagram{\ldots}{x,\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if x#1
|
\if x#1
|
||||||
\optext{load x from rX}
|
\optext{load x from rX}
|
||||||
|
\opisgudtrue
|
||||||
\stackdiagram{\ldots}{x,\ldots}
|
\stackdiagram{\ldots}{x,\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if y#1
|
\if y#1
|
||||||
\optext{load x from rY}
|
\optext{load x from rY}
|
||||||
|
\opisgudtrue
|
||||||
\stackdiagram{\ldots}{x,\ldots}
|
\stackdiagram{\ldots}{x,\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if z#1
|
\if z#1
|
||||||
\optext{load x from rZ}
|
\optext{load x from rZ}
|
||||||
|
\opisgudtrue
|
||||||
\stackdiagram{\ldots}{x,\ldots}
|
\stackdiagram{\ldots}{x,\ldots}
|
||||||
\fi
|
\fi
|
||||||
|
|
||||||
% Branch instructions
|
% Branch instructions
|
||||||
|
\if0#1
|
||||||
|
\optext{branch to immediate if x is not zero}
|
||||||
|
\opisgudtrue
|
||||||
|
\stackdiagram{x,\ldots}{\ldots}
|
||||||
|
\fi
|
||||||
\if <#1
|
\if <#1
|
||||||
\optext{branch to immediate if x is less than zero}
|
\optext{branch to immediate if x is less than zero}
|
||||||
|
\opisgudtrue
|
||||||
\opisimmtrue
|
\opisimmtrue
|
||||||
\opisfuntrue
|
\opisfuntrue
|
||||||
\stackdiagram{x,\ldots}{\ldots}
|
\stackdiagram{x,\ldots}{\ldots}
|
||||||
\fi
|
\fi
|
||||||
\ifx#1\{
|
\ifx#1\{
|
||||||
\optext{branch to immediate if x is less than or equal to zero}
|
\optext{branch to immediate if x is less than or equal to zero}
|
||||||
|
\opisgudtrue
|
||||||
\opisimmtrue
|
\opisimmtrue
|
||||||
\opisfuntrue
|
\opisfuntrue
|
||||||
\stackdiagram{x,\ldots}{\ldots}
|
\stackdiagram{x,\ldots}{\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if =#1
|
\if =#1
|
||||||
\optext{branch to immediate if x is zero}
|
\optext{branch to immediate if x is zero}
|
||||||
|
\opisgudtrue
|
||||||
\opisimmtrue
|
\opisimmtrue
|
||||||
\opisfuntrue
|
\opisfuntrue
|
||||||
\stackdiagram{x,\ldots}{\ldots}
|
\stackdiagram{x,\ldots}{\ldots}
|
||||||
\fi
|
\fi
|
||||||
\ifx#1\}
|
\ifx#1\}
|
||||||
\optext{branch to immediate if x is greater or equal to zero}
|
\optext{branch to immediate if x is greater or equal to zero}
|
||||||
|
\opisgudtrue
|
||||||
\opisimmtrue
|
\opisimmtrue
|
||||||
\opisfuntrue
|
\opisfuntrue
|
||||||
\stackdiagram{x,\ldots}{\ldots}
|
\stackdiagram{x,\ldots}{\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if >#1
|
\if >#1
|
||||||
\optext{branch to immediate if x is greater than zero}
|
\optext{branch to immediate if x is greater than zero}
|
||||||
|
\opisgudtrue
|
||||||
\opisimmtrue
|
\opisimmtrue
|
||||||
\opisfuntrue
|
\opisfuntrue
|
||||||
\stackdiagram{x,\ldots}{\ldots}
|
\stackdiagram{x,\ldots}{\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if ,#1
|
\if ,#1
|
||||||
\optext{jump to immediate without pushing return address}
|
\optext{jump to immediate without pushing return address}
|
||||||
|
\opisgudtrue
|
||||||
\opisimmtrue
|
\opisimmtrue
|
||||||
\opisfuntrue
|
\opisfuntrue
|
||||||
\stackdiagram{\ldots}{\ldots}
|
\stackdiagram{\ldots}{\ldots}
|
||||||
\fi
|
\fi
|
||||||
\if ;#1
|
\if ;#1
|
||||||
\optext{return from subroutine}
|
\optext{return from subroutine}
|
||||||
|
\opisgudtrue
|
||||||
\opisfuntrue
|
\opisfuntrue
|
||||||
\stackdiagram{f,\ldots}{\ldots}
|
\stackdiagram{f,\ldots}{\ldots}
|
||||||
\fi
|
\fi
|
||||||
|
@ -429,6 +554,14 @@
|
||||||
\stackdiagram{?}{?}
|
\stackdiagram{?}{?}
|
||||||
\fi
|
\fi
|
||||||
|
|
||||||
|
\ifopisgud
|
||||||
|
\tikzset{every node/.style={color=black!25!green}}
|
||||||
|
\fi
|
||||||
|
|
||||||
|
\ifopisbad
|
||||||
|
\tikzset{every node/.style={color=black!25!red}}
|
||||||
|
\fi
|
||||||
|
|
||||||
\ifopisfun
|
\ifopisfun
|
||||||
\ifopisimm
|
\ifopisimm
|
||||||
\tikzset{->/.style={arrows={Arc Barb[reversed,length=3pt]-Latex[length=5pt]}, double distance=1pt}}
|
\tikzset{->/.style={arrows={Arc Barb[reversed,length=3pt]-Latex[length=5pt]}, double distance=1pt}}
|
||||||
|
|
|
@ -89,6 +89,11 @@ Need better description of data '' format. See QBE's data for inspiration?
|
||||||
Consider having each op-code mean something different in different sections?
|
Consider having each op-code mean something different in different sections?
|
||||||
Only consistency would be labels... those could be more universally parsed?
|
Only consistency would be labels... those could be more universally parsed?
|
||||||
Alternatively remove sections altogether and use only dynamic memory?
|
Alternatively remove sections altogether and use only dynamic memory?
|
||||||
|
I prefer sections, start with just implementations/documentation/specification
|
||||||
|
of code/data. For JIT code is obvious, data is variables loaded with appropriate
|
||||||
|
data and "passed through" to JIT.
|
||||||
|
Ideally keep immediate instructions consistent in each section (easier
|
||||||
|
parsing/highlighting/etc)?
|
||||||
```
|
```
|
||||||
|
|
||||||
## File Format
|
## File Format
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
divert(`-1')dnl
|
divert(`-1')dnl
|
||||||
changequote(`«', `»')
|
changequote(`«', `»')
|
||||||
changecom(«/*», «*/»)
|
changecom(«\»)
|
||||||
\ note: use https://github.com/vim-scripts/syntaxm4.vim.git
|
\ note: use https://github.com/vim-scripts/syntaxm4.vim.git
|
||||||
vim-m4-syntax: quote=«,» comment=\\
|
vim-m4-syntax: quote=«,» comment=\\
|
||||||
|
|
||||||
define(«TICK», changequote([,])[changequote([,])»changequote(«,»)]changequote(«,»))
|
|
||||||
|
|
||||||
\ forloop(var, from, to, stmt) - improved version:
|
\ forloop(var, from, to, stmt) - improved version:
|
||||||
\ works even if VAR is not a strict macro name
|
\ works even if VAR is not a strict macro name
|
||||||
\ performs sanity check that FROM is larger than TO
|
\ performs sanity check that FROM is larger than TO
|
||||||
|
|
9
samples/hello.arx
Normal file
9
samples/hello.arx
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#!/usr/bin/env arctic
|
||||||
|
|
||||||
|
"data"
|
||||||
|
:message sHello\ World!\x0A
|
||||||
|
|
||||||
|
"code"
|
||||||
|
@main
|
||||||
|
:main $15 $message $1 `1 $0 ;
|
||||||
|
|
|
@ -11,12 +11,21 @@ let b:current_syntax = "arctic"
|
||||||
syntax match arcticComment "\v#.*$"
|
syntax match arcticComment "\v#.*$"
|
||||||
highlight link arcticComment Comment
|
highlight link arcticComment Comment
|
||||||
|
|
||||||
syntax region arcticData start=/'/ end=/'/
|
syntax region arcticEmbed start=/'/ end=/'/
|
||||||
highlight link arcticData Character
|
highlight link arcticEmbed Character
|
||||||
|
|
||||||
syntax region arcticSection start=/"/ end=/"/
|
syntax region arcticSection start=/"/ end=/"/
|
||||||
highlight link arcticSection PreProc
|
highlight link arcticSection PreProc
|
||||||
|
|
||||||
|
syntax region arcticData keepend start=/\c"data"/ end=/"/ contains=arcticData.*,arcticLabel,arcticSection
|
||||||
|
syntax region arcticCode keepend start=/\c"code"/ end=/"/ contains=arcticCode.*,arcticLabel,arcticCall,arcticConstant,arcticSection
|
||||||
|
|
||||||
|
syntax match arcticDataImmediate "\v[][a-zA-Z0-9_]([^ ]|\\ )*"
|
||||||
|
highlight link arcticDataImmediate Statement
|
||||||
|
|
||||||
|
syntax match arcticDataOperator "\v[-.+*/%\|;&^!?()]"
|
||||||
|
highlight link arcticDataOperator Operator
|
||||||
|
|
||||||
syntax match arcticLabel "\v:[^ ]*"
|
syntax match arcticLabel "\v:[^ ]*"
|
||||||
highlight link arcticLabel Label
|
highlight link arcticLabel Label
|
||||||
|
|
||||||
|
@ -26,8 +35,8 @@ highlight link arcticCall Function
|
||||||
syntax match arcticConstant "\v\$[^ ]*"
|
syntax match arcticConstant "\v\$[^ ]*"
|
||||||
highlight link arcticConstant Constant
|
highlight link arcticConstant Constant
|
||||||
|
|
||||||
syntax match arcticImmediate "\v[][0EFGHLMPQTdou$@<{=}>,`][^ ]*"
|
syntax match arcticCodeImmediate "\v[][0EFGHLMPQTdou@<{=}>,`]([^ ]|\\ )*"
|
||||||
highlight link arcticImmediate Statement
|
highlight link arcticCodeImmediate Statement
|
||||||
|
|
||||||
syntax match arcticOperator "\v[-123456789ABCDIJKNORSUVWXYZabcefghijklmnpqrstvwxyz_.+*/%\|;&^!?()]"
|
syntax match arcticCodeOperator "\v[-123456789ABCDIJKNORSUVWXYZabcefghijklmnpqrstvwxyz_.+*/%\|;&^!?()]"
|
||||||
highlight link arcticOperator Operator
|
highlight link arcticCodeOperator Operator
|
||||||
|
|
|
@ -1,3 +1,37 @@
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "architectures.h"
|
#include "architectures.h"
|
||||||
|
|
||||||
#include "arch/x86_64.h"
|
enum Architecture parse_arch(const char *arch) {
|
||||||
|
if (!arch)
|
||||||
|
return ARCH_NATIVE;
|
||||||
|
|
||||||
|
if (!strncmp(arch, "x86_64", 6)) {
|
||||||
|
return ARCH_X86_64;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ARCH_NATIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *archstr(enum Architecture arch) {
|
||||||
|
switch (arch) {
|
||||||
|
case ARCH_NATIVE:
|
||||||
|
return "native";
|
||||||
|
|
||||||
|
case ARCH_INTERPRET:
|
||||||
|
return "interpret";
|
||||||
|
|
||||||
|
case ARCH_X86_64:
|
||||||
|
return "x86_64";
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Architecture getnative() {
|
||||||
|
#ifdef __x86_64__
|
||||||
|
return ARCH_X86_64;
|
||||||
|
#else
|
||||||
|
return ARCH_INTERPRET;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
|
@ -2,7 +2,17 @@
|
||||||
#define ARCHITECTURES_H
|
#define ARCHITECTURES_H
|
||||||
|
|
||||||
enum Architecture {
|
enum Architecture {
|
||||||
ARCH_NATIVE
|
ARCH_NATIVE,
|
||||||
|
ARCH_INTERPRET,
|
||||||
|
|
||||||
|
ARCH_X86_64
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* when given a null pointer, defaults to ARCH_NATIVE */
|
||||||
|
enum Architecture parse_arch(const char *arch);
|
||||||
|
|
||||||
|
const char *archstr(enum Architecture arch);
|
||||||
|
|
||||||
|
enum Architecture getnative();
|
||||||
|
|
||||||
#endif /* ARCHITECTURES_H */
|
#endif /* ARCHITECTURES_H */
|
||||||
|
|
53
src/arctic.h
Normal file
53
src/arctic.h
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
#ifndef ARCTIC_H
|
||||||
|
#define ARCTIC_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
enum ArcticVariableIndex {
|
||||||
|
VARIABLE_A = 0, VARIABLE_B, VARIABLE_C,
|
||||||
|
VARIABLE_I, VARIABLE_N,
|
||||||
|
VARIABLE_X, VARIABLE_Y, VARIABLE_Z,
|
||||||
|
VARIABLE_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ArcticImmediateKind {
|
||||||
|
PLAIN_IMMEDIATE, VARIABLE_IMMEDIATE, INTEGER_IMMEDIATE, NUMERIC_IMMEDIATE, SYMBOLIC_IMMEDIATE
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ArcticImmediate {
|
||||||
|
enum ArcticImmediateKind kind;
|
||||||
|
union {
|
||||||
|
enum ArcticVariableIndex v;
|
||||||
|
int64_t i;
|
||||||
|
double n;
|
||||||
|
const char *s;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ArcticOperation {
|
||||||
|
char code;
|
||||||
|
uint8_t bigendian;
|
||||||
|
struct ArcticImmediate immediate;
|
||||||
|
};
|
||||||
|
|
||||||
|
union ArcticType {
|
||||||
|
int8_t b;
|
||||||
|
uint8_t ub;
|
||||||
|
int16_t s;
|
||||||
|
uint16_t us;
|
||||||
|
int32_t w;
|
||||||
|
uint32_t uw;
|
||||||
|
int64_t i;
|
||||||
|
uint64_t u;
|
||||||
|
double d;
|
||||||
|
uint8_t *p;
|
||||||
|
struct ArcticOperation *f;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ArcticState {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
int parse_arctic(struct ArcticState *state, const char *arctic);
|
||||||
|
|
||||||
|
#endif /* ARCTIC_H */
|
25
src/args.c
25
src/args.c
|
@ -1,10 +1,29 @@
|
||||||
#include "args.h"
|
#include "args.h"
|
||||||
|
|
||||||
#include <argp.h>
|
#include <argp.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
static int parse_opt(int key, char *arg, struct argp_state *state) {
|
static int parse_opt(int key, char *arg, struct argp_state *state) {
|
||||||
switch (key) {
|
struct Arguments *args = state->input;
|
||||||
|
|
||||||
|
switch (key) {
|
||||||
|
case 'i':
|
||||||
|
args->behaviour = BEHAVIOUR_INTERPRET;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case 'j':
|
||||||
|
args->behaviour = BEHAVIOUR_JIT;
|
||||||
|
args->jit.arch = parse_arch(arg);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case 'a':
|
||||||
|
args->behaviour = BEHAVIOUR_ASM;
|
||||||
|
args->assemble.arch = parse_arch(arg);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case ARGP_KEY_ARG:
|
||||||
|
strncpy(args->program, arg, PATH_MAX);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -21,5 +40,7 @@ int parse_arguments(struct Arguments *args, int argc, char *argv[]) {
|
||||||
const char *args_doc = "PROGRAM";
|
const char *args_doc = "PROGRAM";
|
||||||
|
|
||||||
struct argp argp = { options, parse_opt, args_doc, 0, 0, 0 };
|
struct argp argp = { options, parse_opt, args_doc, 0, 0, 0 };
|
||||||
return argp_parse(&argp, argc, argv, 0, 0, args);
|
int result;
|
||||||
|
argp_parse(&argp, argc, argv, 0, &result, args);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
#include "architectures.h"
|
#include "architectures.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <linux/limits.h>
|
||||||
|
|
||||||
enum Behaviour {
|
enum Behaviour {
|
||||||
BEHAVIOUR_INTERPRET,
|
BEHAVIOUR_INTERPRET,
|
||||||
|
@ -13,12 +13,13 @@ enum Behaviour {
|
||||||
|
|
||||||
struct Arguments {
|
struct Arguments {
|
||||||
enum Behaviour behaviour;
|
enum Behaviour behaviour;
|
||||||
FILE *program;
|
char program[PATH_MAX + 1];
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
} interpret;
|
} interpret;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
enum Architecture arch;
|
||||||
} jit;
|
} jit;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
|
301
src/critbit.c
Normal file
301
src/critbit.c
Normal file
|
@ -0,0 +1,301 @@
|
||||||
|
#include "critbit.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
struct CritBitNode {
|
||||||
|
unsigned int isleaf:1;
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
unsigned int byte:31;
|
||||||
|
uint8_t others;
|
||||||
|
struct CritBitNode *left; /* lefts are 0s */
|
||||||
|
struct CritBitNode *right; /* rights are 1s */
|
||||||
|
};
|
||||||
|
struct {
|
||||||
|
unsigned int valuelen:31;
|
||||||
|
void *value;
|
||||||
|
char *key;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
void crit_bit_init(struct CritBitTree *tree, void (*free_data)(void *data, int datalen)) {
|
||||||
|
if (!tree) return;
|
||||||
|
|
||||||
|
tree->count = 0;
|
||||||
|
tree->root = 0;
|
||||||
|
tree->free_data = free_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void free_node(void (*free_data)(void *data, int datalen), struct CritBitNode *node) {
|
||||||
|
if (!node) return;
|
||||||
|
if (node->isleaf) {
|
||||||
|
if (free_data)
|
||||||
|
free_data(node->value, node->valuelen);
|
||||||
|
free(node->key);
|
||||||
|
free(node);
|
||||||
|
} else {
|
||||||
|
free_node(free_data, node->left);
|
||||||
|
free_node(free_data, node->right);
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void crit_bit_free(struct CritBitTree *tree) {
|
||||||
|
if (tree->root)
|
||||||
|
free_node(tree->free_data, tree->root);
|
||||||
|
|
||||||
|
tree->root = 0;
|
||||||
|
tree->count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct CritBitNode *makeleaf(const char *key, size_t keylen, void *data, int datalen) {
|
||||||
|
struct CritBitNode *leaf = malloc(sizeof *leaf);
|
||||||
|
if (!leaf)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
leaf->key = malloc(keylen + 1);
|
||||||
|
if (!leaf->key) {
|
||||||
|
free(leaf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(leaf->key, key, keylen + 1);
|
||||||
|
leaf->value = data;
|
||||||
|
leaf->valuelen = datalen;
|
||||||
|
leaf->isleaf = 1;
|
||||||
|
|
||||||
|
return leaf;
|
||||||
|
}
|
||||||
|
|
||||||
|
int crit_bit_add(struct CritBitTree *tree, const char *key, void *data, int datalen) {
|
||||||
|
if (!tree) return 0;
|
||||||
|
|
||||||
|
const uint8_t *keybytes = (void*)key;
|
||||||
|
size_t keylen = strlen(key);
|
||||||
|
struct CritBitNode *node = tree->root;
|
||||||
|
|
||||||
|
if (!node) {
|
||||||
|
struct CritBitNode *root = malloc(sizeof *root);
|
||||||
|
root->key = malloc(keylen + 1);
|
||||||
|
strcpy(root->key, key);
|
||||||
|
root->valuelen = datalen;
|
||||||
|
root->value = data;
|
||||||
|
root->isleaf = 1;
|
||||||
|
tree->root = root;
|
||||||
|
tree->count++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (node && !node->isleaf) {
|
||||||
|
uint8_t check = 0;
|
||||||
|
if (node->byte < keylen)
|
||||||
|
check = keybytes[node->byte];
|
||||||
|
if ((node->others | check) == 0xFF)
|
||||||
|
node = node->right;
|
||||||
|
else
|
||||||
|
node = node->left;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!node)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
uint32_t newbyte;
|
||||||
|
uint32_t newothers = ~0; /* sigil for finding existing keys */
|
||||||
|
for (newbyte = 0; newbyte < keylen; ++newbyte) {
|
||||||
|
if (node->key[newbyte] != key[newbyte]) {
|
||||||
|
newothers = node->key[newbyte] ^ key[newbyte];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newothers == ~0) {
|
||||||
|
if (node->key[newbyte] != 0) {
|
||||||
|
newothers = node->key[newbyte];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newothers == ~0) {
|
||||||
|
if (tree->free_data)
|
||||||
|
tree->free_data(node->value, node->valuelen);
|
||||||
|
node->value = data;
|
||||||
|
node->valuelen = datalen;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* bit hacks */
|
||||||
|
while (newothers & (newothers - 1))
|
||||||
|
newothers &= newothers - 1;
|
||||||
|
newothers ^= 0xFF;
|
||||||
|
uint8_t c = node->key[newbyte];
|
||||||
|
int isright = (1 + (newothers | c)) >> 8;
|
||||||
|
|
||||||
|
struct CritBitNode *newnode = malloc(sizeof *newnode);
|
||||||
|
if (!newnode)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
struct CritBitNode *leafnode = makeleaf(key, keylen, data, datalen);
|
||||||
|
if (!leafnode)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
newnode->isleaf = 0;
|
||||||
|
newnode->byte = newbyte;
|
||||||
|
newnode->others = newothers;
|
||||||
|
|
||||||
|
if (isright) {
|
||||||
|
newnode->left = leafnode;
|
||||||
|
} else {
|
||||||
|
newnode->right = leafnode;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CritBitNode **parent = (struct CritBitNode **)&tree->root;
|
||||||
|
for (;;) {
|
||||||
|
struct CritBitNode *here = *parent;
|
||||||
|
if (here->isleaf) break;
|
||||||
|
if (here->byte > newbyte) break;
|
||||||
|
if (here->byte == newbyte && here->others > newothers) break;
|
||||||
|
|
||||||
|
uint8_t c2 = 0;
|
||||||
|
if (here->byte < keylen) c2 = keybytes[here->byte];
|
||||||
|
if ((1 + (here->others | c2)) > 0xFF) {
|
||||||
|
parent = &here->right;
|
||||||
|
} else {
|
||||||
|
parent = &here->left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isright) {
|
||||||
|
newnode->right = *parent;
|
||||||
|
} else {
|
||||||
|
newnode->left = *parent;
|
||||||
|
}
|
||||||
|
*parent = newnode;
|
||||||
|
tree->count++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int crit_bit_has(const struct CritBitTree *tree, const char *key) {
|
||||||
|
if (!tree) return 0;
|
||||||
|
|
||||||
|
const uint8_t *keybytes = (void*)key;
|
||||||
|
size_t keylen = strlen(key);
|
||||||
|
const struct CritBitNode *node = tree->root;
|
||||||
|
|
||||||
|
while (node && !node->isleaf) {
|
||||||
|
uint8_t check = 0;
|
||||||
|
if (node->byte < keylen)
|
||||||
|
check = keybytes[node->byte];
|
||||||
|
if ((node->others | check) == 0xFF)
|
||||||
|
node = node->right;
|
||||||
|
else
|
||||||
|
node = node->left;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node && !strcmp(key, node->key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *crit_bit_get(const struct CritBitTree *tree, const char *key, int *len) {
|
||||||
|
if (!tree) return 0;
|
||||||
|
|
||||||
|
const uint8_t *keybytes = (void*)key;
|
||||||
|
size_t keylen = strlen(key);
|
||||||
|
const struct CritBitNode *node = tree->root;
|
||||||
|
|
||||||
|
while (node && !node->isleaf) {
|
||||||
|
uint8_t check = 0;
|
||||||
|
if (node->byte < keylen)
|
||||||
|
check = keybytes[node->byte];
|
||||||
|
if ((node->others | check) == 0xFF)
|
||||||
|
node = node->right;
|
||||||
|
else
|
||||||
|
node = node->left;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!node) return 0;
|
||||||
|
|
||||||
|
if (len)
|
||||||
|
*len = node->valuelen;
|
||||||
|
return node->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
int crit_bit_del(struct CritBitTree *tree, const char *key) {
|
||||||
|
if (!tree) return 1;
|
||||||
|
|
||||||
|
const uint8_t *keybytes = (void*)key;
|
||||||
|
size_t keylen = strlen(key);
|
||||||
|
struct CritBitNode *node = tree->root;
|
||||||
|
struct CritBitNode *prev = 0;
|
||||||
|
void *tmp = &(tree->root);
|
||||||
|
struct CritBitNode **parent = (struct CritBitNode **)tmp;
|
||||||
|
struct CritBitNode **grandparent = 0;
|
||||||
|
int isright;
|
||||||
|
|
||||||
|
if (!node) return 1;
|
||||||
|
|
||||||
|
while (node && !node->isleaf) {
|
||||||
|
grandparent = parent;
|
||||||
|
uint8_t c = 0;
|
||||||
|
if (node->byte < keylen) c = keybytes[node->byte];
|
||||||
|
isright = ((1 + (node->others | c)) > 0xFF);
|
||||||
|
if (isright) {
|
||||||
|
parent = &node->right;
|
||||||
|
} else {
|
||||||
|
parent = &node->left;
|
||||||
|
}
|
||||||
|
prev = node;
|
||||||
|
node = *parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!node)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (strcmp(key, node->key))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (tree->free_data) tree->free_data(node->value, node->valuelen);
|
||||||
|
free(node->key);
|
||||||
|
free(node);
|
||||||
|
tree->count--;
|
||||||
|
|
||||||
|
if (!grandparent || !prev) {
|
||||||
|
tree->root = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isright) {
|
||||||
|
*grandparent = prev->left;
|
||||||
|
} else {
|
||||||
|
*grandparent = prev->right;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(prev);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int crit_bit_size(const struct CritBitTree *tree) {
|
||||||
|
return tree->count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iterate_node(int (*callback)(const char*,void*,int,void*), void *data, struct CritBitNode *node) {
|
||||||
|
if (!node) return 0;
|
||||||
|
if (node->isleaf) {
|
||||||
|
return callback(node->key, node->value, node->valuelen, data);
|
||||||
|
} else {
|
||||||
|
int r;
|
||||||
|
r = iterate_node(callback, data, node->left);
|
||||||
|
if (r) return r;
|
||||||
|
r = iterate_node(callback, data, node->right);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int crit_bit_foreach(const struct CritBitTree *tree, int (*callback)(const char*,void*,int,void*), void *data) {
|
||||||
|
if (!tree) return 0;
|
||||||
|
if (!tree->root) return 0;
|
||||||
|
if (!callback) return 0;
|
||||||
|
|
||||||
|
return iterate_node(callback, data, tree->root);
|
||||||
|
}
|
19
src/critbit.h
Normal file
19
src/critbit.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef CRITBIT_H
|
||||||
|
#define CRITBIT_H
|
||||||
|
|
||||||
|
struct CritBitTree {
|
||||||
|
void *root;
|
||||||
|
int count;
|
||||||
|
void (*free_data)(void *data, int datalen);
|
||||||
|
};
|
||||||
|
|
||||||
|
void crit_bit_init(struct CritBitTree *tree, void (*free_data)(void *data, int datalen)); /* or just { 0 } if you don't need a free_data */
|
||||||
|
void crit_bit_free(struct CritBitTree *tree); /* a free tree is still initted and can be used */
|
||||||
|
int crit_bit_add(struct CritBitTree *tree, const char *key, void *data, int datalen);
|
||||||
|
int crit_bit_has(const struct CritBitTree *tree, const char *key);
|
||||||
|
void *crit_bit_get(const struct CritBitTree *tree, const char *key, int *len);
|
||||||
|
int crit_bit_del(struct CritBitTree *tree, const char *key);
|
||||||
|
int crit_bit_size(const struct CritBitTree *tree);
|
||||||
|
int crit_bit_foreach(const struct CritBitTree *tree, int (*callback)(const char*,void*,int,void*), void *data); /* returns short-circuit OR of callback value */
|
||||||
|
|
||||||
|
#endif /* CRITBIT_H */
|
|
@ -1,7 +1,4 @@
|
||||||
#include "jit.h"
|
#include "jit.h"
|
||||||
|
|
||||||
#ifdef __x86_64__
|
// #include "arch/x86_64.c"
|
||||||
#include "jit/x86_64.c"
|
// #include "arch/interpret.c"
|
||||||
#else
|
|
||||||
#include "jit/interpret.c"
|
|
||||||
#endif /* architecture */
|
|
||||||
|
|
16
src/jit.h
16
src/jit.h
|
@ -1,7 +1,19 @@
|
||||||
#ifndef JIT_H
|
#ifndef JIT_H
|
||||||
#define JIT_H
|
#define JIT_H
|
||||||
|
|
||||||
/* the implementations must implement this function */
|
#include "architectures.h"
|
||||||
int (*jit(const char *src))(int, char**);
|
|
||||||
|
/* these are what jit functions return */
|
||||||
|
typedef int (*main_func)(int, char**);
|
||||||
|
|
||||||
|
/* the implementations must implement these functions */
|
||||||
|
typedef int (*((*jit)(const char *,int)))(int, char**);
|
||||||
|
|
||||||
|
jit get_implementation(enum Architecture arch);
|
||||||
|
|
||||||
|
/* these are what the asm functions receive */
|
||||||
|
typedef void (*str_func)(const char *, void *);
|
||||||
|
|
||||||
|
void asm_implementation(enum Architecture arch, const char *source, int len, str_func cb, void *data);
|
||||||
|
|
||||||
#endif /* JIT_H */
|
#endif /* JIT_H */
|
||||||
|
|
|
@ -21,7 +21,7 @@ const uint8_t prelude[] = {
|
||||||
// MOV(RBP,RSP)
|
// MOV(RBP,RSP)
|
||||||
};
|
};
|
||||||
|
|
||||||
int (*jit(const char *src))(int, char**) {
|
int (*jit_x86_64(const char *src))(int, char**) {
|
||||||
// TODO: see https://github.com/spencertipping/jit-tutorial
|
// TODO: see https://github.com/spencertipping/jit-tutorial
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
118
src/main.c
118
src/main.c
|
@ -1,14 +1,120 @@
|
||||||
#include <stdio.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
#include <argp.h>
|
#include <argp.h>
|
||||||
|
|
||||||
#include "jit.h"
|
#include "jit.h"
|
||||||
#include "args.h"
|
#include "args.h"
|
||||||
#include "architectures.h"
|
#include "architectures.h"
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
char *read_dynamic(int fd, int *len) {
|
||||||
struct Arguments args;
|
char buf[0x1000];
|
||||||
int rc = parse_arguments(&args, argc, argv);
|
ssize_t n;
|
||||||
|
char *result = 0;
|
||||||
|
*len = 0;
|
||||||
|
while ((n = read(fd, buf, sizeof buf))) {
|
||||||
|
if (n < 0) {
|
||||||
|
if (errno == EAGAIN)
|
||||||
|
continue;
|
||||||
|
perror("read");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
printf("%d\n", rc);
|
char *nresult = realloc(result, *len + n + 1);
|
||||||
return 0;
|
if (!nresult) {
|
||||||
|
free(result);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
result = nresult;
|
||||||
|
memcpy(result + *len, buf, n);
|
||||||
|
*len += n;
|
||||||
|
result[*len] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *read_filename(const char *fname, int *len, int *mapped) {
|
||||||
|
if (fname[0] == '-' && fname[1] == 0) {
|
||||||
|
*mapped = 0;
|
||||||
|
return read_dynamic(0, len);
|
||||||
|
} else {
|
||||||
|
char *result = 0;
|
||||||
|
int fd = open(fname, O_RDONLY);
|
||||||
|
*len = lseek(fd, 0, SEEK_END);
|
||||||
|
if (*len < 0) {
|
||||||
|
/* fallback to dynamic memory */
|
||||||
|
*len = 0;
|
||||||
|
*mapped = 0;
|
||||||
|
result = read_dynamic(fd, len);
|
||||||
|
} else {
|
||||||
|
*mapped = 1;
|
||||||
|
result = mmap(0, *len, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_read_file(char *contents, int len, int mapped) {
|
||||||
|
if (!mapped) {
|
||||||
|
free(contents);
|
||||||
|
} else {
|
||||||
|
munmap(contents, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dump_str(const char *str, void *unused) {
|
||||||
|
puts(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
struct Arguments args = { 0 };
|
||||||
|
int offset = parse_arguments(&args, argc, argv);
|
||||||
|
|
||||||
|
int len;
|
||||||
|
int mapped;
|
||||||
|
char *source = read_filename(args.program, &len, &mapped);
|
||||||
|
int result;
|
||||||
|
|
||||||
|
switch (args.behaviour) {
|
||||||
|
case BEHAVIOUR_INTERPRET: {
|
||||||
|
jit interp = get_implementation(ARCH_INTERPRET);
|
||||||
|
if (!interp) {
|
||||||
|
free_read_file(source, len, mapped);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
main_func interp_main = interp(source, len);
|
||||||
|
free_read_file(source, len, mapped);
|
||||||
|
if (!interp_main) return -1;
|
||||||
|
|
||||||
|
result = interp_main(argc - offset, argv + offset);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case BEHAVIOUR_JIT: {
|
||||||
|
jit jitter = get_implementation(args.jit.arch);
|
||||||
|
if (!jitter) {
|
||||||
|
free_read_file(source, len, mapped);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
main_func jitter_main = jitter(source, len);
|
||||||
|
free_read_file(source, len, mapped);
|
||||||
|
result = jitter_main(argc - offset, argv + offset);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case BEHAVIOUR_ASM:
|
||||||
|
asm_implementation(args.assemble.arch, source, len, dump_str, 0);
|
||||||
|
free_read_file(source, len, mapped);
|
||||||
|
result = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
6
tests/test0.arx
Normal file
6
tests/test0.arx
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#!/usr/bin/env arctic
|
||||||
|
|
||||||
|
# Simple smoke test, ensures shebang, comments, and basic "code" work
|
||||||
|
"code"
|
||||||
|
$0 ;
|
||||||
|
|
Loading…
Reference in a new issue