commit 8b3cc2461409f715de00d31e690257f83a94d7b3
parent 817c8ea4ee71f8c6a36793bde9391f9d6e6aa5da
Author: Virgil Dupras <hsoft@hardcoded.net>
Date: Tue, 19 Jul 2022 14:14:38 -0400
cc: make functions have internal linkage by default and add "extern"
Diffstat:
6 files changed, 53 insertions(+), 33 deletions(-)
diff --git a/fs/cc/ast.fs b/fs/cc/ast.fs
@@ -73,6 +73,7 @@ NODESZ 4 + ufield ast.func.sfsize
NODESZ 8 + ufield ast.func.type
NODESZ 12 + ufield ast.func.address
NODESZ 16 + ufield ast.func.cursf \ last SF offset computed
+NODESZ 20 + ufield ast.func.flags
NODESZ ufield ast.const.value
NODESZ ufield ast.ident.name
NODESZ ufield ast.uop.opid
@@ -84,6 +85,7 @@ ASTIDCNT stringlist astidnames
"unaryop" "postop" "binop" "list" "if" "str" "call" "for" "push" "pop"
0 value curunit \ points to current Unit, the beginning of the AST
+0 value curextern \ is current definition "extern"?
: idname ( id -- str ) astidnames slistiter ;
@@ -400,11 +402,14 @@ current to parseStatements
\\ Parse the next element in a Unit node
: parseUnit ( unitnode tok -- )
dup S" #[" s= if drop #[0 drop exit then
+ 0 to curextern
+ dup S" extern" s= if drop nextt 1 to curextern then
parseType _assert ( unode type ) parseType* ( unode type tok )
expectIdent ( unode type name ) rot nextt case ( type name unode )
S" (" of s=
AST_FUNCTION newnode ( type name fnode ) rot>
( name ) , 0 ( sfsize ) , ( type ) , 0 ( address ) , 0 ( cursf ) ,
+ curextern ( flags ) ,
dup parseArgSpecs parseStatements
endof
AST_DECLARE newnode ( type name dnode ) rot> , , ( dnode )
diff --git a/fs/cc/gen.fs b/fs/cc/gen.fs
@@ -180,7 +180,8 @@ ASTIDCNT wordtbl gentbl ( node -- )
:w ( Function )
_debug if ." debugging: " dup ast.func.name stype nl> then
ops$
- dup ast.func.name entry ( fnode )
+ dup ast.func.flags 1 and ( extern? ) if
+ dup ast.func.name entry then ( fnode )
here over to ast.func.address
dup ast.func.args ast.args.totsize over ast.func.locsize ( argsz locsz )
vmprelude, dup genchildren
diff --git a/fs/doc/cc.txt b/fs/doc/cc.txt
@@ -41,6 +41,8 @@ For this reason, the core of the language is very close to ANSI.
* string literals are not null-terminated, but "counted strings". The exact same
format as system strings.
* Added pspop() and pspush() built-in functions.
+* By default, functions have internal (static) linkage. The "extern" keyword
+ gives them external linkage (an entry in the system dict).
## Caller save
@@ -235,3 +237,15 @@ There are "shortcut words" for closing a macro:
c]# --> Constant ]#
i]# --> Ident ]#
+]# --> over addnode ]#
+
+## Linkage
+
+By default, functions have internal linkage. You give a function external
+linkage with "extern".
+
+void foo() { }
+extern void bar() { foo(); }
+
+This unit will compile fine. Because "foo()" is in the same unit as "bar()",
+"bar()" can call "foo()". However, that function can't be called from another
+unit or from Forth. "bar()" can.
diff --git a/fs/lib/crc.c b/fs/lib/crc.c
@@ -3,7 +3,7 @@
// TODO: use >>=
// TODO: replace if (b==1) with if (b)
-unsigned int crc32(unsigned int crc, int c) {
+extern unsigned int crc32(unsigned int crc, int c) {
unsigned int i;
unsigned int b;
diff --git a/fs/tests/cc/cc.fs b/fs/tests/cc/cc.fs
@@ -17,7 +17,6 @@ boolops 0 #eq
variables 82 #eq
funcall 42 #eq
42 pushpop 42 #eq
-2 3 adder 5 #eq
3 2 subber 1 #eq
42 plusone 43 #eq
ptrget 42 #eq
diff --git a/fs/tests/cc/test.c b/fs/tests/cc/test.c
@@ -3,76 +3,77 @@
#[ 42 const MYCONST ]#
// just return a constant
-int retconst() {
+extern int retconst() {
return #[ MYCONST c]# ;
}
// test unary op and that we don't require whitespace around symbols
-int neg() {return -$2a;}
-int bwnot() {
+extern int neg() {return -$2a;}
+extern int bwnot() {
return ~'*';
}
// test binop precedence
-int exprbinops() {
+extern int exprbinops() {
return 1 + 2 * 3;
}
-int binopand() {
+extern int binopand() {
return $ff & 42;
}
-int binopor() {
+extern int binopor() {
return 40 | 2;
}
-int binopxor() {
+extern int binopxor() {
return 43 ^ 1;
}
-int binopshl() {
+extern int binopshl() {
return 42 << 3;
}
-int binopshr() {
+extern int binopshr() {
return 42 >> 2;
}
// test some bug I was having
-int binop1(int a, int b) {
+extern int binop1(int a, int b) {
int c;
c = a ^ b;
return c;
}
-int boolops() {
+extern int boolops() {
return 66 < 54 && 2 == 2;
}
-int variables() {
+extern int variables() {
unsigned int foo = 40;
unsigned int _bar = 2;
_bar = foo + _bar;
return foo + _bar;
}
-int funcall() {
+extern int funcall() {
return retconst();
}
-void pushpop() {
+extern void pushpop() {
pspush(pspop());
}
+// this function has a internal linkage
int adder(int a, int b) {
return a + b;
}
-int subber(int a, int b) {
+extern int subber(int a, int b) {
return a - b;
}
// are arguments, both constants and lvalues, properly passed?
-int plusone(int x) {
+extern int plusone(int x) {
return adder(1, x);
}
-int ptrget() {
+extern int ptrget() {
int a = 42;
int *b = &a;
return *b;
}
-int ptrset() {
+extern int ptrset() {
int a = 42;
int *b = &a;
*b = 54;
return a;
}
-int condif(int x) {
+extern int condif(int x) {
if (x == 42) {
x = x+100;
} else {
@@ -81,29 +82,29 @@ int condif(int x) {
return x;
}
// test that ++ and -- modify the lvalue directly
-int incdec(int x) {
+extern int incdec(int x) {
++x;
--x;
return ++x;
}
// test that the final "--" doesn't affect the result
-int incdecp(int x) {
+extern int incdecp(int x) {
x++;
x--;
return ++x--;
}
// test that parens override precedence
-int exprparens() {
+extern int exprparens() {
return (1 + 2) * 3;
}
// test that a void function doesn't add anything to PS
-void cnoop() {}
+extern void cnoop() {}
// test that pointer arithmetics properly multiply operands by 2 or 4.
-int* ptrari(int *x) {
+extern int* ptrari(int *x) {
cnoop(); // this doesn't mess up PS
return x + 1;
}
-int array() {
+extern int array() {
int a[3] = {42, 12, 2};
return *a + a[1] - *(a+2);
}
@@ -111,26 +112,26 @@ int array() {
int global1 = 1234;
int global2[3] = {4, 5, 6};
-int global() {
+extern int global() {
return global1;
}
// "max" is a forth word defined in the system
-int sysword(int a, int b) {
+extern int sysword(int a, int b) {
max(a, b);
return pspop();
}
-void helloworld() {
+extern void helloworld() {
stype("Hello World!");
}
// Now let's put all this together an start calling fancy forth words!
// Here, we see the power of macros in action. Let's say we want to call the
// system word "=><=". It's not a valid C identifier, right? ok, but what about
// using macros to trick the parser into accepting it?
-int isinrange(int n, int l, int h) {
+extern int isinrange(int n, int l, int h) {
#[ S" =><=" i]# (n, l, h);
return pspop();
}
-int forloop(int a, int b) {
+extern int forloop(int a, int b) {
int i;
for (i=0; i<b; i++) {
a++;