diff --git a/.gitignore b/.gitignore
index 890e3b9..0b18635 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,3 @@
c2html
-example
-*.html
\ No newline at end of file
+*.html
+samples
\ No newline at end of file
diff --git a/c2html.c b/c2html.c
index 6c2ff57..b8bd96e 100644
--- a/c2html.c
+++ b/c2html.c
@@ -52,6 +52,7 @@ typedef enum {
T_FCALLNAME,
T_IDENTIFIER,
T_OPERATOR,
+ T_DIRECTIVE,
} Kind;
typedef struct {
@@ -103,7 +104,8 @@ static Token *tokenize(const char *str, long len)
Token T;
long curly_bracket_depth = 0;
- long bracket_depth = 0;
+ bool only_spaces_since_line_start = 1;
+ bool prev_nonspace_was_directive = 0;
do {
if(i == len) {
T.kind = T_DONE;
@@ -193,41 +195,121 @@ static Token *tokenize(const char *str, long len)
T.kind = T_VFLT;
} else T.kind = T_VINT;
T.len = i - T.off;
+ } else if(isalpha(str[i]) || str[i] == '_') {
+
+ T.off = i;
+ while(isalpha(str[i]) || isdigit(str[i]) || str[i] == '_')
+ i += 1;
+ T.len = i - T.off;
+
+ /* It may either be an identifier or a
+ * language keyword.
+ */
+
+ if(iskword(str + T.off, T.len))
+ T.kind = T_KWORD;
+ else {
+
+ /* If the identifier is followed by a '(' and
+ * it's in the global scope, then it's in a
+ * function definiton. If it's not in the global
+ * scope then it's a function call.
+ * Between the identifier and the '(' there may
+ * be some whitespace. An exception is made if
+ * before the identifier comes a preprocessor
+ * directive, in which case the '(' must come
+ * right after the identifier.
+ */
+
+ bool followed_by_parenthesis = 0;
+ bool yes_and_immediately = 0;
+ {
+ long k = i;
+ while(k < len && (str[k] == ' ' || str[k] == '\t'))
+ k += 1;
+
+ if(k < len && str[k] == '(') {
+ followed_by_parenthesis = 1;
+ if(k == i)
+ yes_and_immediately = 1;
+ }
+ }
+
+ if(followed_by_parenthesis) {
+ if(curly_bracket_depth == 0) {
+ if(prev_nonspace_was_directive) {
+ if(yes_and_immediately)
+ T.kind = T_FDECLNAME;
+ else
+ T.kind = T_IDENTIFIER;
+ } else
+ T.kind = T_FDECLNAME;
+ } else
+ T.kind = T_FCALLNAME;
+ } else {
+ T.kind = T_IDENTIFIER;
+ }
+ }
+
+ } else if(str[i] == '#' && only_spaces_since_line_start) {
+
+ // The first non-whitespace token of the line
+ // is a '#'. If it's followed by an alphabetical
+ // character, then it's a directive. (There may
+ // be whitespace between the '#' and the identifier)
+
+ long j = i; // Use a secondary cursor to explore
+ // what's after the '#'.
+
+ j += 1; // Skip the '#'.
+
+ // Skip spaces after the '#', if there are any.
+ while(j < len && (str[j] == ' ' || str[j] == '\t'))
+ j += 1;
+
+ if(isalpha(str[j])) {
+
+ // It's a preprocessor directive!
+
+ T.kind = T_DIRECTIVE;
+ T.off = i;
+
+ while(j < len && isalpha(str[j]))
+ j += 1;
+
+ T.len = j - T.off;
+
+ i = j;
+
+ } else {
+ // Wasn't a directive.. Just tokenize the '#'.
+ T.kind = '#';
+ T.off = i;
+ T.len = 1;
+ i += 1;
+ }
+
+ } else if(str[i] == '<' && prev_nonspace_was_directive) {
+
+ T.kind = T_VSTR;
+ T.off = i;
+ while(i < len && str[i] != '>')
+ i += 1;
+ if(i < len)
+ i += 1; // Skip the '>'.
+ T.len = i - T.off;
+
} else if(isoperat(str[i])) {
T.kind = T_OPERATOR;
T.off = i;
while(i < len && isoperat(str[i]))
i += 1;
T.len = i - T.off;
- } else if(isalpha(str[i]) || str[i] == '_') {
- T.off = i;
- while(isalpha(str[i]) || isdigit(str[i]) || str[i] == '_')
- i += 1;
- T.len = i - T.off;
- if(iskword(str + T.off, T.len))
- T.kind = T_KWORD;
- else {
- // Is the identifier followed by
- // a left parenthesis?
- long k = i;
- while(k < len && (str[k] == ' ' || str[k] == '\t'))
- k += 1;
- if(k < len && str[k] == '(') {
- if(curly_bracket_depth == 0)
- T.kind = T_FDECLNAME;
- else
- T.kind = T_FCALLNAME;
- } else {
- T.kind = T_IDENTIFIER;
- }
- }
} else {
switch(str[i]) {
case '{': curly_bracket_depth += 1; break;
case '}': curly_bracket_depth -= 1; break;
- case '(': bracket_depth += 1; break;
- case ')': bracket_depth -= 1; break;
}
T.kind = str[i];
@@ -236,6 +318,18 @@ static Token *tokenize(const char *str, long len)
i += 1;
}
+ if(T.kind == T_NEWL)
+ only_spaces_since_line_start = 1;
+ else
+ if(T.kind != T_TAB && T.kind != T_SPACE)
+ only_spaces_since_line_start = 0;
+
+ if(T.kind == T_DIRECTIVE)
+ prev_nonspace_was_directive = 1;
+ else
+ if(T.kind != T_TAB && T.kind != T_SPACE)
+ prev_nonspace_was_directive = 0;
+
if(count == capacity) {
int new_capacity;
if(capacity == 0)
@@ -367,8 +461,8 @@ static void print_escaped(buff_t *buff, const char *str, long len)
switch(str[j]) {
case '<': buff_printf(buff, "<"); break;
case '>': buff_printf(buff, ">"); break;
- case '\n': buff_printf(buff, "
"); break;
- case '\t': buff_printf(&buff, " "); break;
+ case '\n': buff_printf(buff, "
\n"); break;
+ case '\t': buff_printf(buff, " "); break;
case ' ':
if(j == 0 || str[j-1] != ' ')
@@ -504,6 +598,12 @@ char *c2html(const char *str, long len, _Bool table_mode, const char *class_pref
buff_printf(&buff, "");
break;
+ case T_DIRECTIVE:
+ buff_printf(&buff, "", class_prefix);
+ print_escaped(&buff, str + tokens[i].off, tokens[i].len);
+ buff_printf(&buff, "");
+ break;
+
default:
buff_printf(&buff, "%c", str[tokens[i].off]);
break;
diff --git a/style.css b/style.css
index e9a4421..fa08ab0 100644
--- a/style.css
+++ b/style.css
@@ -61,6 +61,7 @@
color: hsl(114, 31%, 68%);
}
+ .c2h-directive,
.c2h-kword {
color: hsl(300, 30%, 68%);
}