lilo_booter

OpenJScad RPN Hacking v3

May 8th, 2016
116
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. function stack( )
  2. {
  3.     this.inner = [ ];
  4.     this.rstack = [ ];
  5.  
  6.     this.words = { };
  7.     this.parsers = { };
  8.  
  9.     this.parsing = "";
  10.  
  11.     this.floating = /^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$/;
  12.  
  13.     this.define = function( name, func, parsing )
  14.     {
  15.         this.parsers[ name ] = parsing != null && parsing;
  16.         if ( typeof( func ) == "function" )
  17.             this.words[ name ] = func;
  18.         else if ( typeof( func ) == "string" )
  19.             this.words[ name ] = func.split( " " );
  20.         else
  21.             this.words[ name ] = func;
  22.         return this;
  23.     }
  24.  
  25.     this.parse = function( input )
  26.     {
  27.         return this.run( input.split( " " ) );
  28.     }
  29.  
  30.     this.clear_parser = function( )
  31.     {
  32.         this.parsing = "";
  33.     }
  34.  
  35.     this.run = function( words )
  36.     {
  37.         if ( words != null )
  38.             for ( var index in words )
  39.                 this.push( words[ index ] );
  40.         return this;
  41.     }
  42.  
  43.     this.push = function( object )
  44.     {
  45.         if ( this.parsing == "" && typeof( object ) == "string" && object in this.parsers && this.parsers[ object ] )
  46.         {
  47.             this.inner.push( object );
  48.             this.parsing = object;
  49.         }
  50.         else if ( this.parsing != "" )
  51.         {
  52.             this.inner.push( object );
  53.             object = this.parsing;
  54.         }
  55.  
  56.         if ( typeof( object ) == "string" && object in this.words && typeof( this.words[ object ] ) == "function" )
  57.             this.words[ object ]( this.inner, this.rstack );
  58.         else if ( typeof( object ) == "string" && object in this.words )
  59.             this.run( this.words[ object ] );
  60.         else if ( typeof( object ) == "string" && this.floating.exec( object ) )
  61.             this.inner.push( parseFloat( object ) );
  62.         else
  63.             this.inner.push( object );
  64.  
  65.         return this;
  66.     }
  67.  
  68.     this.pop = function( )
  69.     {
  70.         return this.inner.pop( );
  71.     }
  72. }
  73.  
  74. function grammar( )
  75. {
  76.     var parser = new stack( );
  77.  
  78.     // Return parser with defined words
  79.     return parser
  80.  
  81.     // Basic maths
  82.     .define( "*", function( s ) { s.push( s.pop( ) * s.pop( ) ); } )
  83.     .define( "+", function( s ) { s.push( s.pop( ) + s.pop( ) ); } )
  84.     .define( "-", function( s ) { var a = s.pop( ); s.push( s.pop( ) - a ); } )
  85.     .define( "/", function( s ) { var a = s.pop( ); s.push( s.pop( ) / a ); } )
  86.     .define( "%", function( s ) { var a = s.pop( ); s.push( s.pop( ) % a ); } )
  87.     .define( "float", function( s ) { s.push( parseFloat( s.pop( ) ) ); } )
  88.     .define( "int", function( s ) { s.push( parseInt( s.pop( ) ) ); } )
  89.  
  90.     // Bitwise operators
  91.     .define( "&", function( s ) { s.push( parseInt( s.pop( ) ) & parseInt( s.pop( ) ) ) } )
  92.     .define( "|", function( s ) { s.push( parseInt( s.pop( ) ) | parseInt( s.pop( ) ) ) } )
  93.     .define( "^", function( s ) { s.push( parseInt( s.pop( ) ) ^ parseInt( s.pop( ) ) ) } )
  94.     .define( ">>", function( s ) { var a = parseInt( s.pop( ) ); s.push( parseInt( s.pop( ) ) >> a ) } )
  95.     .define( "<<", function( s ) { var a = parseInt( s.pop( ) ); s.push( parseInt( s.pop( ) ) << a ) } )
  96.  
  97.     // Boolean logic
  98.     .define( "true", function( s ) { s.push( true ); } )
  99.     .define( "false", function( s ) { s.push( false ); } )
  100.     .define( "=", function( s ) { s.push( s.pop( ) == s.pop( ) ); } )
  101.     .define( "<", function( s ) { var a = s.pop( ); s.push( s.pop( ) < a ); } )
  102.     .define( ">", function( s ) { var a = s.pop( ); s.push( s.pop( ) > a ); } )
  103.     .define( ">=", function( s ) { var a = s.pop( ); s.push( s.pop( ) >= a ); } )
  104.     .define( "<=", function( s ) { var a = s.pop( ); s.push( s.pop( ) <= a ); } )
  105.     .define( "&&", function( s ) { var a = s.pop( ); s.push( s.pop( ) && a ); } )
  106.     .define( "||", function( s ) { var a = s.pop( ); s.push( s.pop( ) || a ); } )
  107.  
  108.     // General
  109.     .define( "2dup", "1 pick 1 pick" )
  110.     .define( "max", "2dup < if swap then drop" )
  111.     .define( "min", "2dup > if swap then drop" )
  112.  
  113.     // Basic stack manipulations
  114.     .define( "pick", function( s ) { var index = parseInt( s.pop( ) ); s.push( s[ s.length - index - 1 ] ); } )
  115.     .define( "roll", function( s ) { var index = parseInt( s.pop( ) ); var a = s.splice( s.length - index - 1, 1 ); s.push( a[ 0 ] ); } )
  116.     .define( "pack", function( s ) { var length = parseInt( s.pop( ) ); var pack = s.splice( s.length - length, length ); s[ s.length ] = pack; } )
  117.     .define( "drop", function( s ) { s.pop( ); } )
  118.     .define( "depth", function( s ) { s.push( s.length ); } )
  119.  
  120.     // Standard FORTH words
  121.     .define( "dup", "0 pick" )
  122.     .define( "over", "1 pick" )
  123.     .define( "swap", "1 roll" )
  124.  
  125.     // Vector/array words
  126.     .define( "[", function( s, r ) { r.push( s.length ); } )
  127.     .define( "]", function( s, r ) { var start = r.pop( ); parser.push( s.length - start ); parser.push( "pack" ); } )
  128.  
  129.     // Map words
  130.     .define( "{", function( s, r ) { r.push( { } ); } )
  131.     .define( "::", function( s, r ) { var n = s.pop( ); if ( n != "::" ) r[ r.length - 1 ][ n ] = s.pop( ); if ( n != "::" ) parser.clear_parser( ); }, true )
  132.     .define( "@@", function( s ) { var n = s.pop( ); if ( n != "@@" ) s.push( s[ s.length - 1 ][ n ] ); if ( n != "@@" ) parser.clear_parser( ); }, true )
  133.     .define( "}", function( s, r ) { s.push( r.pop( ) ); } )
  134.  
  135.     // Word definitions
  136.     .define( ":", function( s, r )
  137.     {
  138.         function append( r, token )
  139.         {
  140.             // Initialise the state on the return stack
  141.             if ( r.length == 0 || !( "name" in r[ r.length - 1 ] ) )
  142.                 r.push( { name: "", definition: [ ], count: 0 } );
  143.  
  144.             // For convenience, we'll grab a reference to the state here
  145.             var state = r[ r.length - 1 ];
  146.  
  147.             // Deal with : and ; tokens
  148.             if ( token == ":" )
  149.                 state.count ++;
  150.             else if ( token == ";" )
  151.                 state.count --;
  152.  
  153.             // Drop opening :, assign name from first token following opening :, drop closing ;
  154.             if ( token == ":" && state.count == 1 )
  155.                 ;
  156.             else if ( state.count == 1 && state.name == "" )
  157.                 state.name = token;
  158.             else if ( token != ";" || state.count > 0 )
  159.                 state.definition.push( token );
  160.  
  161.             // We are no longer consuming tokens here
  162.             return state.count != 0;
  163.         }
  164.  
  165.         // Keep appending until the closing ';' is encountered (allows nested word definitions)
  166.         if ( !append( r, s.pop( ) ) )
  167.         {
  168.             // Stop parsing
  169.             parser.clear_parser( );
  170.  
  171.             // Define the word
  172.             var state = r.pop( );
  173.             parser.define( state.name, state.definition );
  174.         }
  175.     },
  176.     true )
  177.  
  178.     .define( ";", function( s ) { } )
  179.  
  180.     // Logic branching
  181.     .define( "if", function( s, r )
  182.     {
  183.         function append( r, token )
  184.         {
  185.             // Initialise the state on the return stack
  186.             if ( r.length == 0 || !( "if" in r[ r.length - 1 ] ) )
  187.                 r.push( { if: [ ], else: null, count: 0 } );
  188.  
  189.             // For convenience, we'll grab a reference to the state here
  190.             var state = r[ r.length - 1 ];
  191.  
  192.             // Deal with if/else/then tokens
  193.             if ( token == "if" )
  194.                 state.count ++;
  195.             else if ( token == "else" && state.count == 1 )
  196.                 state.else = [ ];
  197.             else if ( token == "then" )
  198.                 state.count --;
  199.  
  200.             if ( token == "if" && state.if.length == 0 )
  201.                 ;
  202.             else if ( state.else == null )
  203.                 state.if.push( token );
  204.             else
  205.                 state.else.push( token );
  206.  
  207.             // We are no longer consuming tokens here
  208.             return state.count != 0;
  209.         }
  210.  
  211.         // Keep appending until the closing 'then' is encountered
  212.         if ( !append( r, s.pop( ) ) )
  213.         {
  214.             // Stop parsing
  215.             parser.clear_parser( );
  216.  
  217.             // Execute the correct part of the condition
  218.             parser.run( s.pop( ) ? r.pop( ).if : r.pop( ).else );
  219.         }
  220.     },
  221.     true )
  222.  
  223.     .define( "else", function( s ) { } )
  224.     .define( "then", function( s ) { } )
  225.  
  226.     // Loops
  227.     .define( "do", function( s, r )
  228.     {
  229.         function append( r, token )
  230.         {
  231.             // Initialise the state on the return stack
  232.             if ( r.length == 0 || !( "loop" in r[ r.length - 1 ] ) )
  233.                 r.push( { loop: [ ], count: 0 } );
  234.  
  235.             // For convenience, we'll grab a reference to the state here
  236.             var state = r[ r.length - 1 ];
  237.  
  238.             // Deal with : and ; tokens
  239.             if ( token == "do" )
  240.                 state.count ++;
  241.             else if ( token == "loop" || token == "+loop" )
  242.                 state.count --;
  243.  
  244.             // Drop opening do
  245.             if ( token == "do" && state.count == 1 )
  246.                 ;
  247.             else
  248.                 state.loop.push( token );
  249.  
  250.             // We are no longer consuming tokens here
  251.             return state.count != 0;
  252.         }
  253.  
  254.         // Create the index stack if necessary
  255.         if ( !( "istack" in parser ) )
  256.             parser.istack = [ ];
  257.  
  258.         // Keep appending until the closing 'loop' is encountered (allows nested do loops)
  259.         if ( !append( r, s.pop( ) ) )
  260.         {
  261.             // Stop parsing
  262.             parser.clear_parser( );
  263.  
  264.             // Run the loop
  265.             var i = s.pop( );
  266.             var end = s.pop( );
  267.             var state = r.pop( );
  268.  
  269.             while( i < end )
  270.             {
  271.                 parser.istack.push( i );
  272.                 parser.run( state.loop );
  273.                 i = parser.istack.pop( );
  274.             }
  275.         }
  276.     },
  277.     true )
  278.  
  279.     .define( "i", function( s ) { s.push( parser.istack[ parser.istack.length - 1 ] ); } )
  280.     .define( "loop", function( s ) { parser.istack.push( parser.istack.pop( ) + 1 ); } )
  281.     .define( "+loop", function( s ) { parser.istack.push( parser.istack.pop( ) + s.pop( ) ); } )
  282.  
  283.     // Comments
  284.     .define( "(", function( s, r )
  285.     {
  286.         function append( r, token )
  287.         {
  288.             // Initialise the state on the return stack
  289.             if ( r.length == 0 || !( "count" in r[ r.length - 1 ] ) )
  290.                 r.push( { count: 0 } );
  291.  
  292.             // For convenience, we'll grab a reference to the state here
  293.             var state = r[ r.length - 1 ];
  294.  
  295.             // Deal with : and ; tokens
  296.             if ( token == "(" )
  297.                 state.count ++;
  298.             else if ( token == ")" )
  299.                 state.count --;
  300.  
  301.             // We are no longer consuming tokens here
  302.             return state.count != 0;
  303.         }
  304.  
  305.         // Keep appending until the closing ')' is encountered (allows nested comments loops)
  306.         if ( !append( r, s.pop( ) ) )
  307.         {
  308.             // Stop parsing
  309.             parser.clear_parser( );
  310.         }
  311.     },
  312.     true )
  313.  
  314.     .define( ")", function( s ) { } )
  315.  
  316.     // OpenJSCad words
  317.     .define( "cube", function( s ) { s.push( cube( s.pop( ) ) ); } )
  318.     .define( "cylinder", function( s ) { s.push( cylinder( s.pop( ) ) ); } )
  319.     .define( "sphere", function( s ) { s.push( sphere( s.pop( ) ) ); } )
  320.     .define( "torus", function( s ) { s.push( torus( s.pop( ) ) ); } )
  321.     .define( "union", function( s ) { var a = s.pop( ); s.push( union( s.pop( ), a ) ); } )
  322.     .define( "difference", function( s ) { var a = s.pop( ); s.push( difference( s.pop( ), a ) ); } )
  323.     .define( "intersection", function( s ) { var a = s.pop( ); s.push( intersection( s.pop( ), a ) ); } )
  324.     .define( "translate", function( s ) { var a = s.pop( ); s.push( s.pop( ).translate( a ) ); } )
  325.     .define( "scale", function( s ) { var a = s.pop( ); s.push( s.pop( ).scale( a ) ); } )
  326.     .define( "mirroredX", function( s ) { s.push( s.pop( ).mirroredX( ) ); } )
  327.     .define( "mirroredY", function( s ) { s.push( s.pop( ).mirroredY( ) ); } )
  328.     .define( "mirroredZ", function( s ) { s.push( s.pop( ).mirroredZ( ) ); } )
  329.  
  330.     // Debug
  331.     .define( "dump", function( s ) { echo( "dump: " + s ); } )
  332.     ;
  333. }
  334.  
  335. function main( )
  336. {
  337.     return grammar( )
  338.     .parse( "{ 30 :: size true :: center } cube" )
  339.     .parse( "{ 20 :: r true :: center } sphere" )
  340.     .parse( "difference" )
  341.     .parse( "{ 13 :: r true :: center } sphere" )
  342.     .parse( "{ 21 :: size true :: center } cube" )
  343.     .parse( "intersection" )
  344.     .parse( "union" )
  345.     .parse( "[ 0 0 15 ] translate" )
  346.     .parse( ": plug { [ 0 0 0 ] :: start [ 0 0 10 ] :: end 1 :: r1 2 :: r2 50 :: fn } cylinder ;" )
  347.     .parse( "plug" )
  348.     .parse( "{ } torus" )
  349.     .parse( "union" )
  350.     .parse( "union" )
  351.     .pop( );
  352. }
  353.  
  354. function main( )
  355. {
  356.     return grammar( )
  357.     .parse( "( this is a comment )" )
  358.     .parse( ": join depth 1 do union loop ;" )
  359.     .parse( "10 1 do i cube [ i i i ] translate loop join" )
  360.     .parse( "dup mirroredX join" )
  361.     .parse( "dup mirroredY join" )
  362.     .parse( "dup mirroredZ join" )
  363.     .pop( );
  364. }
Add Comment
Please, Sign In to add comment