6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Jul 06, 2024 4:50 pm

All times are UTC




Post new topic Reply to topic  [ 14 posts ] 
Author Message
 Post subject: C02 - Select statement
PostPosted: Tue Feb 06, 2018 4:21 am 
Offline

Joined: Thu Feb 10, 2011 3:14 am
Posts: 79
See thread http://forum.6502.org/viewtopic.php?f=2&t=5066 for background.

When I originally tried to implement the switch statement in C02, I found that allowing fall through between case blocks generated code that was no more efficient than multiple if/then/else blocks.

Last night I realized that if each case block automatically terminated the switch, then each case statement could be a simple CMP and BNE.

My biggest concern was that deviating from the standard behavior of switch would cause confusion, and easily lead to mistakes in code.

I finally decided to use the keyword select instead. The syntax is identical to C's switch statement, however there is an implied break of the switch at the end of each case.

The updated code has been merged into branch master at https://github.com/RevCurtisP/C02


Top
 Profile  
Reply with quote  
PostPosted: Tue Feb 06, 2018 4:25 am 
Offline

Joined: Thu Feb 10, 2011 3:14 am
Posts: 79
Right now, a break statement inside a case or default block will exit the surrounding do, while, or for loop.

I'm thinking I should probably change this to exit out of the select block. instead, to allow premature termination of the case or default block.


Top
 Profile  
Reply with quote  
PostPosted: Tue Feb 06, 2018 4:37 am 
Offline

Joined: Thu Feb 10, 2011 3:14 am
Posts: 79
Here is a sample select statement
Code:
select (c) {
    case 0: //case block
    case 1: //case block
    case 3: //case block
    case 6: //case block
    case 10: //case block
    case 'A': //case block
    default: //default block
}

and the generated code
Code:
        LDA C          ;SELECT (C
        CMP #$00         ;) { CASE 0
        BNE L_0005       ;:
        //case block
        JMP L_0004       ;CASE
L_0005: CMP #$01         ;1
        BNE L_0007       ;:
        //case block
        JMP L_0004       ;CASE
L_0007: CMP #$03         ;3
        BNE L_0009       ;:
        //case block
        JMP L_0004       ;CASE
L_0009: CMP #$06         ;6
        BNE L_0011       ;:
        //case block
        JMP L_0004       ;CASE
L_0011: CMP #$0A         ;10
        BNE L_0013       ;:
        //case block
        JSR PUTLN        ;);
        JMP L_0004       ;CASE
L_0013: CMP #$41         ;'A'
        BNE L_0015       ;:
        //case block
        JMP L_0004       ;DEFAULT:
L_0015: //default block
L_0004:                  ;}



Top
 Profile  
Reply with quote  
PostPosted: Tue Feb 06, 2018 4:45 am 
Offline

Joined: Thu Feb 10, 2011 3:14 am
Posts: 79
It would be trivial to allow multiple arguments to a case statement, so that the C construct
Code:
switch (c) {
    case 1:
    case 2:
        //cases 1 or 2
       break;
    case 3:
        //case 3
       break;
    default:
        //everything else
}

would look like this in C02
Code:
select (c) {
    case 1,2:
        //cases 1 or 2
    case 3:
        //case 3
    default:
        //everything else
}


Does that seam reasonable?


Top
 Profile  
Reply with quote  
PostPosted: Tue Feb 06, 2018 5:30 am 
Offline
User avatar

Joined: Mon May 12, 2014 6:18 pm
Posts: 365
Just a few observations. I think if you are making something not C compatible, you should use whatever syntax you like. If you wanted to optimize a little, you could check if any of the cases are zero and put that case first so you can skip the CMP #00, since LDA sets the zero flag. If case 1 and 2 do the same thing, you might be able to do one CMP #03 followed by one BMI for case 1 and 2 followed by a BEQ for case 3. A few checks like that might make the code you generate a little smaller and faster.

Keep up the good work!


Top
 Profile  
Reply with quote  
PostPosted: Tue Feb 06, 2018 7:44 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10838
Location: England
I think a syntax for handling multiple matches is a good idea, and makes it a bit closer to C.


Top
 Profile  
Reply with quote  
PostPosted: Tue Feb 06, 2018 11:24 am 
Offline
User avatar

Joined: Tue Oct 25, 2016 8:56 pm
Posts: 360
Quote:
My biggest concern was that deviating from the standard behavior of switch would cause confusion, and easily lead to mistakes in code.


I don't think its that big an issue, but using a different keyword is probably still wise so people don't just C&P a block of normal C code and not be aware of the differing semantics

Having said that, structures like this are actually quite common - the entire Visual Basic line (all the way up to VB.Net 2017 or whatever the latest version is) has a Select Case statement that uses exactly these semantics, including implied break on next case. A lot of more modern languages like Go and Rust also eschew fall-through; the argument being that "forgetting a break" is very common and causes many bugs, but the flexibility of allowing fall-through is useful only occassionally.

VB.Net e.g.

Code:
    Public Function WhatNumber(ByRef Number As Integer)
        Select Case Number
            Case 1
                MsgBox("1")
            Case 2, 3
                MsgBox("> 1, < 4
            Case Else
                MsgBox("> 3")
        End Select
    End Function

_________________
Want to design a PCB for your project? I strongly recommend KiCad. Its free, its multiplatform, and its easy to learn!
Also, I maintain KiCad libraries of Retro Computing and Arduino components you might find useful.


Top
 Profile  
Reply with quote  
PostPosted: Tue Feb 06, 2018 8:27 pm 
Offline

Joined: Sat Jun 04, 2016 10:22 pm
Posts: 483
Location: Australia
The select case was also in QBASIC/QuickBASIC. I don't think it was in GW-BASIC/BASICA, though.


Top
 Profile  
Reply with quote  
PostPosted: Wed Feb 07, 2018 12:55 am 
Offline

Joined: Tue Jul 24, 2012 2:27 am
Posts: 672
If you can have "goto"s inside the select block, that would let the user manually enable fall through and tail sharing only in cases where they explicitly need it.

_________________
WFDis Interactive 6502 Disassembler
AcheronVM: A Reconfigurable 16-bit Virtual CPU for the 6502 Microprocessor


Top
 Profile  
Reply with quote  
PostPosted: Wed Feb 07, 2018 1:45 am 
Offline

Joined: Thu Feb 10, 2011 3:14 am
Posts: 79
White Flame wrote:
If you can have "goto"s inside the select block, that would let the user manually enable fall through and tail sharing only in cases where they explicitly need it.

There's nothing preventing that. It's possible to goto in and out of any type of control structure.

EDIT: I just wrote a test case veriifying that this works.
Code:
for (c=5; c<=9; c++) {
  prbyte(c);
  putc(' ');
  select (c) {
    case 9:
      puts("WORKING NINE TO ");
      goto five;
    case 5:
      five: putln("FIVE");
    default: putln("*");
  }
}

which resulted in
Code:
05 FIVE
06 *
07 *
08 *
09 WORKING NINE TO FIVE


Top
 Profile  
Reply with quote  
PostPosted: Wed Feb 07, 2018 2:46 am 
Offline

Joined: Thu Feb 10, 2011 3:14 am
Posts: 79
Druzyek wrote:
you could check if any of the cases are zero and put that case first so you can skip the CMP #00, since LDA sets the zero flag.
I modified the code so that if the first argument of the first case is 0, the initial CMP is skipped.

Druzyek wrote:
If case 1 and 2 do the same thing, you might be able to do one CMP #03 followed by one BMI for case 1 and 2 followed by a BEQ for case 3.
Instead of this, I'm thinking a special argument type, <TERM which would generate a BCS to jump over the case block. Maybe a >TERM as well, but that would be a little more complicated.

Druzyek wrote:
Keep up the good work!
Thanks.


Top
 Profile  
Reply with quote  
PostPosted: Wed Feb 07, 2018 2:49 am 
Offline

Joined: Thu Feb 10, 2011 3:14 am
Posts: 79
BigEd wrote:
I think a syntax for handling multiple matches is a good idea, and makes it a bit closer to C.

I added multiple arguments to a case, separated by commas.


Top
 Profile  
Reply with quote  
PostPosted: Wed Feb 07, 2018 4:29 am 
Offline

Joined: Thu Feb 10, 2011 3:14 am
Posts: 79
I found and fixed a bug with if's inside a case statement and updated branch "master", then I created branch "break-case" and modified the code so that a break statement will exit out of the select instead of the surrounding loop.

I think I'm done for the night.


Top
 Profile  
Reply with quote  
PostPosted: Thu Feb 08, 2018 9:53 pm 
Offline

Joined: Thu Feb 10, 2011 3:14 am
Posts: 79
I merged the break-case branch into master on GitHUb last night, so a break statement inside a case will now exit theselect.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 14 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 15 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron