Page 1 of 2

Placeholders in assembly: How is it done?

Posted: Tue Aug 01, 2017 10:22 am
by N2TheRed
Placeholders in assembly: How is it done?

C#

Code: Select all

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?

Re: Placeholders in assembly: How is it done?

Posted: Tue Aug 01, 2017 10:47 am
by BigEd
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.

Re: Placeholders in assembly: How is it done?

Posted: Tue Aug 01, 2017 11:00 am
by N2TheRed
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?

Re: Placeholders in assembly: How is it done?

Posted: Tue Aug 01, 2017 11:04 am
by BigEd
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.

Re: Placeholders in assembly: How is it done?

Posted: Tue Aug 01, 2017 11:44 am
by N2TheRed
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.

Re: Placeholders in assembly: How is it done?

Posted: Tue Aug 01, 2017 11:55 am
by BigEd
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.

Re: Placeholders in assembly: How is it done?

Posted: Tue Aug 01, 2017 12:08 pm
by N2TheRed
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.

Re: Placeholders in assembly: How is it done?

Posted: Tue Aug 01, 2017 12:32 pm
by BigEd
It will be interesting to see what you come up with.

Re: Placeholders in assembly: How is it done?

Posted: Tue Aug 01, 2017 6:39 pm
by dwight
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

Re: Placeholders in assembly: How is it done?

Posted: Tue Aug 01, 2017 7:23 pm
by GARTHWILSON
N2TheRed wrote:
Placeholders in assembly: How is it done?

C#

Code: Select all

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: Select all

        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.

Re: Placeholders in assembly: How is it done?

Posted: Tue Aug 01, 2017 11:31 pm
by whartung
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: Select all

#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);
}

Re: Placeholders in assembly: How is it done?

Posted: Wed Aug 02, 2017 10:10 am
by N2TheRed
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.

Re: Placeholders in assembly: How is it done?

Posted: Wed Aug 02, 2017 10:14 am
by N2TheRed
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!

Re: Placeholders in assembly: How is it done?

Posted: Wed Aug 02, 2017 10:28 am
by N2TheRed
BigEd wrote:
It will be interesting to see what you come up with.

It has turned out rather challenging.

Re: Placeholders in assembly: How is it done?

Posted: Wed Aug 02, 2017 2:40 pm
by whartung
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).