Skip to content

Commit e6e4bf6

Browse files
committed
feat(main): add chart support
1 parent ea7fac8 commit e6e4bf6

File tree

8 files changed

+102
-13
lines changed

8 files changed

+102
-13
lines changed

src/ast.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,15 @@ AstExpr *ast_expr_make_int(long long value)
402402
return expr;
403403
}
404404

405+
AstExpr *ast_expr_make_char(long long value)
406+
{
407+
AstExpr *expr = xcalloc(1, sizeof(AstExpr));
408+
expr->kind = EXPR_INT_LITERAL;
409+
expr->type = TYPE_CHAR;
410+
expr->data.int_value = (long long)(unsigned char)value;
411+
return expr;
412+
}
413+
405414
AstExpr *ast_expr_make_float(double value)
406415
{
407416
AstExpr *expr = xcalloc(1, sizeof(AstExpr));
@@ -510,6 +519,10 @@ TypeKind ast_type_from_keyword(const char *kw)
510519
{
511520
return TYPE_INT;
512521
}
522+
if (strcmp(kw, "char") == 0)
523+
{
524+
return TYPE_CHAR;
525+
}
513526
if (strcmp(kw, "float") == 0)
514527
{
515528
return TYPE_FLOAT;
@@ -535,6 +548,8 @@ const char *ast_type_name(TypeKind type)
535548
{
536549
case TYPE_INT:
537550
return "int";
551+
case TYPE_CHAR:
552+
return "char";
538553
case TYPE_FLOAT:
539554
return "float";
540555
case TYPE_BOOL:

src/ast.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ typedef enum
77
{
88
TYPE_UNKNOWN = 0,
99
TYPE_INT,
10+
TYPE_CHAR,
1011
TYPE_FLOAT,
1112
TYPE_BOOL,
1213
TYPE_STRING,
@@ -236,6 +237,7 @@ AstExpr *ast_expr_make_array_literal(AstExprList *elements);
236237
AstExpr *ast_expr_make_subscript(AstExpr *array, AstExpr *index);
237238

238239
AstExpr *ast_expr_make_int(long long value);
240+
AstExpr *ast_expr_make_char(long long value);
239241
AstExpr *ast_expr_make_float(double value);
240242
AstExpr *ast_expr_make_bool(int value);
241243
AstExpr *ast_expr_make_string(char *value);

src/codegen_lua.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,12 @@ static void emit_main_wrapper(FILE *out, const AstFunction *fn, const FunctionSi
9797
case TYPE_INT:
9898
fprintf(out, "local %s = args_table and tonumber(args_table[%zu]) or 0\n", param->name, i + 1);
9999
break;
100+
case TYPE_CHAR:
101+
fprintf(out, "local %s = args_table and args_table[%zu] and string.byte(args_table[%zu]) or 0\n",
102+
param->name,
103+
i + 1,
104+
i + 1);
105+
break;
100106
case TYPE_FLOAT:
101107
fprintf(out, "local %s = args_table and tonumber(args_table[%zu]) or 0.0\n", param->name, i + 1);
102108
break;
@@ -271,15 +277,15 @@ static void emit_expression_expected(FILE *out, const AstExpr *expr, const Funct
271277
return;
272278
}
273279

274-
if (expected_type == TYPE_INT && actual == TYPE_FLOAT)
280+
if ((expected_type == TYPE_INT || expected_type == TYPE_CHAR) && actual == TYPE_FLOAT)
275281
{
276282
fputs("math.floor(", out);
277283
emit_expression_raw(out, expr, functions);
278284
fputc(')', out);
279285
return;
280286
}
281287

282-
if ((expected_type == TYPE_INT || expected_type == TYPE_FLOAT) && actual == TYPE_BOOL)
288+
if ((expected_type == TYPE_INT || expected_type == TYPE_FLOAT || expected_type == TYPE_CHAR) && actual == TYPE_BOOL)
283289
{
284290
fputc('(', out);
285291
emit_expression_as_bool(out, expr, functions);
@@ -400,6 +406,7 @@ static void emit_expression_as_bool(FILE *out, const AstExpr *expr, const Functi
400406
break;
401407
case TYPE_INT:
402408
case TYPE_FLOAT:
409+
case TYPE_CHAR:
403410
fputc('(', out);
404411
emit_expression_raw(out, expr, functions);
405412
fputs(" ~= 0)", out);
@@ -624,6 +631,9 @@ static void emit_array_default_value(FILE *out, TypeKind type)
624631
case TYPE_INT:
625632
fputs("0", out);
626633
break;
634+
case TYPE_CHAR:
635+
fputs("0", out);
636+
break;
627637
case TYPE_FLOAT:
628638
fputs("0.0", out);
629639
break;

src/lexer.l

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,43 @@ static char *yy_parse_string_literal(const char *src)
6060
buffer[out] = '\0';
6161
return buffer;
6262
}
63+
64+
static long long yy_parse_char_literal(const char *src)
65+
{
66+
size_t len = strlen(src);
67+
if (len < 3 || src[0] != '\'' || src[len - 1] != '\'')
68+
{
69+
return 0;
70+
}
71+
if (src[1] != '\\')
72+
{
73+
return (unsigned char)src[1];
74+
}
75+
if (len < 4)
76+
{
77+
return 0;
78+
}
79+
char esc = src[2];
80+
switch (esc)
81+
{
82+
case '\\':
83+
return '\\';
84+
case '\'':
85+
return '\'';
86+
case 'n':
87+
return '\n';
88+
case 'r':
89+
return '\r';
90+
case 't':
91+
return '\t';
92+
case '0':
93+
return '\0';
94+
case '"':
95+
return '"';
96+
default:
97+
return (unsigned char)esc;
98+
}
99+
}
63100
%}
64101

65102
%option noyywrap nodefault noinput nounput
@@ -70,6 +107,7 @@ static char *yy_parse_string_literal(const char *src)
70107

71108
[ \t\r\n]+ { /* skip whitespace */ }
72109
"int" { return KW_INT; }
110+
"char" { return KW_CHAR; }
73111
"float" { return KW_FLOAT; }
74112
"bool" { return KW_BOOL; }
75113
"void" { return KW_VOID; }
@@ -117,6 +155,7 @@ static char *yy_parse_string_literal(const char *src)
117155
"{" { return LBRACE; }
118156
"}" { return RBRACE; }
119157
\"([^\"\n]|\\.)*\" { yylval.string = yy_parse_string_literal(yytext); return STRING_LITERAL; }
158+
'([^\\'\n]|\\.)' { yylval.intValue = yy_parse_char_literal(yytext); return CHAR_LITERAL; }
120159
. { fprintf(stderr, "invalid character '%s'\n", yytext); }
121160

122161
%%

src/parser.y

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,11 @@ static void parser_error_cleanup(AstProgram **out_program);
4242
AstProgram *program;
4343
}
4444

45-
%token <intValue> INT_LITERAL
45+
%token <intValue> INT_LITERAL CHAR_LITERAL
4646
%token <floatValue> FLOAT_LITERAL
4747
%token <id> IDENT
4848
%token <string> STRING_LITERAL
49-
%token KW_INT KW_FLOAT KW_BOOL KW_VOID
49+
%token KW_INT KW_CHAR KW_FLOAT KW_BOOL KW_VOID
5050
%token RETURN
5151
%token WHILE FOR
5252
%token TRUE FALSE
@@ -109,6 +109,7 @@ function_definition
109109

110110
type_specifier
111111
: KW_INT { $$ = TYPE_INT; }
112+
| KW_CHAR { $$ = TYPE_CHAR; }
112113
| KW_FLOAT { $$ = TYPE_FLOAT; }
113114
| KW_BOOL { $$ = TYPE_BOOL; }
114115
| KW_VOID { $$ = TYPE_VOID; }
@@ -474,6 +475,10 @@ primary_expression
474475
{
475476
$$ = ast_expr_make_int($1);
476477
}
478+
| CHAR_LITERAL
479+
{
480+
$$ = ast_expr_make_char($1);
481+
}
477482
| FLOAT_LITERAL
478483
{
479484
$$ = ast_expr_make_float($1);

src/semantic.c

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -313,8 +313,8 @@ static int analyze_statement(SemanticInfo *info, AstFunction *fn, SymbolTable *s
313313
if (!is_boolean_like(cond_type))
314314
{
315315
semantic_error("while condition in function '%s' must be boolean-compatible but found %s",
316-
fn->name,
317-
ast_type_name(cond_type));
316+
fn->name,
317+
ast_type_name(cond_type));
318318
return 0;
319319
}
320320
int loop_has_return = 0;
@@ -339,8 +339,8 @@ static int analyze_statement(SemanticInfo *info, AstFunction *fn, SymbolTable *s
339339
if (!is_boolean_like(cond_type))
340340
{
341341
semantic_error("for condition in function '%s' must be boolean-compatible but found %s",
342-
fn->name,
343-
ast_type_name(cond_type));
342+
fn->name,
343+
ast_type_name(cond_type));
344344
ok = 0;
345345
}
346346
}
@@ -414,7 +414,10 @@ static TypeKind analyze_expression(SemanticInfo *info, SymbolTable *symbols, Ast
414414
switch (expr->kind)
415415
{
416416
case EXPR_INT_LITERAL:
417-
expr->type = TYPE_INT;
417+
if (expr->type != TYPE_CHAR)
418+
{
419+
expr->type = TYPE_INT;
420+
}
418421
return expr->type;
419422
case EXPR_FLOAT_LITERAL:
420423
expr->type = TYPE_FLOAT;
@@ -629,11 +632,11 @@ static int ensure_assignable(TypeKind target, TypeKind value)
629632
{
630633
return target == TYPE_STRING && value == TYPE_STRING;
631634
}
632-
if (target == TYPE_BOOL && (value == TYPE_INT || value == TYPE_FLOAT || value == TYPE_BOOL))
635+
if (target == TYPE_BOOL && (is_numeric(value) || value == TYPE_BOOL))
633636
{
634637
return 1;
635638
}
636-
if ((target == TYPE_INT || target == TYPE_FLOAT) && value == TYPE_BOOL)
639+
if (is_numeric(target) && value == TYPE_BOOL)
637640
{
638641
return 1;
639642
}
@@ -650,12 +653,12 @@ static int ensure_assignable(TypeKind target, TypeKind value)
650653

651654
static int is_numeric(TypeKind type)
652655
{
653-
return type == TYPE_INT || type == TYPE_FLOAT;
656+
return type == TYPE_INT || type == TYPE_FLOAT || type == TYPE_CHAR;
654657
}
655658

656659
static int is_boolean_like(TypeKind type)
657660
{
658-
return type == TYPE_BOOL || type == TYPE_INT || type == TYPE_FLOAT;
661+
return type == TYPE_BOOL || type == TYPE_INT || type == TYPE_FLOAT || type == TYPE_CHAR;
659662
}
660663

661664
static TypeKind arithmetic_result(TypeKind left, TypeKind right)

tests/pass/char.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
int main()
2+
{
3+
char a = 'A';
4+
char b = a + 1;
5+
int sum = a + b;
6+
printf("%d %d %d\n", a, b, sum);
7+
return 0;
8+
}

tests/pass/char.lua

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
os.exit((function(args)
2+
local a = 65
3+
local b = (a + 1)
4+
local sum = (a + b)
5+
print(string.format("%d %d %d", a, b, sum))
6+
return 0
7+
end)(arg))

0 commit comments

Comments
 (0)