repos / gbc

GBC - Go B Compiler
git clone https://github.com/xplshn/gbc.git

commit
407d53b
parent
aad8fd0
author
xplshn
date
2025-09-14 08:47:52 +0000 UTC
make pointers go-like

Signed-off-by: xplshn <[email protected]>
10 files changed,  +170, -154
M cmd/gbc/main.go
+7, -7
 1@@ -60,7 +60,12 @@ func main() {
 2 			cfg.SetWarning(config.WarnPedantic, true)
 3 		}
 4 
 5-		// Apply warning flags
 6+		// Apply language standard first
 7+		if err := cfg.ApplyStd(std); err != nil {
 8+			util.Error(token.Token{}, err.Error())
 9+		}
10+
11+		// Apply warning flags (override standard settings)
12 		for i, entry := range warningFlags {
13 			if entry.Enabled != nil && *entry.Enabled {
14 				cfg.SetWarning(config.Warning(i), true)
15@@ -70,7 +75,7 @@ func main() {
16 			}
17 		}
18 
19-		// Apply feature flags
20+		// Apply feature flags (override standard settings)
21 		for i, entry := range featureFlags {
22 			if entry.Enabled != nil && *entry.Enabled {
23 				cfg.SetFeature(config.Feature(i), true)
24@@ -80,11 +85,6 @@ func main() {
25 			}
26 		}
27 
28-		// Apply language standard
29-		if err := cfg.ApplyStd(std); err != nil {
30-			util.Error(token.Token{}, err.Error())
31-		}
32-
33 		// Set target architecture
34 		cfg.SetTarget(runtime.GOOS, runtime.GOARCH, target)
35 
M examples/cal3.bx
+5, -5
 1@@ -36,11 +36,11 @@ int main() {
 2     now := time(0);
 3     tptr := localtime(&now);
 4 
 5-    byte_ptr := (byte*)tptr;
 6-    year  := *((int*)(byte_ptr + 20)) + 1900;
 7-    month := *((int*)(byte_ptr + 16));    // 0 = Jan
 8-    today := *((int*)(byte_ptr + 12));
 9-    wday  := *((int*)(byte_ptr + 24));
10+    byte_ptr := (*byte)tptr;
11+    year  := *((*int)(byte_ptr + 20)) + 1900;
12+    month := *((*int)(byte_ptr + 16));    // 0 = Jan
13+    today := *((*int)(byte_ptr + 12));
14+    wday  := *((*int)(byte_ptr + 24));
15 
16     days := days_in_month(month, year);
17 
M examples/hashTable.bx
+7, -7
 1@@ -10,14 +10,14 @@ extrn putchar, getchar, printf, scanf, strlen, strcpy, strcmp, malloc;
 2 int TABLE_SIZE = 101;
 3 
 4 type struct Entry {
 5-    key   byte*;
 6-    value byte*;
 7-    next  Entry*;
 8+    key   *byte;
 9+    value *byte;
10+    next  *Entry;
11 };
12 
13-Entry* table[TABLE_SIZE];
14+*Entry table[TABLE_SIZE];
15 
16-int hash(key byte*) {
17+int hash(key *byte) {
18     result := 0;
19     i := 0;
20     while (key[i] != 0) {
21@@ -27,7 +27,7 @@ int hash(key byte*) {
22     return ((result % TABLE_SIZE + TABLE_SIZE) % TABLE_SIZE);
23 }
24 
25-void set(key, value byte*) {
26+void set(key, value *byte) {
27     index := hash(key);
28     entry := table[index];
29 
30@@ -53,7 +53,7 @@ void set(key, value byte*) {
31     table[index] = new_entry;
32 }
33 
34-byte* get(key byte*) {
35+*byte get(key *byte) {
36     index := hash(key);
37     entry := table[index];
38 
M examples/txtfmt.bx
+1, -1
1@@ -7,7 +7,7 @@ byte word_buf[50];
2 int line_len;
3 int word_len;
4 
5-void print_string(s byte*, len int) {
6+void print_string(s *byte, len int) {
7     auto i;
8     i = 0;
9     while (i < len) {
M pkg/config/config.go
+3, -1
 1@@ -260,7 +260,9 @@ func (c *Config) ApplyStd(stdName string) error {
 2 		{FeatExtrn, !isPedantic, true}, {FeatAsm, !isPedantic, true},
 3 		{FeatTyped, false, true}, {FeatShortDecl, false, true},
 4 		{FeatBxDeclarations, false, true}, {FeatStrictDecl, false, isPedantic},
 5-		{FeatFloat, false, true},
 6+		{FeatContinue, false, true}, {FeatNoDirectives, false, false},
 7+		{FeatFloat, false, true}, {FeatStrictTypes, false, false},
 8+		{FeatPromTypes, false, false},
 9 	}
10 
11 	switch stdName {
M pkg/parser/parser.go
+136, -122
  1@@ -176,7 +176,7 @@ func (p *Parser) parseTopLevel() *ast.Node {
  2 			stmt = p.parseUntypedGlobalDefinition(identTok)
  3 		}
  4 	default:
  5-		if p.isTypedPass && (p.isBuiltinType(p.current) || p.check(token.Const)) {
  6+		if p.isTypedPass && (p.isBuiltinType(p.current) || p.check(token.Const) || p.isPointerTypeAhead()) {
  7 			stmt = p.parseTypedVarOrFuncDecl(true)
  8 		} else {
  9 			stmt = p.parseExpr()
 10@@ -242,7 +242,7 @@ func (p *Parser) isBuiltinType(tok token.Token) bool {
 11 	return tok.Type >= token.Void && tok.Type <= token.Any
 12 }
 13 
 14-// isPointerCastAhead checks if the current position looks like a pointer cast: (type*)
 15+// isPointerCastAhead checks if the current position looks like a pointer cast: (*type)
 16 // This allows complex pointer casts while disallowing simple scalar C-style casts
 17 func (p *Parser) isPointerCastAhead() bool {
 18 	if !p.isTypedPass { return false }
 19@@ -252,29 +252,43 @@ func (p *Parser) isPointerCastAhead() bool {
 20 
 21 	if p.match(token.Const) {}
 22 
 23-	if p.isBuiltinType(p.current) {
 24-		p.advance()
 25-	} else if p.check(token.Ident) && p.isTypeName(p.current.Value) {
 26-		p.advance()
 27-	} else {
 28-		return false
 29-	}
 30-
 31+	// Check for Go-style pointer syntax: *type
 32 	hasPointer := false
 33 	if p.match(token.Star) {
 34 		hasPointer = true
 35-		for p.match(token.Star) {}
 36+		for p.match(token.Star) {} // Allow multiple stars for pointer-to-pointer
 37 	}
 38 
 39-	if p.match(token.LBracket) {
 40+	if p.isBuiltinType(p.current) {
 41+		p.advance()
 42+	} else if p.check(token.Ident) && p.isTypeName(p.current.Value) {
 43+		p.advance()
 44+	} else if p.match(token.LBracket) {
 45 		hasPointer = true
 46 		for !p.check(token.RBracket) && !p.check(token.EOF) { p.advance() }
 47 		if p.check(token.RBracket) { p.advance() }
 48+	} else {
 49+		return false
 50 	}
 51 
 52 	return hasPointer && p.check(token.RParen)
 53 }
 54 
 55+func (p *Parser) isPointerTypeAhead() bool {
 56+	if !p.check(token.Star) { return false }
 57+
 58+	originalPos, originalCurrent := p.pos, p.current
 59+	defer func() { p.pos, p.current = originalPos, originalCurrent }()
 60+
 61+	// Skip all consecutive * tokens
 62+	for p.check(token.Star) {
 63+		p.advance()
 64+	}
 65+
 66+	// Check if what follows the * is actually a type name
 67+	return p.isBuiltinType(p.current) || (p.check(token.Ident) && p.isTypeName(p.current.Value))
 68+}
 69+
 70 func (p *Parser) parseStmt() *ast.Node {
 71 	tok := p.current
 72 
 73@@ -298,7 +312,7 @@ func (p *Parser) parseStmt() *ast.Node {
 74 		return ast.NewLabel(tok, labelName, p.parseStmt())
 75 	}
 76 
 77-	if p.isTypedPass && (p.isBuiltinType(p.current) || (p.isTypeName(p.current.Value) && p.peek().Type != token.Define) || p.check(token.Const)) {
 78+	if p.isTypedPass && (p.isBuiltinType(p.current) || (p.isTypeName(p.current.Value) && p.peek().Type != token.Define) || p.check(token.Const) || p.isPointerTypeAhead()) {
 79 		return p.parseTypedVarOrFuncDecl(false)
 80 	}
 81 
 82@@ -882,85 +896,85 @@ func (p *Parser) parseTypedVarDeclBody(startTok token.Token, declType *ast.BxTyp
 83 }
 84 
 85 func (p *Parser) parseType() *ast.BxType {
 86-	if !p.isTypedPass {
 87-		return nil
 88-	}
 89-
 90-	isConst := p.match(token.Const)
 91-	var baseType *ast.BxType
 92-
 93-	if p.match(token.LBracket) {
 94-		p.expect(token.RBracket, "Expected ']' to complete array type specifier")
 95-		elemType := p.parseType()
 96-		baseType = &ast.BxType{Kind: ast.TYPE_ARRAY, Base: elemType}
 97-	} else {
 98-		tok := p.current
 99-		if p.match(token.Struct) {
100-			if p.check(token.Ident) && p.peek().Type != token.LBrace {
101-				tagName := p.current.Value
102-				p.advance()
103-				baseType = &ast.BxType{Kind: ast.TYPE_STRUCT, Name: tagName, StructTag: tagName}
104-			} else {
105-				baseType = p.parseStructDef()
106-			}
107-		} else if p.match(token.Enum) {
108-			if p.check(token.Ident) {
109-				tagName := p.current.Value
110-				p.advance()
111-				baseType = &ast.BxType{Kind: ast.TYPE_ENUM, Name: tagName}
112-			} else {
113-				util.Error(tok, "Anonymous enums are not supported as types")
114-				baseType = ast.TypeUntyped
115-			}
116-		} else if p.isBuiltinType(tok) {
117-			p.advance()
118-			var typeName string
119-			for keyword, t := range token.KeywordMap {
120-				if t == p.previous.Type {
121-					typeName = keyword
122-					break
123-				}
124-			}
125-
126-			if p.previous.Type == token.Void {
127-				baseType = ast.TypeVoid
128-			} else if p.previous.Type == token.StringKeyword {
129-				baseType = ast.TypeString
130-			} else if p.previous.Type >= token.Float && p.previous.Type <= token.Float64 {
131-				baseType = &ast.BxType{Kind: ast.TYPE_FLOAT, Name: typeName}
132-			} else {
133-				if typeName == "" {
134-					util.Error(tok, "Internal parser error: could not find string for builtin type %v", tok.Type)
135-					return ast.TypeUntyped
136-				}
137-				baseType = &ast.BxType{Kind: ast.TYPE_PRIMITIVE, Name: typeName}
138-			}
139-		} else if p.check(token.Ident) {
140-			typeName := p.current.Value
141-			if !p.isTypeName(typeName) {
142-				util.Error(p.current, "Unknown type name '%s'", typeName)
143-				p.advance()
144-				return ast.TypeUntyped
145-			}
146-			p.advance()
147-			baseType = &ast.BxType{Kind: ast.TYPE_PRIMITIVE, Name: typeName}
148-		} else {
149-			util.Error(p.current, "Expected a type name, 'struct', 'enum', or '[]'")
150-			p.advance()
151-			return ast.TypeUntyped
152-		}
153-	}
154-
155-	for p.match(token.Star) {
156-		baseType = &ast.BxType{Kind: ast.TYPE_POINTER, Base: baseType}
157-	}
158-
159-	if isConst {
160-		newType := *baseType
161-		newType.IsConst = true
162-		return &newType
163-	}
164-	return baseType
165+    if !p.isTypedPass {
166+        return nil
167+    }
168+
169+    isConst := p.match(token.Const)
170+    var baseType *ast.BxType
171+
172+    // Handle Go-style pointer syntax (*int)
173+    if p.match(token.Star) {
174+        elemType := p.parseType()
175+        baseType = &ast.BxType{Kind: ast.TYPE_POINTER, Base: elemType}
176+    } else if p.match(token.LBracket) {
177+        p.expect(token.RBracket, "Expected ']' to complete array type specifier")
178+        elemType := p.parseType()
179+        baseType = &ast.BxType{Kind: ast.TYPE_ARRAY, Base: elemType}
180+    } else {
181+        tok := p.current
182+        if p.match(token.Struct) {
183+            if p.check(token.Ident) && p.peek().Type != token.LBrace {
184+                tagName := p.current.Value
185+                p.advance()
186+                baseType = &ast.BxType{Kind: ast.TYPE_STRUCT, Name: tagName, StructTag: tagName}
187+            } else {
188+                baseType = p.parseStructDef()
189+            }
190+        } else if p.match(token.Enum) {
191+            if p.check(token.Ident) {
192+                tagName := p.current.Value
193+                p.advance()
194+                baseType = &ast.BxType{Kind: ast.TYPE_ENUM, Name: tagName}
195+            } else {
196+                util.Error(tok, "Anonymous enums are not supported as types")
197+                baseType = ast.TypeUntyped
198+            }
199+        } else if p.isBuiltinType(tok) {
200+            p.advance()
201+            var typeName string
202+            for keyword, t := range token.KeywordMap {
203+                if t == p.previous.Type {
204+                    typeName = keyword
205+                    break
206+                }
207+            }
208+
209+            if p.previous.Type == token.Void {
210+                baseType = ast.TypeVoid
211+            } else if p.previous.Type == token.StringKeyword {
212+                baseType = ast.TypeString
213+            } else if p.previous.Type >= token.Float && p.previous.Type <= token.Float64 {
214+                baseType = &ast.BxType{Kind: ast.TYPE_FLOAT, Name: typeName}
215+            } else {
216+                if typeName == "" {
217+                    util.Error(tok, "Internal parser error: could not find string for builtin type %v", tok.Type)
218+                    return ast.TypeUntyped
219+                }
220+                baseType = &ast.BxType{Kind: ast.TYPE_PRIMITIVE, Name: typeName}
221+            }
222+        } else if p.check(token.Ident) {
223+            typeName := p.current.Value
224+            if !p.isTypeName(typeName) {
225+                util.Error(p.current, "Unknown type name '%s'", typeName)
226+                p.advance()
227+                return ast.TypeUntyped
228+            }
229+            p.advance()
230+            baseType = &ast.BxType{Kind: ast.TYPE_PRIMITIVE, Name: typeName}
231+        } else {
232+            util.Error(p.current, "Expected a type name, 'struct', 'enum', or '[]'")
233+            p.advance()
234+            return ast.TypeUntyped
235+        }
236+    }
237+
238+    if isConst {
239+        newType := *baseType
240+        newType.IsConst = true
241+        return &newType
242+    }
243+    return baseType
244 }
245 
246 func (p *Parser) parseStructDef() *ast.BxType {
247@@ -1129,21 +1143,21 @@ func (p *Parser) parseAssignmentExpr() *ast.Node {
248 	// Try to detect multi-assignment pattern: lhs1, lhs2, ... = rhs1, rhs2, ...
249 	startPos := p.pos
250 	startCurrent := p.current
251-	
252+
253 	// Parse first expression
254 	left := p.parseTernaryExpr()
255-	
256+
257 	// Check if this could be a multi-assignment (comma followed by more expressions then equals)
258 	if p.check(token.Comma) {
259 		var lhsList []*ast.Node
260 		lhsList = append(lhsList, left)
261-		
262+
263 		// Parse comma-separated lvalues
264 		for p.match(token.Comma) {
265 			expr := p.parseTernaryExpr()
266 			lhsList = append(lhsList, expr)
267 		}
268-		
269+
270 		// Check if we have an assignment operator
271 		if op := p.current.Type; op >= token.Eq && op <= token.EqShr {
272 			// Validate all lhs expressions are lvalues
273@@ -1152,10 +1166,10 @@ func (p *Parser) parseAssignmentExpr() *ast.Node {
274 					util.Error(p.current, "Invalid target for assignment")
275 				}
276 			}
277-			
278+
279 			tok := p.current
280 			p.advance()
281-			
282+
283 			// Parse comma-separated rvalues
284 			var rhsList []*ast.Node
285 			for {
286@@ -1165,21 +1179,21 @@ func (p *Parser) parseAssignmentExpr() *ast.Node {
287 					break
288 				}
289 			}
290-			
291+
292 			// Check that number of lhs and rhs match
293 			if len(lhsList) != len(rhsList) {
294 				util.Error(tok, "Mismatched number of variables and values in assignment (%d vs %d)", len(lhsList), len(rhsList))
295 			}
296-			
297+
298 			return ast.NewMultiAssign(tok, op, lhsList, rhsList)
299 		}
300-		
301+
302 		// Not a multi-assignment, backtrack and treat as comma expression
303 		p.pos = startPos
304 		p.current = startCurrent
305 		left = p.parseTernaryExpr()
306 	}
307-	
308+
309 	// Regular single assignment
310 	if op := p.current.Type; op >= token.Eq && op <= token.EqShr {
311 		if !isLValue(left) {
312@@ -1225,26 +1239,26 @@ func (p *Parser) parseBinaryExpr(minPrec int) *ast.Node {
313 }
314 
315 func (p *Parser) parseUnaryExpr() *ast.Node {
316-	tok := p.current
317-	if p.match(token.Not, token.Complement, token.Minus, token.Plus, token.Inc, token.Dec, token.Star, token.And) {
318-		op, opToken := p.previous.Type, p.previous
319-		operand := p.parseUnaryExpr()
320-
321-		if op == token.Star {
322-			return ast.NewIndirection(tok, operand)
323-		}
324-		if op == token.And {
325-			if !isLValue(operand) {
326-				util.Error(opToken, "Address-of operator '&' requires an l-value")
327-			}
328-			return ast.NewAddressOf(tok, operand)
329-		}
330-		if (op == token.Inc || op == token.Dec) && !isLValue(operand) {
331-			util.Error(opToken, "Prefix '++' or '--' requires an l-value")
332-		}
333-		return ast.NewUnaryOp(tok, op, operand)
334-	}
335-	return p.parsePostfixExpr()
336+    tok := p.current
337+    if p.match(token.Not, token.Complement, token.Minus, token.Plus, token.Inc, token.Dec, token.Star, token.And) {
338+        op, opToken := p.previous.Type, p.previous
339+        operand := p.parseUnaryExpr()
340+
341+        if op == token.Star {
342+            return ast.NewIndirection(tok, operand)
343+        }
344+        if op == token.And {
345+            if !isLValue(operand) {
346+                util.Error(opToken, "Address-of operator '&' requires an l-value")
347+            }
348+            return ast.NewAddressOf(tok, operand)
349+        }
350+        if (op == token.Inc || op == token.Dec) && !isLValue(operand) {
351+            util.Error(opToken, "Prefix '++' or '--' requires an l-value")
352+        }
353+        return ast.NewUnaryOp(tok, op, operand)
354+    }
355+    return p.parsePostfixExpr()
356 }
357 
358 func (p *Parser) parsePostfixExpr() *ast.Node {
M tests/arrays.bx
+5, -5
 1@@ -3,7 +3,7 @@ extrn printf, malloc;
 2 type struct Point {
 3     x int;
 4     y int;
 5-    name byte*;
 6+    name *byte;
 7 };
 8 
 9 type enum Color {
10@@ -128,9 +128,9 @@ void demo_pointer_arrays() {
11     printf("\nPointer arrays:\n");
12 
13     int values[3];
14-    int* int_ptr_array[3];
15-    byte* string_array[3];
16-    void* void_ptr_array[3];
17+    *int int_ptr_array[3];
18+    *byte string_array[3];
19+    *void void_ptr_array[3];
20 
21     values[0] = 42;
22     values[1] = 84;
23@@ -210,7 +210,7 @@ void demo_enum_arrays() {
24 void demo_struct_pointer_arrays() {
25     printf("\nStruct pointer arrays:\n");
26 
27-    Point *point_ptr_array[2];
28+    *Point point_ptr_array[2];
29 
30     point_ptr_array[0] = malloc(sizeof(Point));
31     point_ptr_array[1] = malloc(sizeof(Point));
M tests/casting.bx
+2, -2
 1@@ -9,8 +9,8 @@ main() {
 2     printf("Function-style casts: a=%d, int(a)=%d, (int(a)+1)=%d\n", a, b, c);
 3 
 4     ptr := &a;
 5-    byte_ptr := (byte*)ptr;
 6-    int_ptr := (int*)byte_ptr;
 7+    byte_ptr := (*byte)ptr;
 8+    int_ptr := (*int)byte_ptr;
 9     value := *int_ptr;
10 
11     printf("Pointer casts work: value=%d\n", value);
M tests/edge.bx
+2, -2
 1@@ -3,10 +3,10 @@ type struct Inner {
 2 };
 3 
 4 type struct Outer {
 5-    inner Inner*;
 6+    inner *Inner;
 7 };
 8 
 9-Outer* createOuter(val int) {
10+*Outer createOuter(val int) {
11     auto i = Inner{value: val};
12     auto o = Outer{inner: &i};
13     return (&o);
M tests/enums3.bx
+2, -2
 1@@ -22,12 +22,12 @@ Shape create_shape(c Color, x int, y int) {
 2 }
 3 
 4 void print_shape(s Shape) {
 5-    color_names := []byte*{ "RED", "GREEN", "BLUE", "YELLOW" };
 6+    color_names := []*byte{ "RED", "GREEN", "BLUE", "YELLOW" };
 7     printf("Shape: %s at (%d, %d)\n",
 8            color_names[s.shape_color], s.x_pos, s.y_pos);
 9 }
10 
11-void move_shape(s Shape*, dx int, dy int) {
12+void move_shape(s *Shape, dx int, dy int) {
13     s.x_pos = s.x_pos + dx;
14     s.y_pos = s.y_pos + dy;
15 }