Bläddra i källkod

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

master
Ognjen Milan Robovic 6 månader sedan
förälder
incheckning
2f4bc29217
2 ändrade filer med 71 tillägg och 58 borttagningar
  1. +1
    -0
      chapter/chapter_0.c
  2. +70
    -58
      chapter/chapter_4.c

+ 1
- 0
chapter/chapter_0.c Visa fil

@@ -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);
}


+ 70
- 58
chapter/chapter_4.c Visa fil

@@ -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]));
}
}

finished:
}
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.

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

Laddar…
Avbryt
Spara