duskos

dusk os fork
git clone git://git.alexwennerberg.com/duskos
Log | Files | Refs | README | LICENSE

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:
Mfs/cc/ast.fs | 5+++++
Mfs/cc/gen.fs | 3++-
Mfs/doc/cc.txt | 14++++++++++++++
Mfs/lib/crc.c | 2+-
Mfs/tests/cc/cc.fs | 1-
Mfs/tests/cc/test.c | 61+++++++++++++++++++++++++++++++------------------------------
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++;