added logic for preprocessor directives
This commit is contained in:
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
c2html
|
c2html
|
||||||
example
|
|
||||||
*.html
|
*.html
|
||||||
|
samples
|
||||||
@@ -52,6 +52,7 @@ typedef enum {
|
|||||||
T_FCALLNAME,
|
T_FCALLNAME,
|
||||||
T_IDENTIFIER,
|
T_IDENTIFIER,
|
||||||
T_OPERATOR,
|
T_OPERATOR,
|
||||||
|
T_DIRECTIVE,
|
||||||
} Kind;
|
} Kind;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -103,7 +104,8 @@ static Token *tokenize(const char *str, long len)
|
|||||||
|
|
||||||
Token T;
|
Token T;
|
||||||
long curly_bracket_depth = 0;
|
long curly_bracket_depth = 0;
|
||||||
long bracket_depth = 0;
|
bool only_spaces_since_line_start = 1;
|
||||||
|
bool prev_nonspace_was_directive = 0;
|
||||||
do {
|
do {
|
||||||
if(i == len) {
|
if(i == len) {
|
||||||
T.kind = T_DONE;
|
T.kind = T_DONE;
|
||||||
@@ -193,41 +195,121 @@ static Token *tokenize(const char *str, long len)
|
|||||||
T.kind = T_VFLT;
|
T.kind = T_VFLT;
|
||||||
} else T.kind = T_VINT;
|
} else T.kind = T_VINT;
|
||||||
T.len = i - T.off;
|
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])) {
|
} else if(isoperat(str[i])) {
|
||||||
T.kind = T_OPERATOR;
|
T.kind = T_OPERATOR;
|
||||||
T.off = i;
|
T.off = i;
|
||||||
while(i < len && isoperat(str[i]))
|
while(i < len && isoperat(str[i]))
|
||||||
i += 1;
|
i += 1;
|
||||||
T.len = i - T.off;
|
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 {
|
} else {
|
||||||
|
|
||||||
switch(str[i]) {
|
switch(str[i]) {
|
||||||
case '{': curly_bracket_depth += 1; break;
|
case '{': curly_bracket_depth += 1; break;
|
||||||
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];
|
T.kind = str[i];
|
||||||
@@ -236,6 +318,18 @@ static Token *tokenize(const char *str, long len)
|
|||||||
i += 1;
|
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) {
|
if(count == capacity) {
|
||||||
int new_capacity;
|
int new_capacity;
|
||||||
if(capacity == 0)
|
if(capacity == 0)
|
||||||
@@ -367,8 +461,8 @@ static void print_escaped(buff_t *buff, const char *str, long len)
|
|||||||
switch(str[j]) {
|
switch(str[j]) {
|
||||||
case '<': buff_printf(buff, "<"); break;
|
case '<': buff_printf(buff, "<"); break;
|
||||||
case '>': buff_printf(buff, ">"); break;
|
case '>': buff_printf(buff, ">"); break;
|
||||||
case '\n': buff_printf(buff, "<br />"); break;
|
case '\n': buff_printf(buff, "<br />\n"); break;
|
||||||
case '\t': buff_printf(&buff, "    "); break;
|
case '\t': buff_printf(buff, "    "); break;
|
||||||
|
|
||||||
case ' ':
|
case ' ':
|
||||||
if(j == 0 || str[j-1] != ' ')
|
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, "</span>");
|
buff_printf(&buff, "</span>");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case T_DIRECTIVE:
|
||||||
|
buff_printf(&buff, "<span class=\"%sdirective\">", class_prefix);
|
||||||
|
print_escaped(&buff, str + tokens[i].off, tokens[i].len);
|
||||||
|
buff_printf(&buff, "</span>");
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
buff_printf(&buff, "%c", str[tokens[i].off]);
|
buff_printf(&buff, "%c", str[tokens[i].off]);
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user