Added more explanations...

This commit is contained in:
Ognjen Milan Robovic 2023-12-03 11:05:54 -05:00
parent 2286ad75dd
commit 44006f375a
8 changed files with 384 additions and 8 deletions

View File

@ -209,7 +209,7 @@ int file_type (char * name) {
return (-1); // If it's not in array, we return -1, so we don't access the wrong value in some other array.
}
void * file_record (char * name) {
char * file_record (char * name) {
int file = -1; // You can also initialize local variables in this way.
int size = -1;
char * data = NULL;

View File

@ -357,7 +357,7 @@ extern void file_write (int file, void * data, int size); // We write from 'd
extern int file_seek (int file, int whence); // We retrieve data about offsets in 'file'.
extern int file_size (char * name); // We get the size of the file by its' 'name'.
extern int file_type (char * name); // We get the type of the file by its' 'name' (by file name extension).
extern void * file_record (char * name); // We store an entire file into some memory address.
extern char * file_record (char * name); // We store an entire file into some memory address.
// These will be useful in chapter three, where we'll learn about 'printf' function. It's too complex to cover it at this point.
extern char * number_to_string (int number);

View File

@ -9,8 +9,8 @@ In this chapter, you'll learn about:
- Curses library (libncurses "clone")
- More on function declarations
- General scope
- Escape sequences
- General scope
- Sane program layout
- Terminal input and output
@ -152,6 +152,147 @@ extern int curses_screen_width; // Width of terminal window in which we're rend
extern int curses_screen_height; // Height of terminal window in which we're rendering.
extern int curses_active; // As long as there's no termination signal, this variable will be different from zero. We use it to exit the program.
/*
Now, lets talk about scope. Roughly speaking, every variable, constant, function, enumeration, structure, union, definition, declaration, file, anything really has some scope,
where it is known to the compiler, visible. If, for example you're using 'printf' function from <stdio.h> header file, and you didn't write "#include <stdio.h>" before that line
in which you're using it (and outside of function definition, that's K&R thing, I'll explain later), compiler will get scared and confused, and it'll just drop dead. You're left
with no executable, compiler spat out some error messages, you don't know what they mean, it's over.
So, if you have something like this:
@C
int F (int A) {
int V = randomize (0, A);
return (A + V);
}
@
Variable 'V' is local to function 'F', and to no other function, you can only use variable 'V' inside function 'F', but you can name other local variable as 'V' too, no problems.
Inside file named "a.c", for example:
@C
static int X = 100;
static int Y = 200;
static int Z = 300;
@
Variables 'X', 'Y' and 'Z' are only visible in file "a.c", and no other file. You can modify them inside any function in that file, but don't name any local variables as that.
You want to use global variables? You should have declarations in header file, and definitions in source file:
@C
// a.h
extern char * A;
extern char * B;
extern char * C;
@
@C
// a.c
#include "path/to/file/a.h"
// ...
char * A = "Heyo";
char * B = "Cyaa";
char * C = "Meme";
@
In this case, you can modify variables 'A', 'B' and 'C' in any file that has included header file "a.h", not only "a.c", but you must define them only once, as shown here.
When you forget to include some header file, provide a variable, constant, function declaration or definition, compiler will warn you about it, because it can guess in simple
cases where that function is declared, but it can't (shouldn't) scan your entire SSD or HDD to find it, because it would take too long and maybe you just mistyped the name of it.
If you forget to write "#include <unistd.h>", and use write or read "functions", the compiler will kindly tell you to include it, but it would assume you want to use that very
functions, and it will compile it anyway, giving you your executable in hope it's correct. It can't do that always...
In K&R C, aka old C, it was something like this (don't mind the stupid example):
@C
// K&R C (with a lot of implcit state) // Sadly new C standards (verbose and "safe")
putchar (c) { extern int putint (int file, int data, int size);
extern putint;
static int putchar (int c) {
putint (1, c, 1); return (putint (1, c, 1));
} }
@
Essentially, you'll get the feeling for it after few compiler warnings, don't be afraid to make mistakes that compiler can catch.
About my preffered program layout, here's what I think about it:
@C
// License notice if you want.
// Header guards or definitions.
#ifndef BLA_BLA_HEADER
#define BLA_BLA_HEADER
#define _DEFAULT_SOURCE
// Standard library C header files.
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
// User provided C source or header files.
#include "heyo.h"
#include "cyaa.c"
// Macros that you really want to have.
#define UNUSED(x) (void) x
// Internal function declarations then variable definitions.
static void uberheyo (void);
// Or:
static void ubercyaa (void) {
// ...
}
static int h = 0;
static int c = 1;
// External function then variable declarations.
extern void heyo (void);
extern void cyaa (void);
extern int H;
extern int c;
// Internal function definition, if not defined above...
void uberheyo (void) {
// ...
}
// External function then variable definition, if not in included C source file.
void heyo (void) {
// ...
}
void cyaa (void) {
// ...
}
int H = 0;
int C = 1;
// Main function.
int main (void) {
// ...
}
// Or:
int main (int argc, char * * argv) {
// ...
}
// You can also define internal or external functions here if you want to.
// End of header guards.
#endif
@
Find one style, and try to be consistent about it, I have to show-case more example of how things look like, so I use more approaches...
*/
extern void curses_configure (void); // I like using the approach of "just do it" instead of "begin" and "end", due to that we'll see more internal functions and variables.
extern void curses_synchronize (void); // This function needs to be explained in more details, that'll be done in file "chapter_2.c".

View File

@ -366,7 +366,7 @@ void program_curses_view_file (char * text_file, int x, int y) {
reset_x = x;
reset_y = y;
for (curses_active = 1; curses_active != 0; ) { // We enter our main subprogram loop.
while (curses_active == TRUE) { // We enter our main subprogram loop.
int offset, select, length;
curses_render_background (' ', COLOUR_WHITE, EFFECT_NORMAL); // We need to clear the screen buffer before rendering.
@ -381,7 +381,7 @@ void program_curses_view_file (char * text_file, int x, int y) {
select = syntax_select (& text_data [offset], & length); // Here we're evaluating variables 'select' and 'length'.
// 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...
// We can do the same thing in 2 lines of code, but it's less readable in my opinion, I prefer more 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:

View File

@ -9,7 +9,7 @@
/*
In this chapter, you'll learn about:
- Programming language layout
- Programming languages
- Syntax highlighting
- Importance of readability
- Differences between languages

View File

@ -19,6 +19,7 @@ gcc -o xhartae xhartae.o chapter/chapter_0.o chapter/chapter_1.o chapter/chapter
gcc -g -Wall -Wextra -Wpedantic -Werror -Ofast -o program/program_0 program/program_0.c
gcc -g -Wall -Wextra -Wpedantic -Werror -Ofast -o program/program_1 program/program_1.c
gcc -g -Wall -Wextra -Wpedantic -Werror -Ofast -o program/program_2 program/program_2.c
gcc -g -Wall -Wextra -Wpedantic -Werror -Ofast -o program/program_4 program/program_4.c
gcc -g -Wall -Wextra -Wpedantic -Werror -Ofast -o program/program_z program/program_z.c
gcc -g -Wall -Wextra -Wpedantic -Werror -Ofast -o example/xcb_window example/xcb_window.c -lxcb

View File

@ -1 +1,235 @@
#include "../chapter/chapter_0.c"
#include "../chapter/chapter_1.c"
#include "../chapter/chapter_2.c"
#include "../chapter/chapter_3.c"
#include "../chapter/chapter_4.c"
static void highlight_common (void) {
char * separators = ".,:;<=>+-*/%!&~^?|()[]{}'\"@#$` \t\r\n";
syntax_define (FALSE, FALSE, "\"", "\"", '\\', COLOUR_PINK, EFFECT_NORMAL);
syntax_define (TRUE, FALSE, "()[]{}", "", '\0', COLOUR_BLUE, EFFECT_NORMAL);
syntax_define (TRUE, FALSE, ".,:;<=>+*-/%!&~^?|@#$`", "", '\0', COLOUR_CYAN, EFFECT_NORMAL);
syntax_define (TRUE, TRUE, "0123456789", separators, '\0', COLOUR_PINK, EFFECT_BOLD);
syntax_define (TRUE, TRUE, "abcdefghijklmnopqrstuvwxyz", separators, '\0', COLOUR_WHITE, EFFECT_NORMAL);
syntax_define (TRUE, TRUE, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", separators, '\0', COLOUR_WHITE, EFFECT_BOLD);
syntax_define (TRUE, TRUE, "_", separators, '\0', COLOUR_WHITE, EFFECT_ITALIC);
}
static void highlight_c (void) {
char * separators = ".,:;<=>+-*/%!&~^?|()[]{}'\" \t\r\n";
char * keywords [] = {
"register", "volatile", "auto", "const", "static", "extern", "if", "else",
"do", "while", "for", "continue", "switch", "case", "default", "break",
"enum", "union", "struct", "typedef", "goto", "void", "return", "sizeof",
"char", "short", "int", "long", "signed", "unsigned", "float", "double"
};
int word;
syntax_define (FALSE, FALSE, "/*", "*/", '\0', COLOUR_GREY, EFFECT_BOLD);
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);
syntax_define (FALSE, FALSE, "\"", "\"", '\\', COLOUR_PINK, EFFECT_NORMAL);
for (word = 0; word != (int) (sizeof (keywords) / sizeof (keywords [0])); ++word) {
syntax_define (FALSE, TRUE, keywords [word], separators, '\0', COLOUR_YELLOW, EFFECT_BOLD);
}
syntax_define (TRUE, FALSE, "()[]{}", "", '\0', COLOUR_BLUE, EFFECT_NORMAL);
syntax_define (TRUE, FALSE, ".,:;<=>+*-/%!&~^?|", "", '\0', COLOUR_CYAN, EFFECT_NORMAL);
syntax_define (TRUE, TRUE, "0123456789", separators, '\0', COLOUR_PINK, EFFECT_BOLD);
syntax_define (TRUE, TRUE, "abcdefghijklmnopqrstuvwxyz", separators, '\0', COLOUR_WHITE, EFFECT_NORMAL);
syntax_define (TRUE, TRUE, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", separators, '\0', COLOUR_WHITE, EFFECT_BOLD);
syntax_define (TRUE, TRUE, "_", separators, '\0', COLOUR_WHITE, EFFECT_ITALIC);
}
static void highlight_ada (void) {
char * separators = ".,:;<=>+-*/&|()\" \t\r\n";
char * keywords [] = {
"abort", "else", "new", "return", "abs", "elsif", "not", "reverse",
"abstract", "end", "null", "accept", "entry", "select", "access", "of",
"separate", "aliased", "exit", "or", "some", "all", "others", "subtype",
"and", "for", "out", "array", "function", "at", "tagged", "generic",
"package", "task", "begin", "goto", "pragma", "body", "private", "then",
"type", "case", "in", "constant", "until", "is", "raise", "use",
"if", "declare", "range", "delay", "limited", "record", "when", "delta",
"loop", "rem", "while", "digits", "renames", "with", "do", "mod",
"requeue", "xor", "procedure", "protected", "interface", "synchronized", "exception", "overriding",
"terminate"
};
int word;
syntax_define (FALSE, FALSE, "--", "\n", '\0', COLOUR_GREY, EFFECT_BOLD);
syntax_define (FALSE, FALSE, "'", "'", '\\', COLOUR_PINK, EFFECT_BOLD);
syntax_define (FALSE, FALSE, "\"", "\"", '\\', COLOUR_PINK, EFFECT_NORMAL);
for (word = 0; word != (int) (sizeof (keywords) / sizeof (keywords [0])); ++word) {
syntax_define (FALSE, TRUE, keywords [word], separators, '\0', COLOUR_YELLOW, EFFECT_BOLD);
}
syntax_define (TRUE, FALSE, "()", "", '\0', COLOUR_BLUE, EFFECT_NORMAL);
syntax_define (TRUE, FALSE, ".,:;<=>+-*/&|'", "", '\0', COLOUR_CYAN, EFFECT_NORMAL);
syntax_define (TRUE, TRUE, "0123456789", separators, '\0', COLOUR_PINK, EFFECT_BOLD);
syntax_define (TRUE, TRUE, "abcdefghijklmnopqrstuvwxyz", separators, '\0', COLOUR_WHITE, EFFECT_NORMAL);
syntax_define (TRUE, TRUE, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", separators, '\0', COLOUR_WHITE, EFFECT_BOLD);
}
static void highlight_cpp (void) {
char * separators = ".,:;<=>+-*/%!&~^?|()[]{}'\" \t\r\n";
char * keywords [] = {
"alignas", "alignof", "and", "and_eq", "asm", "atomic_cancel", "atomic_commit", "atomic_noexcept",
"auto", "bitand", "bitor", "bool", "break", "case", "catch", "char",
"char8_t", "char16_t", "char32_t", "class", "compl", "concept", "const", "consteval",
"constexpr", "constinit", "const_cast", "continue", "co_await", "co_return", "co_yield", "decltype",
"default", "delete", "do", "double", "dynamic_cast", "else", "enum", "explicit",
"export", "extern", "false", "float", "for", "friend", "goto", "if",
"inline", "int", "long", "mutable", "namespace", "new", "noexcept", "not",
"not_eq", "nullptr", "operator", "or", "or_eq", "private", "protected", "public",
"reflexpr", "register", "reinterpret_cast", "requires", "return", "short", "signed", "sizeof",
"static", "static_assert", "static_cast", "struct", "switch", "synchronized", "template", "this",
"thread_local", "throw", "true", "try", "typedef", "typeid", "typename", "union",
"unsigned", "using", "virtual", "void", "volatile", "wchar_t", "while", "xor",
"xor_eq", "final", "override", "import", "module", "transaction_safe"
};
int word;
syntax_define (FALSE, FALSE, "/*", "*/", '\0', COLOUR_GREY, EFFECT_BOLD);
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);
syntax_define (FALSE, FALSE, "\"", "\"", '\\', COLOUR_PINK, EFFECT_NORMAL);
for (word = 0; word != (int) (sizeof (keywords) / sizeof (keywords [0])); ++word) {
syntax_define (FALSE, TRUE, keywords [word], separators, '\0', COLOUR_YELLOW, EFFECT_BOLD);
}
syntax_define (TRUE, FALSE, "()[]{}", "", '\0', COLOUR_BLUE, EFFECT_NORMAL);
syntax_define (TRUE, FALSE, ".,:;<=>+*-/%!&~^?|", "", '\0', COLOUR_CYAN, EFFECT_NORMAL);
syntax_define (TRUE, TRUE, "0123456789", separators, '\0', COLOUR_PINK, EFFECT_BOLD);
syntax_define (TRUE, TRUE, "abcdefghijklmnopqrstuvwxyz", separators, '\0', COLOUR_WHITE, EFFECT_NORMAL);
syntax_define (TRUE, TRUE, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", separators, '\0', COLOUR_WHITE, EFFECT_BOLD);
syntax_define (TRUE, TRUE, "_", separators, '\0', COLOUR_WHITE, EFFECT_ITALIC);
}
static void highlight_flat_assembly (void) {
char * separators = ".,+-=:;(){}[]%$<> \t\r\n";
char * instructions [] = {
"mov", "movabs", "movapd", "movaps", "movebe", "movsd", "movsx", "movzx",
"movsxd", "movd", "movq", "movs", "movsb", "movsw", "movsd", "movsq",
"cmovmp", "cmovrcxz", "cmovc", "cmovnc", "cmove", "cmovne", "cmovz", "cmovnz",
"cmovg", "cmovng", "cmovge", "cmovnge", "cmovl", "cmovnl", "cmovle", "cmovnle",
"cmova", "cmovna", "cmovae", "cmovnae", "cmovb", "cmovnb", "cmovbe", "cmovnbe",
"cmovs", "cmovns", "cmovo", "cmovno", "cmovp", "cmovnp", "cmovpo", "cmovpe",
"cmp", "cmps", "cmpsb", "cmpsw", "cmpsd", "cmpsq", "cmpxchg", "lea",
"monitor", "cpuid", "in", "out", "syscall", "sysenter", "sysret", "sysexit",
"swap", "bswap", "pop", "push", "call", "ret", "enter", "leave",
"and", "or", "not", "neg", "sal", "sar", "shl", "shr",
"inc", "dec", "add", "sub", "mul", "div", "imul", "idiv",
"nop", "fnop", "adc", "sbb", "aaa", "aas", "aam", "aad",
"jmp", "jrcxz", "jc", "jnc", "je", "jne", "jz", "jnz",
"jg", "jng", "jge", "jnge", "jl", "jnl", "jle", "jnle",
"ja", "jna", "jae", "jnae", "jb", "jnb", "jbe", "jnbe",
"js", "jns", "jo", "jno", "jp", "jnp", "jpo", "jpe",
"rep", "repe", "repz", "repne", "repnz", "loop", "loope", "loopne"
};
char * registers [] = {
"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi",
"r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d",
"ax", "cx", "dx", "bx", "sp", "bp", "si", "di",
"r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w",
"al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
"r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b",
"ah", "ch", "dh", "bh"
};
char * keywords [] = {
"format", "executable", "readable", "writable", "segment", "sector", "entry", "macro",
"db", "dw", "dd", "dq", "rb", "rw", "rd", "rq"
};
int word;
syntax_define (FALSE, FALSE, ";", "\n", '\0', COLOUR_GREY, EFFECT_BOLD);
syntax_define (FALSE, FALSE, "'", "'", '\\', COLOUR_PINK, EFFECT_BOLD);
syntax_define (FALSE, FALSE, "\"", "\"", '\\', COLOUR_PINK, EFFECT_NORMAL);
for (word = 0; word != (int) (sizeof (instructions) / sizeof (instructions [0])); ++word) {
syntax_define (FALSE, TRUE, instructions [word], separators, '\0', COLOUR_YELLOW, EFFECT_BOLD);
}
for (word = 0; word != (int) (sizeof (registers) / sizeof (registers [0])); ++word) {
syntax_define (FALSE, TRUE, registers [word], separators, '\0', COLOUR_CYAN, EFFECT_BOLD);
}
for (word = 0; word != (int) (sizeof (keywords) / sizeof (keywords [0])); ++word) {
syntax_define (FALSE, TRUE, keywords [word], separators, '\0', COLOUR_YELLOW, EFFECT_ITALIC);
}
syntax_define (TRUE, FALSE, "()[]{}", "", '\0', COLOUR_BLUE, EFFECT_NORMAL);
syntax_define (TRUE, FALSE, ".,+-=:;%$<>", "", '\0', COLOUR_CYAN, EFFECT_NORMAL);
syntax_define (TRUE, TRUE, "0123456789", separators, '\0', COLOUR_PINK, EFFECT_BOLD);
syntax_define (TRUE, TRUE, "abcdefghijklmnopqrstuvwxyz", separators, '\0', COLOUR_WHITE, EFFECT_NORMAL);
syntax_define (TRUE, TRUE, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", separators, '\0', COLOUR_WHITE, EFFECT_BOLD);
syntax_define (TRUE, TRUE, "_", separators, '\0', COLOUR_WHITE, EFFECT_ITALIC);
}
int main (int argc, char * * argv) {
int offset = 0;
int select = 0;
int length = 0;
char * buffer = NULL;
if (argc < 2) {
print ("Usage: /1.//program_4 [text_file]/-\n");
return (EXIT_FAILURE);
}
select = file_type (argv [1]);
buffer = file_record (argv [1]);
if ((select == FILE_TYPE_C_SOURCE) || (select == FILE_TYPE_C_HEADER)) {
highlight_c ();
} else if ((select == FILE_TYPE_ADA_BODY) || (select == FILE_TYPE_ADA_SPECIFICATION)) {
highlight_ada ();
} else if ((select == FILE_TYPE_CPP_SOURCE) || (select == FILE_TYPE_CPP_HEADER)) {
highlight_cpp ();
} else if (select == FILE_TYPE_FLAT_ASSEMBLY) {
highlight_flat_assembly ();
} else {
highlight_common ();
}
for (offset = 0; buffer [offset] != '\0'; offset += length) {
select = syntax_select (& buffer [offset], & length);
if (select >= syntax_count) {
terminal_colour (COLOUR_WHITE, EFFECT_NORMAL);
} else {
terminal_colour (syntax_colour [select], syntax_effect [select]);
}
out (& buffer [offset], length);
terminal_cancel ();
}
buffer = deallocate (buffer);
return (EXIT_SUCCESS);
}

View File

@ -115,9 +115,9 @@ One sane C program should have the following structure (please keep in mind that
1) Header guards and implementation definitions.
2) System header files then project header files.
3) Macro definitions (please avoid them).
4) Internal function then variable declarations.
4) Internal function declarations then variable definitions.
5) External function then variable declarations.
6) Internal function then variable definition.
6) Internal function definition.
7) External function then variable definition.
8) Main function.
9) You can also define functions here if you want to.