Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Review: Parsing preprocessor in one pass edge cases. #54

Open
Ed94 opened this issue Jan 2, 2024 · 0 comments
Open

Review: Parsing preprocessor in one pass edge cases. #54

Ed94 opened this issue Jan 2, 2024 · 0 comments
Labels
documentation Improvements or additions to documentation enhancement New feature or request testing

Comments

@Ed94
Copy link
Owner

Ed94 commented Jan 2, 2024

I think I found a way to resolve issues I have with trying to preserve with WYSIWYG AST of any regular C/C++ file, even for edge cases messes.

static AudioData AUDIO = {
#ifndef __cplusplus
	.Buffer.defaultSize = 0,
	.mixedProcessor = NULL
#else
	0,
	NULL
#endif
};

In the above example, a programmer implicitly knows the context of the preprocessor is within the context of the Audio's initialization definition's scope. The traditional parser cannot. This is not good for a WYSIWYG as it makes it harder to parse contextually a file based on relative symbols.

Ideally to parse this definition and change out the context of this if def you would want to find the AUDIO static variable definition, then go to its assignment expression node and find within the block node the preprocessor conditional.
Technically speaking, this is possible to do by adding the ability to support conditional preprocessor blocks as valid nodes within assignment expressions. But not all preprocessor definitions are organized in such a way.

The other way around is also valid:

#if defined(_WIN32)
    typedef void *PVOID;
    typedef PVOID HANDLE;
    typedef HANDLE HWND;
    #define GLFW_EXPOSE_NATIVE_WIN32
    #define GLFW_NATIVE_INCLUDE_NONE // To avoid some symbols re-definition in windows.h
    #include "GLFW/glfw3native.h"

    #if defined(RL_SUPPORT_WINMM_HIGHRES_TIMER) && !defined(RL_SUPPORT_BUSY_WAIT_LOOP)
        // NOTE: Those functions require linking with winmm library
    #if __cplusplus
        extern "C" {
    #endif
        unsigned int __stdcall timeBeginPeriod(unsigned int uPeriod);
        unsigned int __stdcall timeEndPeriod(unsigned int uPeriod);
    #if __cplusplus
        }
    #endif
    #endif
#endif

In this case we just have to allow for untyped lexical nodes for unresolved text definitions in preprocessor contextes ( the extern "C" { and } at the closing of the extern for c++. These could be difficult to navigation but not impossible with a proper visual debugger of the ast for metaprograms. This still allows the user to traverse the AST with as much contextual ergonomics possible.

If the preprocessor macro or conditional block intersects the construction of a complete context of a C++ definition, where to put the preprocessors' node becomes ambiguous:

#define UNFORTUNATE 1

void Something
#if UNFORTUNATE
	(void)
#else
	(int)
#endif
{
}

This one is quite horrible as there is no salvaging the function definition. It will just break. The only thing that could be done is moving void Something to an untyped lexed node. The preprocessor conditionals would be in a global body node and the block scope will not have a context assignable (and thus not know what context to interpret it with). In that worst case you would have to use a parsing function that could deal with the 'laundry mat' of possible context that could be shoved in a executable context ( parse_any_execution_block).

So long as each parsing function can handle its failure correctly and 'recover' to a valid context for continuing to parse valid operations is setup iny any body/scope function a condition to handle parse failures with : on failure -> call parser:: recover_from_unresolved_state`. Which the function can provide a way for the parser to limit the bad definition to the least amount of tokens / scope possible. And continue from a valid state from then on.

int main()
{
	#define CURSED_EXP + 5 +
	int why = 2 CURSED_EXP some_var_you_might_want_to_refactor;
}

If the macro is within the statements bound we can just resolve the assignment's expression to be an untyped lexed text (so sucks, but not horrible). In a context system could still identifysome_var_you_might_want_to_refactor.

@Ed94 Ed94 added documentation Improvements or additions to documentation enhancement New feature or request testing labels Jan 2, 2024
@Ed94 Ed94 moved this to Todo in gencpp roadmap Dec 11, 2024
@Ed94 Ed94 added this to the C++ Parser support complete milestone Dec 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation enhancement New feature or request testing
Projects
Status: Todo
Development

No branches or pull requests

1 participant