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

Added buffer in get_ch() for line continuation lookahead #136

Merged
merged 9 commits into from
Feb 20, 2025
39 changes: 39 additions & 0 deletions pnut.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@
#define OPTIMIZE_CONSTANT_PARAM_not
#define SUPPORT_ADDRESS_OF_OP_not

// Make get_ch() use a length-1 character buffer to lookahead and skip line continuations
#define SUPPORT_LINE_CONTINUATION_not

// Shell backend codegen options
#ifndef SH_AVOID_PRINTF_USE_NOT
#define SH_AVOID_PRINTF_USE
Expand Down Expand Up @@ -747,8 +750,44 @@ void output_declaration_c_code(bool no_header) {
}
#endif

#ifdef SUPPORT_LINE_CONTINUATION
// get_ch_ is reponsible for reading the next character from the input file,
// switching to the next file if necessary and updating the line number.
// get_ch is then responsible for skipping line continuations.
void get_ch_();

int line_continutation_prev_char = -2; // -1 is EOF, -2 is uninitialized
void get_ch() {
if (line_continutation_prev_char == -2) {
while (1) { // Loop as long as we're reading line continuations
get_ch_(); // Read the next character
if (ch == '\\') {
get_ch_(); // Skip backslash
if (ch == '\n') {
continue; // Loop again to read the next character
} else {
// '\' is not followed by newline, so we save the current character
// and make '\' the current character
line_continutation_prev_char = ch;
ch = '\\';
break;
}
} else {
break;
}
}
} else {
ch = line_continutation_prev_char;
line_continutation_prev_char = -2;
}
}

void get_ch_() {
#else
void get_ch() {
#endif
ch = fgetc(fp);

if (ch == EOF) {
// If it's not the last file on the stack, EOF means that we need to switch to the next file
if (include_stack->next != 0) {
Expand Down
2 changes: 2 additions & 0 deletions sh.c
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ void print_escaped_text(text t, bool for_printf) {
putchar('0'); putchar('x');
puthex_unsigned(TEXT_TO_INT(text_pool[t + 1]));
} else if (text_pool[t] == TEXT_FROM_INT(TEXT_INTEGER_OCT)) {
putchar('0'); // Note: This is not supported by zsh by default
putoct_unsigned(TEXT_TO_INT(text_pool[t + 1]));
} else if (text_pool[t] == TEXT_FROM_INT(TEXT_STRING)) {
print_escaped_string((char*) text_pool[t + 1], (char*) text_pool[t + 2], for_printf);
Expand Down Expand Up @@ -315,6 +316,7 @@ void print_text(text t) {
putchar('0'); putchar('x');
puthex_unsigned(TEXT_TO_INT(text_pool[t + 1]));
} else if (text_pool[t] == TEXT_FROM_INT(TEXT_INTEGER_OCT)) {
putchar('0'); // Note: This is not supported by zsh by default
putoct_unsigned(TEXT_TO_INT(text_pool[t + 1]));
} else if (text_pool[t] == TEXT_FROM_INT(TEXT_STRING)) {
if (TEXT_TO_INT(text_pool[t + 2]) == 0) { // null-terminated string
Expand Down
36 changes: 36 additions & 0 deletions tests/_all/line_continuation.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// comp_pnut_opt: -DSUPPORT_LINE_CONTINUATION
#include <stdio.h>

void putint_aux(int n) {
if (n >= 10) putint_aux(n / 10);
putchar('0' + (n % 10));
}

void putint(int n) {
if (n < 0) {
putchar('-');
putint_aux(-n);
} else {
putint_aux(n);
}
}

int main() {

/**/
int foo = 0;

/\
*
*/ fo\
\
\
o +\
= 1\
\
10\
200;

putint(foo);
return 0;
}
1 change: 1 addition & 0 deletions tests/_all/line_continuation.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
110200
Loading