Finished chapter 4, I will hunt grammar mistakes later...

This commit is contained in:
Ognjen Milan Robovic 2023-11-19 10:42:14 -05:00
parent 715063ebc6
commit 2f4bc29217
2 changed files with 71 additions and 58 deletions

View File

@ -181,6 +181,7 @@ int string_compare (char * string_0, char * string_1) {
return (FALSE); // > We return FALSE, 0, since strings aren't the same...
}
}
if (* string_0 != * string_1) { // Now, we'll do one last termination check.
return (FALSE);
}

View File

@ -158,72 +158,80 @@ static int syntax_define (int enrange, int derange, char * begin, char * end, ch
}
/*
TODO: WE LEFT OF HERE...
This is more complex, but if you use your eyes to look, your brain to comprehend and your heart to love, I'm sure that you'll understand it.
*/
static int syntax_select (char * string, int * length) {
int offset, subset, select;
int offset, select;
fatal_failure (syntax_active == FALSE, "syntax_select: Syntax is not active.");
fatal_failure (syntax_active == FALSE, "syntax_select: Syntax is not active."); // Don't select without rules, abort!
fatal_failure (string == NULL, "syntax_select: String is null.");
fatal_failure (length == NULL, "syntax_select: Length is null.");
for (select = offset = 0; select != syntax_count; ++select) {
if (syntax_enrange [select] == FALSE) {
if (string_compare_limit (string, syntax_begin [select], string_length (syntax_begin [select])) == TRUE) {
break; // We need to limit our string comparisson function.
} else {
continue;
}
} else {
for (subset = 0; subset != string_length (syntax_begin [select]); ++subset) {
if (string [offset] == syntax_begin [select] [subset]) {
goto selected; // We can't use 'break' here, because it will exit only one loop, not both of them.
} else {
continue;
}
// In this first part of the function, we need to check if our syntax rule has been detected at the string offset we've provided. We're looping defined syntax rules and
// choosing whether to compare any of the characters, or full string, depending on 'syntax_enrange' value which is essentially boolean, true or false, which I express with
// 'int' type for "type-safety simplicity". Keep in mind that we're not returning or modifying the string we provided, so it won't be null-terminated, instead I think
// it's best to modify only variable 'length', hence we check with 'string_compare_limit' function.
for (select = offset = 0; select != syntax_count; ++select) { // We're looping defined syntax rules:
if (syntax_enrange [select] == FALSE) { // Choosing the comparisson:
if (string_compare_limit (string, syntax_begin [select], string_length (syntax_begin [select])) == TRUE) { // Limiting our string comparisson.
break; // If strings are same, we exit the loop.
}
} else { // Else, we compare any character.
if (character_compare_array (string [offset], syntax_begin [select]) == TRUE) { // With our obviously named function...
break; // We found it, exit the loop!
} // If we didn't, just continue.
}
}
selected:
} // And now we have our 'select' value.
// If there was no syntax rule detected, we need to return from a function, and increment the offset by setting variable 'length' to 1. If we don't increment it, at the
// first unrecognized character, our second nested-loop inside function 'preview_c_file' would use uninitialized or zero value, depending on how we structured our code
// before that. We also return 'syntax_count' as the syntax rule index, which is invalid, and would produce Valgrind warning if we didn't handle it. In my unimportant
// opinion, this if statement is the ugliest part of the function.
if (select >= syntax_count) {
* length = 1;
return (syntax_count);
}
for (offset = 1; string [offset - 1] != '\0'; ++offset) {
if (string [offset] == syntax_escape [select]) {
// In this second part, we have our 'select' value, index of the syntax rule, and we want to know the 'length' value, by trying to match with 'syntax_end' string. We have
// to again, separate two cases for matching any character or full string, except that we use it to determine its' match-length. Important difference is also that there's
// special case where we have escape character matching, and where 'syntax_end' string is empty (but not NULL), so in that case we match only one character. We could have
// nested loop there, and second loop would need goto statement to exit it, so we only use one loop.
for (offset = 1; string [offset - 1] != '\0'; ++offset) { // Now, offset must be 1, and we loop...
if (string [offset] == syntax_escape [select]) { // Here's our escape exception.
++offset;
continue;
}
if (syntax_derange [select] == FALSE) {
if (string_compare_limit (& string [offset], syntax_end [select], string_length (syntax_end [select])) == TRUE) {
* length = offset + string_length (syntax_end [select]);
return (select);
if (syntax_derange [select] == FALSE) { // Choosing what to compare, yet again...
if (string_compare_limit (& string [offset], syntax_end [select], string_length (syntax_end [select])) == TRUE) { // Again, we're comparing full string.
* length = offset + string_length (syntax_end [select]); // We found it, yaay!
break;
}
} else {
subset = 0;
if (string_compare (syntax_end [select], "") == TRUE) {
if (string_compare (syntax_end [select], "") == TRUE) { // And here's our empty string exception.
break;
} do {
if (string [offset] == syntax_end [select] [subset]) {
* length = offset;
goto finished;
}
} while (++subset != string_length (syntax_end [select]));
}
}
}
if (character_compare_array (string [offset], syntax_end [select]) == TRUE) {
* length = offset;
break;
}
} // These two loops look similar, but no!
} // And now we have our 'length' value.
finished:
return (select);
return (select); // Lastly, return syntax rule index.
}
/*
Imagine my shock, we can now print coloured text, without regular expressions. Nothing much, we can print it without using 'curses_*' functions, but if we want to preview large,
well more than 24 line of code, we'd want to scroll it or modify it if we're making a text editor, hence, using curses is good. Lets see how our "mini-main" subprogram-like
function does its' work, and how we use 'syntax_*' functions in them.
*/
void preview_c_file (char * text_file, int width, int height, int x, int y) {
// Before we begin (Ada pun intended, remove this in final version), I won't (re)align 'separators' and 'keywords', because they fuck-up my comments, which I never write
// in my "official" programs. I write comments only here, to explain stuff in more details. Have fun... Oh, and type of variable 'keywords' an array of string pointers of
// automatic length, which we get with "sizeof (keywords) / sizeof (keywords [0])" part, for those keywords, it would be 32UL, and we cast it to integer.
char * separators = ".,:;<=>+*-/%!&~^?|()[]{}'\" \t\r\n";
char * keywords [] = {
@ -240,7 +248,7 @@ void preview_c_file (char * text_file, int width, int height, int x, int y) {
(void) width;
(void) height;
syntax_define (FALSE, FALSE, "/*", "*/", '\0', COLOUR_GREY, EFFECT_BOLD);
syntax_define (FALSE, FALSE, "/*", "*/", '\0', COLOUR_GREY, EFFECT_BOLD); // Below, we're simply using our 'syntax_define' function.
syntax_define (FALSE, FALSE, "//", "\n", '\0', COLOUR_GREY, EFFECT_BOLD);
syntax_define (FALSE, FALSE, "#", "\n", '\\', COLOUR_YELLOW, EFFECT_ITALIC);
syntax_define (FALSE, FALSE, "'", "'", '\\', COLOUR_PINK, EFFECT_BOLD);
@ -258,27 +266,33 @@ void preview_c_file (char * text_file, int width, int height, int x, int y) {
syntax_define (TRUE, TRUE, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", separators, '\0', COLOUR_WHITE, EFFECT_BOLD);
syntax_define (TRUE, TRUE, "_", separators, '\0', COLOUR_WHITE, EFFECT_ITALIC);
text_data = file_record (text_file);
text_data = file_record (text_file); // And, imagine, importing our file data into a buffer!
reset_x = x;
reset_y = y;
for (curses_active = 1; curses_active != 0; ) {
for (curses_active = 1; curses_active != 0; ) { // We enter our main subprogram loop.
int offset, select, length;
curses_render_background (' ', COLOUR_WHITE, EFFECT_NORMAL);
curses_render_background (' ', COLOUR_WHITE, EFFECT_NORMAL); // We need to clear the screen buffer before rendering.
x = reset_x;
y = reset_y;
select = syntax_count;
length = 0;
for (offset = 0; offset < string_length (text_data); offset += length) {
for (offset = 0; offset < string_length (text_data); offset += length) { // And it's time to start rendering our C file.
int suboffset, colour, effect;
select = syntax_select (& text_data [offset], & length);
select = syntax_select (& text_data [offset], & length); // Here we're evaluating variables 'select' and 'length'.
if (select >= syntax_count) {
// We can do the same thing in 2 lines of code, but it's less readable in my opinion, I prefer longer verbose way below...
// colour = (select >= syntax_count) ? COLOUR_WHITE : syntax_colour [select];
// effect = (select >= syntax_count) ? EFFECT_NORMAL : syntax_effect [select];
// Or, if you find this more intuitive:
// colour = (select < syntax_count) ? syntax_colour [select] : COLOUR_WHITE;
// effect = (select < syntax_count) ? syntax_effect [select] : EFFECT_NORMAL;
if (select >= syntax_count) { // Here, we're handling error value of 'syntax_select'.
colour = COLOUR_WHITE;
effect = EFFECT_NORMAL;
} else {
@ -286,25 +300,23 @@ void preview_c_file (char * text_file, int width, int height, int x, int y) {
effect = syntax_effect [select];
}
for (suboffset = 0; suboffset < length; ++suboffset) {
if (text_data [offset + suboffset] == CHARACTER_LINE_FEED) {
x = reset_x;
y += 1;
} else if (text_data [offset + suboffset] == CHARACTER_TAB_HORIZONTAL) {
x += 8;
for (suboffset = 0; suboffset < length; ++suboffset) { // Sadly, we need to render them one by one character.
if (text_data [offset + suboffset] == CHARACTER_LINE_FEED) { // Rendering of blank characters isn't counted, so:
x = reset_x; // If there's a new line, we need to reset 'x' value.
y += 1; // And increment 'y' value.
} else if (text_data [offset + suboffset] == CHARACTER_TAB_HORIZONTAL) { // If there's a tab, we offset 'x' value by normal count.
x += 8; // Normal indentation is 8-characters wide.
} else {
curses_render_character (text_data [offset + suboffset], colour, effect, x, y);
curses_render_character (text_data [offset + suboffset], colour, effect, x, y); // Finally, we can render it character by character.
x += 1;
}
}
// curses_render_string_limit (& text_data [offset], length, syntax_colour [select], syntax_effect [select], x, y);
}
curses_synchronize ();
curses_synchronize (); // Lastly, we synchronize our terminal.
}
text_data = deallocate (text_data);
text_data = deallocate (text_data); // And deallocate the memory when we exit the subprogram.
}
#endif