Repository navigation
Fix Trac 6028: normalize SDCC assembly before preprocessing #8892
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1133,15 +1133,89 @@ std::size_t Preprocessor::calculateHash(const std::string &toolinfo) const | |
| return (std::hash<std::string>{})(hashData); | ||
| } | ||
|
|
||
| void Preprocessor::simplifyPragmaAsm() | ||
| static simplecpp::Token* simplifySdccAsm(simplecpp::TokenList& tokenList, simplecpp::Token* start) | ||
| { | ||
| simplifyPragmaAsm(mTokens); | ||
| const simplecpp::Token* previous = start->previousSkipComments(); | ||
| if (sameline(start, previous) && previous->op != '{' && previous->op != '}' && previous->op != ';') | ||
| return nullptr; | ||
| // Do not rewrite a macro definition or a GNU/MS-style asm statement. | ||
| for (const simplecpp::Token* tok = previous; sameline(start, tok); tok = tok->previous) { | ||
| if (tok->op == '#') | ||
| return nullptr; | ||
| } | ||
| const simplecpp::Token* first = start->nextSkipComments(); | ||
| if (!first || (sameline(start, first) && first->op != ';') || | ||
| first->op == '(' || first->op == '{' || first->str() == "volatile" || | ||
| first->str() == "__volatile" || first->str() == "__volatile__" || | ||
| first->str() == "goto" || first->str() == "inline") | ||
| return nullptr; | ||
|
|
||
| simplecpp::Token* end = start->next; | ||
| const simplecpp::Token* comment = nullptr; | ||
| bool nestedAsm = false; | ||
| for (; end; end = end->next) { | ||
| if (end->comment || sameline(end, comment)) | ||
| continue; | ||
| if (end->op == ';') { | ||
| comment = end; | ||
| continue; | ||
| } | ||
| if (end->str() == "__endasm" && !sameline(end, end->previousSkipComments())) { | ||
| const simplecpp::Token* next = end->nextSkipComments(); | ||
| if (!sameline(end, next) || next->op == ';') | ||
| break; | ||
| } | ||
| // An incomplete block must not consume C code or a different conditional | ||
| // branch. Leave such input to the normal preprocessor/tokenizer. | ||
| if (end->str() == "__asm") | ||
| nestedAsm = true; | ||
| if (end->op == '{' || end->op == '}' || | ||
| (end->op == '#' && !sameline(end, end->previousSkipComments()))) | ||
| return end->previous; | ||
| } | ||
| if (!end) | ||
| return tokenList.back(); | ||
| // Do not normalize an inner block after rejecting an ambiguous outer one. | ||
| if (nestedAsm) | ||
| return end; | ||
|
|
||
| // Preserve an asm statement as an analysis barrier, including for empty | ||
| // blocks. Hide assembler # operands before simplecpp stringifies them. | ||
| std::unique_ptr<simplecpp::Token> open(new simplecpp::Token("(", start->location)); | ||
| std::unique_ptr<simplecpp::Token> close(new simplecpp::Token(")", start->location)); | ||
|
Comment on lines
+1182
to
+1185
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is an AI review. Take it with a grain of salt and feel free to reject it by resolving the comment. I built the PR and compared it with main. Other asm forms are unchanged: One behavior change I noticed: the assembler text is now dropped. For void f(void) {
__asm
mov ax,bx
__endasm;
}main produces
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the assembler text is used somehow and shouldn't be dropped. However I am not sure what we use it for. One possible idea is when checking if the code in two scopes are the same to find copy paste mistakes, then we want to know if the same assembler instructions are provided. for this purpose it's enough with a hash or an id string we don't need to see the exact code.. |
||
| // A second terminator would break an unbraced do/while or if/else body. | ||
| simplecpp::Token* terminator = end->next; | ||
| while (terminator && terminator->comment) | ||
| terminator = terminator->next; | ||
| if (terminator && terminator->op == ';') | ||
| tokenList.deleteToken(terminator); | ||
| start->setstr("asm"); | ||
| end->setstr(";"); | ||
| while (start->next != end) | ||
| tokenList.deleteToken(start->next); | ||
| open->previous = start; | ||
| open->next = close.get(); | ||
| close->previous = open.get(); | ||
| close->next = end; | ||
| start->next = open.release(); | ||
| end->previous = close.release(); | ||
| return end; | ||
| } | ||
|
|
||
| void Preprocessor::simplifyAsm() | ||
| { | ||
| simplifyAsm(mTokens); | ||
| } | ||
|
|
||
| void Preprocessor::simplifyPragmaAsm(simplecpp::TokenList &tokenList) | ||
| void Preprocessor::simplifyAsm(simplecpp::TokenList &tokenList) | ||
| { | ||
| // assembler code.. | ||
| for (simplecpp::Token *tok = tokenList.front(); tok; tok = tok->next) { | ||
| if (tok->str() == "__asm") { | ||
| if (simplecpp::Token* end = simplifySdccAsm(tokenList, tok)) | ||
| tok = end; | ||
| continue; | ||
| } | ||
| if (tok->op != '#') | ||
| continue; | ||
| if (sameline(tok, tok->previousSkipComments())) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AI review
This check only accepts
__asmat the start of a line or right after{,}or;. Code such asif (a) __asm,else __asm,case 1: __asmorlabel: __asm, followed bymovx @dptr,a/mov a,#(s_XINIT>>8)on the next lines, still givessyntax error/Unmatched ')', the same as on main. I reproduced this withcase 1: __asmandif (a) __asm.The GNU/ARM forms that this check guards against (
int x __asm("sym"),__asm void g(),__asm volatile) are already rejected by thefirstchecks below. Could this also accept a previous),:orelse, or be dropped in favour of thefirstchecks?