Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Results 1 to 8 of 8
  1. #1
    Senior Coder jmrker's Avatar
    Join Date
    Aug 2006
    Location
    FL
    Posts
    3,077
    Thanks
    38
    Thanked 498 Times in 492 Posts

    Smile Adding a single-step option to a loop.

    The following is a "just for fun" attempt at controlling some stacks in JS.

    What I would like to know is how to replace the single step logic in the
    "runProgram()" function.

    Currently it uses a confirm() command, but I would like to use something
    else to single-step through the stack actions.
    It causes the screen to darken and put an obtrusive box in the middle of the screen.

    Any recommended changes are welcome.

    Code:
    <!DOCTYPE HTML>
    <html>
    <head>
    <title> Stack Test </title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    
    <style type="text/css">
     #stackDisplay {
      height:100px; width:200px; overflow:auto; margin: 0px 5px;
       background-color:yellow; float:left; border:1px solid black;
     }
     #operandDisplay {
      height:100px; width:200px; overflow:auto; margin: 0px 5px;
      background-color:cyan; float:left; border:1px solid black;
     }
     #program {
      height:100px; width:200px;  margin: 0px 5px;
      background-color:lightblue; float:left; border:1px solid black;
     }
    </style>
    
    </head>
    <body>
    <div id="stackDisplay"></div>
    <div id="operandDisplay"></div>
    <textarea id="program"></textarea>
    <br style="clear:both">
    
    <input type="checkbox" id="SStep"> Single Step <button onclick="runProgram()">Run</button>
    
    <script type="text/javascript">
    function $_(IDS) { return document.getElementById(IDS); }
    
    var TOS = NOS = act = 0;       // TOS=TopOfStack, NOS=NextOnStack
    var stack = [];       var operand = [];
    
    function runProgram() {
      TOS = NOS = act = 0;       // TOS=TopOfStack, NOS=NextOnStack
      stack = [];  operand = [];
      $_('stackDisplay').innerHTML = '';
      $_('operandDisplay').innerHTML = '';
      strToTokens($_('program').value);
      var flag = true;
      while (((operand.length) > 0) && (flag)) {
        act = operand.shift();
        if ('*/+-'.indexOf(act) != -1) { Act2Stack(act) }
        if ('dup,swap,drop'.indexOf(act) != -1) { Act1Stack(act); }
        showStacks();
        if ($_('SStep').checked) { flag = confirm('Next'); }
      }
    }  
    
    function strToTokens(str) {
      var arr = str.split(' ');
      for (var i=0; i<arr.length; i++) {
        if (isNaN(arr[i])) { operand.push(arr[i]); }
                      else { stack.push(arr[i]); }
      }
    }
    function showStacks() {
      $_('stackDisplay').innerHTML = stack.join('<br>');
      $_('operandDisplay').innerHTML = operand.join('<br>');
      return true;
    }
    
    function Act1Stack(act) {
      var tmp;
      switch (act) {
        case 'dup'  : stack.unshift(stack[stack.length-1]); break; 
        case 'swap' : tmp = stack.shift(); TOS = stack.shift();
                      stack.unshift(tmp); stack.unshift(TOS); break; 
        case 'drop' : tmp = stack.shift(); break;
      }
    }
    function Act2Stack(act) {
      TOS = stack.shift()*1;
      NOS = stack.shift()*1;
      switch (act) {
        case '*' : TOS = TOS * NOS; break;
        case '/' : TOS = TOS / NOS; break;
        case '+' : TOS = TOS + NOS; break;
        case '-' : TOS = TOS - NOS; break;
      } stack.unshift(TOS);
    }
    
    // Testing program 
    var str = '';
        str = '123 45 + 3 / 3 - -1 * drop\n';     // -53
        str += '123 45 swap - 3 / 3 + -1 * dup';  //  23
        $_('program').value = str.replace(/\n/g,' ');
    
    </script>
    
    </body>
    </html>

  • #2
    Senior Coder Dormilich's Avatar
    Join Date
    Jan 2010
    Location
    Behind the Wall
    Posts
    3,253
    Thanks
    12
    Thanked 341 Times in 337 Posts
    If it were not switchable, I’d just use something like an iterator (similar to the PHP Iterators) where you tie the call to next() to a button click event.
    The computer is always right. The computer is always right. The computer is always right. Take it from someone who has programmed for over ten years: not once has the computational mechanism of the machine malfunctioned.
    André Behrens, NY Times Software Developer

  • #3
    Master Coder felgall's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, Australia
    Posts
    6,627
    Thanks
    0
    Thanked 648 Times in 638 Posts
    You could override the built in confirm function with your own version that does what you want it to do.
    Stephen
    Learn Modern JavaScript - http://javascriptexample.net/
    Helping others to solve their computer problem at http://www.felgall.com/

    Don't forget to start your JavaScript code with "use strict"; which makes it easier to find errors in your code.

  • #4
    Regular Coder
    Join Date
    Jan 2013
    Location
    Germany
    Posts
    578
    Thanks
    4
    Thanked 77 Times in 77 Posts
    I may be wrong, but I think the question was more about how to "pause" the loop so that the user can see what's going on(?). If that's so, the question just depends on how you want to present it to the user. You could use a timeout (which would give the user only a certain time, no confirmation feedback needed/possible) or you could use a "Next Step" button, which I'd prefer.
    If you use a button, you can pretty much get rid of the loop altogether and simply reduce it to an if statement.

    By the way: If you need comments to explain what variables are for, you are likely to have named them wrong. Just name them "topofStack" and "nextOnStack" – you can remove pointcless, repeated comments and make the code more readable.

  • #5
    Supreme Master coder! Philip M's Avatar
    Join Date
    Jun 2002
    Location
    London, England
    Posts
    17,919
    Thanks
    203
    Thanked 2,531 Times in 2,509 Posts
    Quote Originally Posted by Airblader View Post
    By the way: If you need comments to explain what variables are for, you are likely to have named them wrong. Just name them "topofStack" and "nextOnStack" – you can remove pointcless, repeated comments and make the code more readable.
    I am afraid that I do not agree. TOS and NOS seem eminently appropriate abbreviations to me, as the comments explain them very clearly.

    TOS (or topOfStack) occurs 11 times in the code. Apart from the extra typing required (77 characters) there arises the risk of typo errors such as topofStack instead of topOfStack. (Assuming you want consistency with NextOnStack). Not pointcless at all.

    All the code given in this post has been tested and is intended to address the question asked.
    Unless stated otherwise it is not just a demonstration.

  • #6
    Regular Coder
    Join Date
    Jan 2013
    Location
    Germany
    Posts
    578
    Thanks
    4
    Thanked 77 Times in 77 Posts
    If you care about a few characters, there is always minification I'd rather have my code document itself than having to document it manually, which introduces the risk of rotting comments that are incomplete, not precise and ultimatively simply wrong. Risks, that my IDE cannot protect me from – unlike typos which are virtually inexistent these days with code-completion and all that stuff.

    Comments, if used, should explain the code, not explain the name I'm giving to variables. And If it wasn't for the comments, it would've at least taken me some time to figure out what NOS and TOS are meant to represent.

    A comment that has gotten old, irrelevant, and incorrect is obsolete. Comments get old quickly. It is best not to write a comment that will become obsolete. If you find an obsolete comment, it is best to update it or get rid of it as quickly as possible. Obsolete comments tend to migrate away from the code they once described. They become floating islands of irrelevance and misdirection in the code. – Robert C. Martin
    (Source)

    If a name requires a comment; change the name
    (Source, slide 5 of 43)

    However, I know that to an extent this is a matter of habit and taste. By the way, Philip, I know you're not a friend of lengthy names. I wonder what you'd think if you were to read through our code at work with test function names like

    Code:
    @Test
    public void givenSomeDescriptionOfTheScenarioWhenSomeActionIsTakenThenCompareInputAndOutputToHaveTheExpectedValuesAndStructure () { 
       [...] 
    }
    (Edit: Maybe I should add that I'm not exactly a fan of these super-long names either, but they tend to be really useful when debugging tests)

    And you don't need to be afraid to disagree. I, for once, could live with both naming methods. I was just pointing out my preferences. Descriptive names versus too long names sure isn't always an easy topic for me either.
    Last edited by Airblader; 03-04-2013 at 05:39 PM.

  • #7
    Supreme Master coder! Philip M's Avatar
    Join Date
    Jun 2002
    Location
    London, England
    Posts
    17,919
    Thanks
    203
    Thanked 2,531 Times in 2,509 Posts
    Quote Originally Posted by Airblader View Post
    (Edit: Maybe I should add that I'm not exactly a fan of these super-long names either, but they tend to be really useful when debugging tests)

    And you don't need to be afraid to disagree. I, for once, could live with both naming methods. I was just pointing out my preferences. Descriptive names versus too long names sure isn't always an easy topic for me either.
    Same as before. You work in an environment where other people have to understand your code with ease, and perhaps modify it, and vice-versa. The only person who has to understand my code is myself.

    My policy is that names should be short, as short as is convenient, but still meaningful. Say uname for user name, dy for day and mth for month, but still pretty obvious. Not something impenetrable like a, fred or xyz. I don't indent for the reason I have already explained, but usually leave blank lines before/after loops, between functions etc. I grew up in an environment where variable names had to be as short as possible to save precious bytes - you could not afford lengthy names such as your test functions.

    All the code given in this post has been tested and is intended to address the question asked.
    Unless stated otherwise it is not just a demonstration.

  • #8
    Senior Coder jmrker's Avatar
    Join Date
    Aug 2006
    Location
    FL
    Posts
    3,077
    Thanks
    38
    Thanked 498 Times in 492 Posts

    Thumbs up

    @Airblader: Thank you. The change to an if statement did the trick. I was able to view the changes without the shading and placement of the alert message.

    @Philip M: Thank you for the short variable name defense. I, too, was brought up in an environment of limited memory.
    So long as the variable name is defined (commented?) somewhere, I have no problems understanding the meaning.

    The longer variable names are useful and I can see the benefit of their use in more complicated programs.
    MY problem with them is it gives me more opportunities to make spelling mistakes.

    This was just an attempt at a FORTH style language using javascript as a RPN calculator, so for that reason I was keeping the variable names short.

    @felgall: Would you have a short example of how a function could be created to overwrite the confirmation function?
    I tried something like that but could not figure out how to use it without an infinite pause waiting for the operator to enter something.

    My current logic for the single-step action was a change along this line...
    Code:
    var SSflag = false;
    function RUN() {
      if ( !SSflag ) {
        TOS = NOS = act = 0;
        stack = [];  operand = [];
        $_('stackDisplay').innerHTML = '';
        $_('operandDisplay').innerHTML = '';
        strToTokens($_('program').value);
      } runProgram();
    }
    function runProgram() {
      if ($_('SStep').checked) { SSflag = true;
        if ((stack.length > 0) && (operand.length >= 0)) {
          showStacks();  act = operand.shift();  takeAction(act);
        } else { alert('End of Program'); } // SSflag = false;}
      } else {  SSflag = false;    // run program at full speed
        while (operand.length > 0) { takeAction(operand.shift()); }  showStacks();
      }
    }
    I can provide the rest of the code for anyone interested, but the crux of the probem (single step vs full speed)
    is solved in the runProgram() function above.


  •  

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •