Shop OBEX P1 Docs P2 Docs Learn Events
PNut/Spin2 Latest Version (v49 - CON STRUCT's are now exported, like CON integers and floats) - Page 73 — Parallax Forums

PNut/Spin2 Latest Version (v49 - CON STRUCT's are now exported, like CON integers and floats)

1676869707173»

Comments

  • cgraceycgracey Posts: 14,260
    edited 2025-01-20 00:13

    Thinking more about object pointers...

    They would be like method pointers, minus the 12-bit method index. They would just need the VAR base and code base of an object. Also, maybe an association to an object should be part of the object pointer variable declaration, in order to reduce syntactic clutter during usage.

    Maybe it could all work like this:

    OBJ objtype = "objfile"
    
    VAR ^objtype t
    
    PUB ......
      t := @realobject
      t.method()
      x := t.consymbol * 3
    
  • JonnyMacJonnyMac Posts: 9,211

    Does that work for methods with parameters?

  • cgraceycgracey Posts: 14,260

    @JonnyMac said:
    Does that work for methods with parameters?

    Yes, I just gave the simplest example.

  • Ideally make sure there's compatibility with flexspin's version of the feature (that also uses the OBJ equals syntax)

  • roglohrogloh Posts: 5,868
    edited 2025-01-20 03:12

    @cgracey said:
    Thinking more about object pointers...

    They would be like method pointers, minus the 12-bit method index. They would just need the VAR base and code base of an object. Also, maybe an association to an object should be part of the object pointer variable declaration, in order to reduce syntactic clutter during usage.

    Maybe it could all work like this:

    OBJ objtype = "objfile"
    
    VAR ^objtype t
    
    PUB ......
      t := @realobject
      t.method()
      x := t.consymbol * 3
    

    Interesting. Where is this "realobject" defined? In objfile somewhere? I like the idea of being able to dynamically select the executed code/data based on a dynamic object pointer's value rather than a static association - it could be useful for my memory driver abstraction and it is heading a bit closer to actual OOP. Although ideally we want the object pointer to be assignable to one of several instances of the same base object type (class) with different implementations for each subclass (if you want some inheritance+polymorphism).

  • JonnyMacJonnyMac Posts: 9,211
    edited 2025-01-20 05:15

    Yes, I just gave the simplest example.

    Okay, found the detail in the docs: when using the method pointer you have to explicitly declare the number of return values if !0.

  • @cgracey said:
    Thinking more about object pointers...

    They would be like method pointers, minus the 12-bit method index. They would just need the VAR base and code base of an object. Also, maybe an association to an object should be part of the object pointer variable declaration, in order to reduce syntactic clutter during usage.

    Maybe it could all work like this:

    OBJ objtype = "objfile"
    
    VAR ^objtype t
    
    PUB ......
      t := @realobject
      t.method()
      x := t.consymbol * 3
    

    This is exatly what I would want.

    By the way, I begin to rewrite my programs using structs and find that I can not access structure definitions in an obj from the parent obj.
    We can access constants definition with obj.CONST_NAME
    But not access structure definition with obj.STRUCT_NAME

    Maybe it is better to have a #include for the preprocessor.
    So we can write alle structure definition and global constants in one File and #include this in every object that needs that definitions.

  • cgraceycgracey Posts: 14,260

    @rogloh said:

    @cgracey said:
    Thinking more about object pointers...

    They would be like method pointers, minus the 12-bit method index. They would just need the VAR base and code base of an object. Also, maybe an association to an object should be part of the object pointer variable declaration, in order to reduce syntactic clutter during usage.

    Maybe it could all work like this:

    OBJ objtype = "objfile"
    
    VAR ^objtype t
    
    PUB ......
      t := @realobject
      t.method()
      x := t.consymbol * 3
    

    Interesting. Where is this "realobject" defined? In objfile somewhere? I like the idea of being able to dynamically select the executed code/data based on a dynamic object pointer's value rather than a static association - it could be useful for my memory driver abstraction and it is heading a bit closer to actual OOP. Although ideally we want the object pointer to be assignable to one of several instances of the same base object type (class) with different implementations for each subclass (if you want some inheritance+polymorphism).

    The "realobject" could come from anywhere. It would just need to exist in memory and be the same type of object.

  • cgraceycgracey Posts: 14,260
    edited 2025-01-20 16:24

    @wummi said:

    @cgracey said:
    Thinking more about object pointers...

    They would be like method pointers, minus the 12-bit method index. They would just need the VAR base and code base of an object. Also, maybe an association to an object should be part of the object pointer variable declaration, in order to reduce syntactic clutter during usage.

    Maybe it could all work like this:

    OBJ objtype = "objfile"
    
    VAR ^objtype t
    
    PUB ......
      t := @realobject
      t.method()
      x := t.consymbol * 3
    

    This is exatly what I would want.

    By the way, I begin to rewrite my programs using structs and find that I can not access structure definitions in an obj from the parent obj.
    We can access constants definition with obj.CONST_NAME
    But not access structure definition with obj.STRUCT_NAME

    Maybe it is better to have a #include for the preprocessor.
    So we can write alle structure definition and global constants in one File and #include this in every object that needs that definitions.

    I need to make child-object STRUCT definitions readable by the parent. I will look into this today.

    #INCLUDE would be good, but it would need to be implemented in a way where it wouldn't interfere with source file offsets for error reporting.

  • ersmithersmith Posts: 6,106
    edited 2025-01-20 16:40

    @cgracey said:

    #INCLUDE would be good, but it would need to be implemented in a way where it wouldn't interfere with source file offsets for error reporting.

    Most preprocessors deal with this by having a #line directive which can reset the file name and line number for error reporting, and then inserting appropriate #line during and after #include. See e.g. https://learn.microsoft.com/en-us/cpp/preprocessor/hash-line-directive-c-cpp?view=msvc-170

  • roglohrogloh Posts: 5,868

    @ersmith said:

    @cgracey said:

    #INCLUDE would be good, but it would need to be implemented in a way where it wouldn't interfere with source file offsets for error reporting.

    Most preprocessors deal with this by having a #line directive which can reset the file name and line number for error reporting, and then inserting appropriate #line during and after #include. See e.g. https://learn.microsoft.com/en-us/cpp/preprocessor/hash-line-directive-c-cpp?view=msvc-170

    Perhaps Chip's concern is the line number reporting during compilation, not so much execution, and how potentially nested include files would upset that. Also the #ifdef code could well too depending on how/when that is done, although I believe they are just being replaced with blanks IIRC so original line numbers should still be countable.

    I imagine some type of stack structure that tracks actual line numbers per currently included file might be useful if it could refer to the original source file in the nested group and current line number of the #include line. The line numbers get restarted at 1 for each new file the compiler includes and are restored back to the original line number of the "parent" source file when each include file ends, which then continues incrementing. Of course there still may be problems I don't understand as I might be missing how/when the compiler uses the line numbers if multiple passes are done and some of this information is not present in later passes. For that you may need to map a global line number to an original file/line number for example.

    This is a common and solvable problem for compiler error reporting. For example GCC reports errors found in include files using a hierarchy where each included file and related line number is known and displayed like this:

    In file included from /usr/include/stdio.h:28:0, 
    from ../.././gcc-4.7.0/libgcc/../gcc/tsystem.h:88,
    from ../.././gcc-4.7.0/libgcc/libgcc2.c:29:
    /usr/include/features.h:324:26: fatal error: bits/predefs.h: No such file or directory
    compilation terminated.
    
  • ersmithersmith Posts: 6,106

    @rogloh said:

    @ersmith said:

    @cgracey said:

    #INCLUDE would be good, but it would need to be implemented in a way where it wouldn't interfere with source file offsets for error reporting.

    Most preprocessors deal with this by having a #line directive which can reset the file name and line number for error reporting, and then inserting appropriate #line during and after #include. See e.g. https://learn.microsoft.com/en-us/cpp/preprocessor/hash-line-directive-c-cpp?view=msvc-170

    Perhaps Chip's concern is the line number reporting during compilation, not so much execution, and how potentially nested include files would upset that.

    That's exactly what I was talking about. Typically a preprocessor is implemented as a first pass, before any other part of the compiler, that replaces macros with their definitions, removes code that fails #ifdef tests, and substitutes the contents of a #include file for the #include line. So code that starts off looking like:

    CON
    #ifdef NOT_DEFINED
    #include "a.defs"
    #else
    #include "b.defs"
    #endif
    DAT
       byte "this is the original spin2"
    ...
    

    will after preprocessing look something like:

    CON
    
    
    
    #line 1 "b.defs"
    '' contents of file b.defs
    MyVal = "B"
    
    #line 6 "orig.spin2"
    DAT
      byte "this is the original spin2"
    

    The preprocessor deletes lines in #ifdef as appropriate, replacing them with blank lines to keep the line count straight. But around #include it inserts #line directives so the subsequent compiler passes can figure out what lines to give for errors. You can see this kind of thing in action if you run a stand-alone C preprocessor (like gcc -E). #line are the only directives that the rest of the compiler has to deal with, and they're pretty simple.

    Some modern compilers fold the preprocessing into other passes, so they no longer have a seperate preprocessor. That's OK too, but means you need to keep track of the line numbers/file names in another way.

  • roglohrogloh Posts: 5,868

    Ok gotcha @ersmith . I see how the #line directive is used in the final output now and how it tracks the source input file positions. The Microsoft example posted had only showed it used for output during execution which is commonly used too in C, but this embedded source information can also be used to track files and line numbers during compilation. Hopefully Chip could try to follow something like that.

  • cgraceycgracey Posts: 14,260
    edited 2025-01-21 11:40

    @wummi said:

    @cgracey said:
    Thinking more about object pointers...

    They would be like method pointers, minus the 12-bit method index. They would just need the VAR base and code base of an object. Also, maybe an association to an object should be part of the object pointer variable declaration, in order to reduce syntactic clutter during usage.

    Maybe it could all work like this:

    OBJ objtype = "objfile"
    
    VAR ^objtype t
    
    PUB ......
      t := @realobject
      t.method()
      x := t.consymbol * 3
    

    This is exatly what I would want.

    By the way, I begin to rewrite my programs using structs and find that I can not access structure definitions in an obj from the parent obj.
    We can access constants definition with obj.CONST_NAME
    But not access structure definition with obj.STRUCT_NAME

    Maybe it is better to have a #include for the preprocessor.
    So we can write alle structure definition and global constants in one File and #include this in every object that needs that definitions.

    I've got objects outputting their STRUCTs now, and parent objects are fully receiving them into their context, but I still need to implement the syntax handling in the compiler, so you'll be able to do 'object.struct'. That part should be much easier to implement. I think I've got the hard parts all done.

  • cgraceycgracey Posts: 14,260
    edited 2025-02-02 13:08

    I posted a new PNut_v49 which exports CON STRUCT's, just like CON integers and floats have always been.

    https://obex.parallax.com/obex/pnut-spin2-latest-version/

    CON STRUCT StructX(Object.StructA x[10]) 'StructX is ten StructA's, gets exported
    CON STRUCT StructY = Object.StructA      'StructY is a copy of StructA, gets exported
    VAR Object.StructA StructJ               'StructJ is an instance of StructA
    VAR ^Object.StructA StructK              'StructK is a pointer to StructA
    PUB Name(^Object.StructA StructL)        'StructL is a pointer to StructA
    DAT StructM Object.StructA               'StructM is an instance of StructA
    

    This took a long time to work out, because I started out keeping STRUCT definitions all isolated, but when exporting to the parent, things got hairy due to all the interdependencies. Now, when STRUCTs are defined that involve other STRUCTs, the other STRUCT definition is added in, instead of being referenced. This simplified many things. It also enabled STRUCTs to be exported upwards using "=" syntax (see 2nd line above).

    I found and fixed a bug in the SmoothLine routine that the DEBUG displays use. I had optimized the routine in v44, but didn't realize that I needed to make two variables into 64-bit integers to avoid overflow. The bug caused lines whose slope was near 1 to be drawn in the wrong direction with a vertical or horizontal segment added on.

  • evanhevanh Posts: 16,164
    edited 2025-02-02 13:28

    [haven't been reading]

  • @cgracey
    Just to clarify, Object is the symbol assigned to a child object? i.e., you're getting structure definitions from an external file? And by 'gets exported' I'm assuming you mean it's available for use in creating an instance, like the VAR, PUB and DAT examples?

  • cgraceycgracey Posts: 14,260
    edited 2025-02-02 14:56

    @avsa242 said:
    @cgracey
    Just to clarify, Object is the symbol assigned to a child object? i.e., you're getting structure definitions from an external file? And by 'gets exported' I'm assuming you mean it's available for use in creating an instance, like the VAR, PUB and DAT examples?

    We can use the STRUCTure definitions from a child object by using the syntax: object.structname.

    Any STRUCT that we declare, in turn, is available to any parent object in the future. We can pass structures from the lowest object all the way to the highest by doing this in every object in the chain: CON STRUCT structname = object.structname.

Sign In or Register to comment.