6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Thu Oct 03, 2024 11:02 pm

All times are UTC




Post new topic Reply to topic  [ 19 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Tue Aug 01, 2017 10:22 am 
Offline
User avatar

Joined: Wed May 11, 2016 4:15 am
Posts: 24
Location: Texas
Placeholders in assembly: How is it done?

C#
Code:
SomeMethod("Point A[{0},{1}], B[{2},{3}]", a.x, a.y, b.x, b.y)


If you wanted a function that takes a string with placeholders and some data and have it build a new string, would that be complicated?


Top
 Profile  
Reply with quote  
PostPosted: Tue Aug 01, 2017 10:47 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10943
Location: England
Anything's possible - but it does sound like it would take a little thought.

(A more old fashioned example of the same thing would be C's
printf("one: %d two: %d", a, b)
)

First problem: you need to pass a list of parameters, and the 6502 has no simple calling convention. Perhaps some kind of parameter block would work out: set X and Y to the two bytes of the address of the block, and in the block you'd have
- the address of the string
- the values to be inserted, as a list

Then your print routine just walks down the string, printing characters until it sees the formatting character, at which point it calls a subroutine to print the appropriate value.


Top
 Profile  
Reply with quote  
PostPosted: Tue Aug 01, 2017 11:00 am 
Offline
User avatar

Joined: Wed May 11, 2016 4:15 am
Posts: 24
Location: Texas
BigEd wrote:
Anything's possible - but it does sound like it would take a little thought.

(A more old fashioned example of the same thing would be C's
printf("one: %d two: %d", a, b)
)

First problem: you need to pass a list of parameters, and the 6502 has no simple calling convention. Perhaps some kind of parameter block would work out: set X and Y to the two bytes of the address of the block, and in the block you'd have
- the address of the string
- the values to be inserted, as a list

Then your print routine just walks down the string, printing characters until it sees the formatting character, at which point it calls a subroutine to print the appropriate value.


That's almost like what I've come up with, except I didn't think of the second function. I was thinking that I'd have to convert integer values to their ASCII equivalent and that could be another function.

I haven't figured out how to deal with a variable amount of arguments/placeholders. As a side note, I'm trying in x86 before replicating it in 6502.

So are walking through this string, you have be looking for the placeholder strings. I was thinking that you could be looking for "{", and if you find one, you can check the next character to see if it's a valid index, and if it is, check the third character for the closing "}".

Is that how you would check for it?


Top
 Profile  
Reply with quote  
PostPosted: Tue Aug 01, 2017 11:04 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10943
Location: England
With the {n} syntax, it becomes a parsing problem. I think I'd call a handler as soon as I see the "{", whose job is to process the {n} and to return an error (somehow) if the syntax is wrong.

In the case of printf, if you want to print an actual % you use %%. Again, the handler can do that. Indeed, if you have %r and that happens to make no sense, the handler must complain, so there's no big difference with the {n} notation.


Top
 Profile  
Reply with quote  
PostPosted: Tue Aug 01, 2017 11:44 am 
Offline
User avatar

Joined: Wed May 11, 2016 4:15 am
Posts: 24
Location: Texas
BigEd wrote:
With the {n} syntax, it becomes a parsing problem. I think I'd call a handler as soon as I see the "{", whose job is to process the {n} and to return an error (somehow) if the syntax is wrong.

In the case of printf, if you want to print an actual % you use %%. Again, the handler can do that. Indeed, if you have %r and that happens to make no sense, the handler must complain, so there's no big difference with the {n} notation.


What's a handler? You mean a function that handles check the syntax of a placeholder? That makes sense to me at least.


Last edited by N2TheRed on Thu Aug 03, 2017 11:01 pm, edited 1 time in total.

Top
 Profile  
Reply with quote  
PostPosted: Tue Aug 01, 2017 11:55 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10943
Location: England
Yes, something like that. I'm quite sure that any approach I might sketch out would be modified if I actually sat down to try to write the code.

By handler I just meant a subroutine. In fact, with your problem as stated, you need to turn the ASCII digits into a number, as well as checking that the braces match, so perhaps both can be done by the same routine.


Top
 Profile  
Reply with quote  
PostPosted: Tue Aug 01, 2017 12:08 pm 
Offline
User avatar

Joined: Wed May 11, 2016 4:15 am
Posts: 24
Location: Texas
BigEd wrote:
Yes, something like that. I'm quite sure that any approach I might sketch out would be modified if I actually sat down to try to write the code.

By handler I just meant a subroutine. In fact, with your problem as stated, you need to turn the ASCII digits into a number, as well as checking that the braces match, so perhaps both can be done by the same routine.


Thanks Ed, you have given me much to think about.

I'm going to see what I can do with it now.


Top
 Profile  
Reply with quote  
PostPosted: Tue Aug 01, 2017 12:32 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10943
Location: England
It will be interesting to see what you come up with.


Top
 Profile  
Reply with quote  
PostPosted: Tue Aug 01, 2017 6:39 pm 
Offline

Joined: Tue Jun 08, 2004 11:51 pm
Posts: 213
I'm not of much help here but are you talking about
making an assembler to parse strings or just
writing some code with embedded subroutines?
It looks like you are writing an assembler.
Dwight


Top
 Profile  
Reply with quote  
PostPosted: Tue Aug 01, 2017 7:23 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8521
Location: Southern California
N2TheRed wrote:
Placeholders in assembly: How is it done?

C#
Code:
SomeMethod("Point A[{0},{1}], B[{2},{3}]", a.x, a.y, b.x, b.y)


If you wanted a function that takes a string with placeholders and some data and have it build a new string, would that be complicated?

I would inline the string, and use a macro to put the string and the command all on one line, like this:
Code:
        SomeMethod   "'Point A[{0},{1}], B[{2},{3}]', a.x, a.y, b.x, b.y"
as discussed about a quarter of they way down the 6502 stacks treatise page on inlining data, and then have a parser routine like Ed suggested. Actually, you might be able to have the assembler itself do most of the parsing in the macro, rather than burdening the processor so much at run time. You might have to modify the quotes method slightly to work with most macro assemblers, but it could be done. A super long macro definition doesn't necessarily lay down much machine code, if a lot of the macro is tests and decisions made at assembly time, and conditional assembly whose conditions aren't met in the particular invocation.

Macros allow raising the level of the language a lot, and we can make it imitate, to some extent, the way something would be done in a HHL. In many cases, trying to do a direct translation doesn't work nearly as well as taking a different approach to the problem though, an approach that suits the particular processor better. A really smart macro might be able to do some of this—but there are limits.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Tue Aug 01, 2017 11:31 pm 
Offline

Joined: Sat Dec 13, 2003 3:37 pm
Posts: 1004
Here's a straight forward stab in basic C.

It "works", that is it compiles and builds and runs, and should convey the concepts. It doesn't use any library functions (save printf for the example).

Most routines that accept variable numbers of arguments represent those arguments as an array, that's what I do here.

I also assume no negative numbers. The % is the mod operator.

Simply, it copies each character to the destination. If it encounters the {, then it converts the following digits to a number, and indexes the argument list array to get the actual value, then it converts that to a string and copies it in to the destination buffer. I don't call routines, as there's different issues with sharing variables and what not, and it's not the point of the exercise.

Note that during the numeric conversion, it works backwards in memory.

It has some "error checking", where it simply silently fails (noted by the returns). Error checking is left as an exercise for the reader.

Code:
#include <stdio.h>

#define ARG_SIZE 10

void print_pattern(char *pattern, int* arglist, int argcount) {
    char *p;
    char argbuf[ARG_SIZE];
    char *argp;
    char linebuf[128];
    char *lbp;
    int arg;


    p = pattern;
    lbp = linebuf;
    while(*p) {
        if (*p != '{') {
            *lbp++ = *p++;
        } else {
            p++; /* skip brace */

            /* copy the argument string to the arg buffer */
            argp = argbuf;
            while (*p >= '0' && *p <= '9') {
                *argp++ = *p++;
            }
            *argp++ = '\0';
            if (*p != '}') {
                /* syntax error */
                return;
            }
            p++; /* skip closing } */

            /* convert arg to int */
            arg = 0;
            argp = argbuf;
            while (*argp) {
                arg = arg * 10 + *argp++ - '0';
            }
            arg = arg - 1;
            if (arg >= argcount) {
                /* argument to large error */
                return;
            }
            arg = arglist[arg];

            /* convert value to string */
            argp = argbuf + ARG_SIZE - 1;
            *argp-- = '\0';
            if (arg == 0) {
                *argp = '0';
            } else {
                while (arg > 0) {
                    *argp-- = '0' + arg % 10;
                    arg /= 10;
                }
                argp++;
            }

            /* copy arg to line */
            while (*argp) {
                *lbp++ = *argp++;
            }
        }
        *lbp = '\0';
    }

    printf("%s\n", linebuf);
}

int main() {
    int args[3];
    args[0] = 11;
    args[1] = 0;
    args[2] = 23;

    print_pattern("this {1} that {2} and the other {3}", args, 3);
}


Top
 Profile  
Reply with quote  
PostPosted: Wed Aug 02, 2017 10:10 am 
Offline
User avatar

Joined: Wed May 11, 2016 4:15 am
Posts: 24
Location: Texas
whartung wrote:
Here's a straight forward stab in basic C.

It "works", that is it compiles and builds and runs, and should convey the concepts. It doesn't use any library functions (save printf for the example).

Most routines that accept variable numbers of arguments represent those arguments as an array, that's what I do here.

I also assume no negative numbers. The % is the mod operator.

Simply, it copies each character to the destination. If it encounters the {, then it converts the following digits to a number, and indexes the argument list array to get the actual value, then it converts that to a string and copies it in to the destination buffer. I don't call routines, as there's different issues with sharing variables and what not, and it's not the point of the exercise.

Note that during the numeric conversion, it works backwards in memory.

It has some "error checking", where it simply silently fails (noted by the returns). Error checking is left as an exercise for the reader.



I'm going to refrain from looking at that until I fail or succeed at what I've come up with. However, I will be coming back to read your full post very soon.


Top
 Profile  
Reply with quote  
PostPosted: Wed Aug 02, 2017 10:14 am 
Offline
User avatar

Joined: Wed May 11, 2016 4:15 am
Posts: 24
Location: Texas
dwight wrote:
I'm not of much help here but are you talking about
making an assembler to parse strings or just
writing some code with embedded subroutines?
It looks like you are writing an assembler.
Dwight


I'm just a noob, but I have big dreams!

I'm learning x86 and 6502, so writing an assembler is like a newborn running a marathon. Though, that would be an interesting sight!


Top
 Profile  
Reply with quote  
PostPosted: Wed Aug 02, 2017 10:28 am 
Offline
User avatar

Joined: Wed May 11, 2016 4:15 am
Posts: 24
Location: Texas
BigEd wrote:
It will be interesting to see what you come up with.



It has turned out rather challenging.


Last edited by N2TheRed on Thu Aug 03, 2017 11:02 pm, edited 2 times in total.

Top
 Profile  
Reply with quote  
PostPosted: Wed Aug 02, 2017 2:40 pm 
Offline

Joined: Sat Dec 13, 2003 3:37 pm
Posts: 1004
The only real problem with pushing the elements on the stack is that it's not really a viable option on the 6502, not on the system stack at least, and especially not string values. You can push them on A stack (Forth uses the top of Zero page and indexes with X), but that's using X as your stack pointer, vs the systems. You also still have the problem with stack scarcity for something large like a string.

You could still use the stack if you just push addresses (address of the pattern string, address of the list of arguments (which can be 2 byte integers, or pointers), and the address of the destination buffer).


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 19 posts ]  Go to page 1, 2  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 11 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: