summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKai Stevenson <kai@kaistevenson.com>2023-03-04 17:09:37 -0800
committerKai Stevenson <kai@kaistevenson.com>2023-03-04 17:09:37 -0800
commit482c9971568ab55878b5b4ac3c4add1385b29813 (patch)
tree32007c1ff0e8febae8eacceaac566730babd741b
parent2e9c68c309d004a38ab0c188c05f74291952e465 (diff)
added include guard
-rw-r--r--doc/precedent.114
-rw-r--r--src/precedent.c41
-rw-r--r--src/precedent.h2
3 files changed, 46 insertions, 11 deletions
diff --git a/doc/precedent.1 b/doc/precedent.1
index 6f04f12..5446323 100644
--- a/doc/precedent.1
+++ b/doc/precedent.1
@@ -12,6 +12,7 @@ supports imperative programming, with variable scoping and side-effects.
Precedent supports integers, floats, and strings, with basic functions
to manipulate each. Precedent has a simple pre-processor supporting
include statements, so libraries may be written to re-use code.
+Precedent runs in three stages: preprocess, parse, eval/exec.
.SH OPTIONS
\fB--help\fP
@@ -34,6 +35,7 @@ A key exists in some scope, and points to some symbol. There are default ("inter
keys, and keys created with store(). A key may accept parameters, making it a function.
.SH SYNTAX
+In the documentation to follow, square brackets are used to indicate blocks of precedent code. They are NOT part of the code--only for documentation readability.
Spaces, tabs, newlines, and other forms of whitespace are ignored.
A literal value is either a number or wrapped in quotation marks. The following
are examples of literal values: [ 123, "hello world", 9.81 ]. A key without arguments
@@ -42,6 +44,18 @@ is simply stated as a word. The following are examples of key references:
literals or key references. The following are examples of key references with arguments:
[ print("hello world"), print(myVar), print(eq(1, 2)) ]. Literals and keys may be separated by commas, semicolons, or spaces, to taste.
+.SH PREPROCESSOR
+The preprocessor is an extremely simple parser that runs before the file is passed to the main parser.
+The preprocessor supports two directives: include, and guarded include.
+Include is invoked as follows: [ &toinclude.pcdt ]. The file specified
+is then prepended to the current file.
+The file path is relative to the file that the preprocessor is evaluating. That is to say, a file's include statements should specify the path of the file they wish to include, relative to their own location.
+Guarded include is invoked as follows: [ @toinclude.pcdt ]. It is exactly
+equivalent to a regular include, except that any given file will only be
+included a single time. Suppose there is some library file math.pcdt. If a file
+includes two files, which each include math.pcdt, guarded include will prependonly one copy of math.pcdt to the beginning of the preprocessor output. Guarded include is more performant, and prevents overfilling the hashtable. Use it unless
+you have a very good reason not to.
+
.SH DETAILS
When a function defined by ref() is called as, e.g., myFunc(1, 1), its arguments (in this case, 1 and 1) are passed to the called function as arg0 and arg1. This implementation is subject to change.
Logical functions treat all non-zero integer values as TRUE, and 0 as FALSE. Passing a float or a string to such a function will usually result in an error. Some logical functions short-circuit, meaning that they will cease evaluation as soon as their condition can no longer be met. For example, if the first argument to all() is FALSE, it will not evaluate the rest of its arguments.
diff --git a/src/precedent.c b/src/precedent.c
index 1225a91..8351108 100644
--- a/src/precedent.c
+++ b/src/precedent.c
@@ -45,7 +45,11 @@ int main(int argc, char** argv) {
char* baseDir = malloc((strlen(dirName) + 2) * sizeof(char));
strcpy(baseDir, dirName);
strcat(baseDir, "/");
- char* finalContent = preprocess(read_file(path), baseDir);
+ hashtable_t* includeTable = init_hashtable(500, NULL);
+ char* baseContent = read_file(path);
+ char* finalContent = preprocess(baseContent, baseDir, includeTable);
+ destroy_hashtable(includeTable);
+ /* TODO: write hashtable information if debug */
sym_t* finalSymbol = parse_symbol_final(finalContent);
free(pathCpy);
free(baseDir);
@@ -82,15 +86,20 @@ char* read_file(char* path) {
out[length] = '\0';
return out;
}
-char* preprocess(char* str, char* baseDir) {
+char* preprocess(char* str, char* baseDir, hashtable_t* includeHt) {
while (1) {
int i = 0;
- while (str[i] != '@') {
+ while (str[i] != '@' && str[i] != '&') {
i++;
if (str[i] == '\0') {
return str;
}
}
+ char alwaysInclude = 0;
+ /* include even if already included */
+ if (str[i] == '&') {
+ alwaysInclude = 1;
+ }
str[i] = ' ';
i++;
char* includeName = malloc(40 * sizeof(char));
@@ -105,14 +114,26 @@ char* preprocess(char* str, char* baseDir) {
char* path = malloc((strlen(baseDir) + strlen(includeName) + 1) * sizeof(char));
strcpy(path, baseDir);
strcat(path, includeName);
- char* toInclude = preprocess(read_file(path), baseDir);
- char* newStr = malloc((strlen(toInclude) + strlen(str) + 1) * sizeof(char));
- strcpy(newStr, toInclude);
- strcat(newStr, str);
- free(str);
+ char* fileContent = read_file(path);
+ /* ensure the file has not already been included */
+ char notIncluded = hashtable_get_pair(includeHt, fileContent).key == NULL;
+ if (notIncluded) {
+ hashtable_add_pair(includeHt, init_pair(fileContent, NULL));
+ }
+ if (notIncluded || alwaysInclude) {
+ /* TODO: fix relative paths */
+ char* toInclude = preprocess(fileContent, baseDir, includeHt);
+ char* newStr = malloc((strlen(toInclude) + strlen(str) + 1) * sizeof(char));
+ strcpy(newStr, toInclude);
+ strcat(newStr, str);
+ free(str);
+ free(toInclude);
+ str = newStr;
+ }
+ else {
+ free(fileContent);
+ }
free(includeName);
free(path);
- free(toInclude);
- str = newStr;
}
}
diff --git a/src/precedent.h b/src/precedent.h
index 8a5110e..4956d9c 100644
--- a/src/precedent.h
+++ b/src/precedent.h
@@ -2,6 +2,6 @@
#include "hashtable.h"
#ifndef PRECEDENT
char* read_file(char* path);
-char* preprocess(char* str, char* baseDir);
+char* preprocess(char* str, char* baseDir, hashtable_t* includeHt);
#define PRECEDENT
#endif