Using this code as a starting point:
extern "C" {
void xputc(int);
void xputs(const char *);
}
class ostream {
public:
ostream &operator<<(const char *);
ostream &operator<<(char c);
};
ostream &ostream::operator<<(const char *cp) {
xputs(cp);
return *this;
}
ostream &ostream::operator<<(char c) {
xputc(c);
return *this;
}
static ostream cout;
static const char endl = '\n';
int main(int argc, char **argv) {
cout << "hello, world" << endl;
return 0;
}
(Note that there's no 6502/z80 c++ lib so I wrote my own minimal cout
implementation. It might be possible to include cc65's <stdio.h>
directly but I chose to handle that below in the interest of expediency.)
I ran it through MPW CFront (3.2, based on AT&T 2.1.12) which generated this monstrosity:
#line 1 "hello.cpp"
/* << CFront Version 3.2 (1/27/92; AT&T 2.1.12) �Apple Computer, Inc.1989-92 >> */
/* < hello.cpp > */
/* -D MAC_CONV_IS_A_PLIST -D MAC_CTOR_OPTS -U MAC_DEBUG_MISC -D MAC_FIX_ATT2_0_BUG -D MAC_FIX_ATT2_1_0_BUG -D MAC_LOAD_DUMP -D MAC_MARK_OPTION -D MAC_MISC -D MAC_PASCAL -D MAC_PASCAL_OBJECT -D MAC_SADE_SUPPORT -D MAC_SANE -D MAC_SCANNER -D MAC_TOKEN_STREAM -D MAC_USUALLY_OMIT_THE_SUFFIX */
extern void *__vec_new__FPviT2T1(void *, int , int , void *);
extern void __vec_delete__FPviT2T1N22(void *, int , int , void *, int , int );typedef void (*__vptp)();
struct __mptr {short d;short i;__vptp f;};
static struct __mptr __zero_mptr ={0,0,0};/*dead-stripped if not used*/
#line 1 "hello.cpp"
extern struct __mptr* __ptbl_vec__hello_cpp_[ ] ;
void **__nw__12PascalObjectSFPFv_vUi(pascal void (*)(void ), unsigned int );
void __dl__12PascalObjectSFPPv(void **);
struct PascalObject;
void **__nw__12HandleObjectSFUi(unsigned int );
void __dl__12HandleObjectSFPPv(void **);
struct HandleObject;
struct SingleObject;
struct ostream;
#line 7 "hello.cpp"
struct ostream { /* sizeof ostream == 2 */
#line 12 "hello.cpp"
char __W1;
};
extern void xputs(char *);
extern struct __mptr* __ptbl_vec__hello_cpp_[ ] ;
#line 14 "hello.cpp"
struct ostream *__ls__7ostreamFPCc(struct ostream *this, char *cp){
#line 15 "hello.cpp"
xputs( cp) ;
#line 16 "hello.cpp"
return (struct ostream *)this;
}
extern void xputc(int );
#line 19 "hello.cpp"
struct ostream *__ls__7ostreamFc(struct ostream *this, char c){
#line 20 "hello.cpp"
xputc( (int )c) ;
#line 21 "hello.cpp"
return (struct ostream *)this;
}
#line 25 "hello.cpp"
static struct ostream cout;
#line 26 "hello.cpp"
#line 28 "hello.cpp"
int main(int argc, char **argv){{
#line 30 "hello.cpp"
__ls__7ostreamFc( (struct ostream *)__ls__7ostreamFPCc( & cout, (char *)"hello, world")
#line 31 "hello.cpp"
, (char )((char )13)) ;
return (int )0;
#line 32 "hello.cpp"
}
}
/* the end */
Careful observers will note that MPW's CFront converts the endl
\n
to be \r
which was the classic Macintosh standard end of line character.
I manually commented out the void **__nw__12PascalObjectSFPFv_vUi(pascal void (*)(void ), unsigned int );
line (which cc65 did not like) and added these lines to get working i/o:
#include <stdio.h>
#define xputc(x) fputc(x, stdout)
#define xputs(x) fputs(x, stdout)
Running that code through cc65, generates this assembly, which is actually not that bad:
;
; File generated by cc65 v 2.18 - N/A
;
.fopt compiler,"cc65 v 2.18 - N/A"
.setcpu "6502"
.smart on
.autoimport on
.case on
.debuginfo off
.importzp sp, sreg, regsave, regbank
.importzp tmp1, tmp2, tmp3, tmp4, ptr1, ptr2, ptr3, ptr4
.macpack longbranch
.forceimport __STARTUP__
.forceimport initmainargs
.import _stdout
.import _fputc
.import _fputs
.export ___ls__7ostreamFPCc
.export ___ls__7ostreamFc
.export _main
.segment "DATA"
___zero_mptr:
.word $0000
.word $0000
.word $0000
.segment "RODATA"
L0013:
.byte $68,$65,$6C,$6C,$6F,$2C,$20,$77,$6F,$72,$6C,$64,$00
.segment "BSS"
_cout:
.res 1,$00
; ---------------------------------------------------------------
; __near__ struct ostream * __near__ __ls__7ostreamFPCc (__near__ struct ostream *, __near__ unsigned char *)
; ---------------------------------------------------------------
.segment "CODE"
.proc ___ls__7ostreamFPCc: near
.segment "CODE"
jsr pushax
ldy #$01
jsr ldaxysp
jsr pushax
lda _stdout
ldx _stdout+1
jsr _fputs
ldy #$03
jsr ldaxysp
jmp L0004
L0004: jsr incsp4
rts
.endproc
; ---------------------------------------------------------------
; __near__ struct ostream * __near__ __ls__7ostreamFc (__near__ struct ostream *, unsigned char)
; ---------------------------------------------------------------
.segment "CODE"
.proc ___ls__7ostreamFc: near
.segment "CODE"
jsr pusha
ldy #$00
ldx #$00
lda (sp),y
ldx #$00
jsr pushax
lda _stdout
ldx _stdout+1
jsr _fputc
ldy #$02
jsr ldaxysp
jmp L0009
L0009: jsr incsp3
rts
.endproc
; ---------------------------------------------------------------
; int __near__ __cdecl__ main (int, __near__ __near__ unsigned char * *)
; ---------------------------------------------------------------
.segment "CODE"
.proc _main: near
.segment "CODE"
lda #<(_cout)
ldx #>(_cout)
jsr pushax
lda #<(L0013)
ldx #>(L0013)
jsr ___ls__7ostreamFPCc
jsr pushax
lda #$0D
jsr ___ls__7ostreamFc
ldx #$00
lda #$00
jmp L000E
L000E: jsr incsp4
rts
.endproc
The C code was also compiled and run with clang (on x64) and ORCA/C (on 65816) to verify it was valid.