first functional state of syntax tree

This commit is contained in:
Felix Müller 2024-05-13 22:17:43 +02:00
parent 0e5736e50c
commit 3d3083c894
3 changed files with 271 additions and 105 deletions

View File

@ -70,11 +70,15 @@ void AST_init() {
lookup_table[AST_Box] = "box"; lookup_table[AST_Box] = "box";
lookup_table[AST_Fun] = "fun"; lookup_table[AST_Fun] = "fun";
lookup_table[AST_Call] = "funcall";
lookup_table[AST_Typecast] = "cast"; lookup_table[AST_Typecast] = "cast";
lookup_table[AST_Transmute] = "as"; lookup_table[AST_Transmute] = "as";
lookup_table[AST_Condition] = "condition"; lookup_table[AST_Condition] = "condition";
lookup_table[AST_List] = "list"; lookup_table[AST_List] = "list";
lookup_table[AST_Type] = "type"; lookup_table[AST_Type] = "type";
lookup_table[AST_Negate] = "-";
lookup_table[AST_Parameter] = "parameter";
lookup_table[AST_ParamDecl] = "parameter-declaration";
} }
const char* AST_node_to_string(const struct AST_Node_t* node) { const char* AST_node_to_string(const struct AST_Node_t* node) {
@ -90,11 +94,11 @@ const char* AST_node_to_string(const struct AST_Node_t* node) {
case AST_Ident: case AST_Ident:
case AST_Macro: case AST_Macro:
case AST_Import: case AST_Import:
case AST_Call:
case AST_Storage: case AST_Storage:
case AST_Typekind: case AST_Typekind:
case AST_Sign: case AST_Sign:
case AST_Scale: case AST_Scale:
case AST_Qualifyier:
string = node->value; string = node->value;
break; break;
default: default:

View File

@ -59,14 +59,18 @@ enum AST_SyntaxElement_t {
AST_Fun, AST_Fun,
AST_Import, AST_Import,
// amount of variants // amount of variants
// in this enum // in this enums
AST_ELEMENT_COUNT,
AST_List, AST_List,
AST_Storage, AST_Storage,
AST_Type, AST_Type,
AST_Typekind, AST_Typekind,
AST_Sign, AST_Sign,
AST_Scale AST_Scale,
AST_Negate,
AST_Parameter,
AST_Qualifyier,
AST_ParamDecl,
AST_ELEMENT_COUNT
}; };
/** /**

View File

@ -1,4 +1,4 @@
%{ %code requires {
#include <sys/log.h> #include <sys/log.h>
#include <ast/ast.h> #include <ast/ast.h>
extern int yylineno; extern int yylineno;
@ -6,39 +6,56 @@
int yyerror(char*); int yyerror(char*);
extern int yylex(); extern int yylex();
%}
}
%union { %union {
char *string; char *string;
AST_NODE_PTR node_ptr;
} }
%type <AST_NODE_PTR> expr %type <node_ptr> operation
%type <AST_NODE_PTR> operation %type <node_ptr> boxaccess
%type <AST_NODE_PTR> boxaccess %type <node_ptr> boxselfaccess
%type <AST_NODE_PTR> boxselfaccess %type <node_ptr> statement
%type <AST_NODE_PTR> statement %type <node_ptr> statementlist
%type <AST_NODE_PTR> statementlist %type <node_ptr> assign
%type <AST_NODE_PTR> assign %type <node_ptr> oparith
%type <AST_NODE_PTR> oparith %type <node_ptr> decl
%type <AST_NODE_PTR> decl %type <node_ptr> definition
%type <AST_NODE_PTR> definition %type <node_ptr> while
%type <AST_NODE_PTR> while %type <node_ptr> branch
%type <AST_NODE_PTR> branch %type <node_ptr> funcall
%type <AST_NODE_PTR> funcall %type <node_ptr> boxcall
%type <AST_NODE_PTR> boxcall %type <node_ptr> branchelseifs
%type <AST_NODE_PTR> branchelseifs %type <node_ptr> branchelse
%type <AST_NODE_PTR> branchelse %type <node_ptr> branchelseif
%type <AST_NODE_PTR> branchelseif %type <node_ptr> branchif
%type <AST_NODE_PTR> branchif %type <node_ptr> type
%type <AST_NODE_PTR> type %type <node_ptr> identlist
%type <AST_NODE_PTR> identlist %type <node_ptr> storagequalifier
%type <AST_NODE_PTR> storagequalifier %type <node_ptr> typekind
%type <AST_NODE_PTR> typekind %type <node_ptr> scale
%type <AST_NODE_PTR> scale %type <node_ptr> sign
%type <AST_NODE_PTR> sign %type <node_ptr> expr
%type <AST_NODE_PTR> oplogic %type <node_ptr> oplogic
%type <AST_NODE_PTR> opbool %type <node_ptr> opbool
%type <AST_NODE_PTR> opbit %type <node_ptr> opbit
%type <node_ptr> moduleimport
%type <node_ptr> programbody
%type <node_ptr> fundef
%type <node_ptr> box
%type <node_ptr> typedef
%type <node_ptr> exprlist
%type <node_ptr> argumentlist
%type <node_ptr> paramlist
%type <node_ptr> params
%type <node_ptr> IOqualifyier
%type <node_ptr> paramdecl
%type <node_ptr> boxbody
%type <node_ptr> boxcontent
%type <node_ptr> program
%token KeyInt %token KeyInt
@ -94,78 +111,172 @@
%left OpBitand OpBitor OpBitxor OpBitnot %left OpBitand OpBitor OpBitxor OpBitnot
%% %%
program: program programbody program: program programbody {AST_push_node($1, $2);
FILE *file = fopen("test.txt", "w");
AST_fprint_graphviz(file, $1);
fclose(file);}
| programbody {AST_NODE_PTR program = AST_new_node(AST_Module, NULL); | programbody {AST_NODE_PTR program = AST_new_node(AST_Module, NULL);
AST_fprint_graphviz(stdout, program); }; AST_push_node(program, $1);
FILE *file = fopen("test.txt", "w");
AST_fprint_graphviz(file, program);
fclose(file); };
programbody: moduleimport programbody: moduleimport {$$ = $1;}
| fundef | fundef{$$ = $1;}
| box | box{$$ = $1;}
| definition | definition{$$ = $1;}
| decl | decl{$$ = $1;}
| typedef; | typedef{$$ = $1;};
expr: ValFloat {$$ = AST_new_node{AST_Float, $1};} expr: ValFloat {$$ = AST_new_node(AST_Float, $1);}
| ValInt {$$ = AST_new_node{AST_Int, $1};} | ValInt {$$ = AST_new_node(AST_Int, $1);}
| ValMultistr {$$ = AST_new_node{AST_String, $1};} | ValMultistr {$$ = AST_new_node(AST_String, $1);}
| ValStr {$$ = AST_new_node{AST_String, $1};} | ValStr {$$ = AST_new_node(AST_String, $1);}
| Ident {$$ = AST_new_node{AST_Ident, $1};} | Ident {$$ = AST_new_node(AST_Ident, $1);}
| operation {$$ = $1;} | operation {$$ = $1;}
| boxaccess {$$ = $1;} | boxaccess {$$ = $1;}
| boxselfaccess{$$ = $1;}; | boxselfaccess{$$ = $1;};
exprlist: expr ',' exprlist exprlist: expr ',' exprlist {AST_push_node($3, $1);
| expr ; $$ = $3;}
| expr {AST_NODE_PTR list = AST_new_node(AST_List, NULL);
AST_push_node(list, $1);
$$ = list;};
argumentlist: argumentlist '(' exprlist ')' argumentlist: argumentlist '(' exprlist ')' {AST_push_node($1, $3);
| ; $$ = $1;}
| '(' exprlist ')'{AST_NODE_PTR list = AST_new_node(AST_List, NULL);
AST_push_node(list, $2);
$$ = list;};
fundef: KeyFun Ident paramlist '{' statementlist'}' { DEBUG("Function");}; fundef: KeyFun Ident paramlist '{' statementlist'}' {AST_NODE_PTR fun = AST_new_node(AST_Fun, NULL);
AST_NODE_PTR ident = AST_new_node(AST_Ident, $2);
AST_push_node(fun, ident);
AST_push_node(fun, $3);
AST_push_node(fun, $5);
$$ = fun;
DEBUG("Function");};
paramlist: paramlist '(' params ')' paramlist: paramlist '(' params ')' {AST_push_node($1, $3);
| paramlist '(' ')' $$ = $1;}
| '(' params ')' | paramlist '(' ')'{$$ = $1;}
| '(' ')'; | '(' params ')' {AST_NODE_PTR list = AST_new_node(AST_List, NULL);
AST_push_node(list, $2);}
| '(' ')' {$$ = AST_new_node(AST_List, NULL);};
params: IOqualifyier paramdecl ',' params params: IOqualifyier paramdecl ',' params {AST_NODE_PTR parameter = AST_new_node(AST_Parameter, NULL);
| IOqualifyier paramdecl; AST_push_node(parameter, $1);
AST_push_node(parameter, $2);
AST_push_node($4, parameter);
$$ = $4;}
| IOqualifyier paramdecl {AST_NODE_PTR list = AST_new_node(AST_List, NULL);
AST_NODE_PTR parameter = AST_new_node(AST_Parameter, NULL);
AST_push_node(parameter, $1);
AST_push_node(parameter, $2);
AST_push_node(list, parameter);
$$ = list;};
IOqualifyier: KeyIn IOqualifyier: KeyIn { AST_NODE_PTR in = AST_new_node(AST_Qualifyier, "in");
| KeyOut AST_NODE_PTR list = AST_new_node(AST_List, NULL);
| KeyIn KeyOut AST_push_node(list, in);
| KeyOut KeyIn $$ = list;}
| ; | KeyOut{ AST_NODE_PTR out = AST_new_node(AST_Qualifyier, "out");
AST_NODE_PTR list = AST_new_node(AST_List, NULL);
AST_push_node(list, out);
$$ = list;}
| KeyIn KeyOut{ AST_NODE_PTR in = AST_new_node(AST_Qualifyier, "in");
AST_NODE_PTR out = AST_new_node(AST_Qualifyier, "out");
AST_NODE_PTR list = AST_new_node(AST_List, NULL);
AST_push_node(list, in);
AST_push_node(list, out);
$$ = list;}
| KeyOut KeyIn{ AST_NODE_PTR in = AST_new_node(AST_Qualifyier, "in");
AST_NODE_PTR out = AST_new_node(AST_Qualifyier, "out");
AST_NODE_PTR list = AST_new_node(AST_List, NULL);
AST_push_node(list, in);
AST_push_node(list, out);
$$ = list;}
| {$$ = AST_new_node(AST_List, NULL);};
paramdecl: type ':' Ident { DEBUG("Param-Declaration"); }; paramdecl: type ':' Ident { AST_NODE_PTR paramdecl = AST_new_node(AST_ParamDecl, NULL);
AST_push_node(paramdecl, $1);
AST_NODE_PTR ident = AST_new_node(AST_Ident, $3);
AST_push_node(paramdecl, ident);
$$ = paramdecl;
DEBUG("Param-Declaration"); };
box: KeyType KeyBox ':' Ident '{' boxbody '}' { DEBUG("Box"); } box: KeyType KeyBox ':' Ident '{' boxbody '}' {AST_NODE_PTR box = AST_new_node(AST_Box, NULL);
| KeyType KeyBox ':' Ident '{' '}'; AST_NODE_PTR ident = AST_new_node(AST_Ident, $4);
AST_push_node(box, ident);
AST_push_node(box, $6);
$$ = box;
DEBUG("Box"); }
| KeyType KeyBox ':' Ident '{' '}' {AST_NODE_PTR box = AST_new_node(AST_Box, NULL);
AST_NODE_PTR ident = AST_new_node(AST_Ident, $4);
AST_push_node(box, ident);
$$ = box;};
boxbody: boxbody boxcontent boxbody: boxbody boxcontent {AST_push_node($1, $2);
| boxcontent; $$ = $1;}
| boxcontent {AST_NODE_PTR list = AST_new_node(AST_List, NULL);
AST_push_node(list, $1);
$$ = list;};
boxcontent: decl { DEBUG("Box decl Content"); } boxcontent: decl { $$ = $1;DEBUG("Box decl Content"); }
| definition { DEBUG("Box def Content"); } | definition { $$ = $1;DEBUG("Box def Content"); }
| fundef { DEBUG("Box fun Content"); }; | fundef { $$ = $1;DEBUG("Box fun Content"); };
boxselfaccess: KeySelf '.' Ident {$$ = AST_new_node(AST_Call, NULL);} boxselfaccess: KeySelf '.' Ident {AST_NODE_PTR boxselfaccess = AST_new_node(AST_List, NULL);
| KeySelf '.' boxaccess {$$ = AST_new_node(AST_Call, NULL);}; AST_NODE_PTR self = AST_new_node(AST_Ident, "self");
AST_push_node(boxselfaccess, self);
AST_NODE_PTR identlist = AST_new_node(AST_List, NULL);
AST_NODE_PTR ident = AST_new_node(AST_Ident, $3);
AST_push_node(identlist,ident);
AST_push_node(boxselfaccess, identlist);
$$ = boxselfaccess;}
| KeySelf '.' boxaccess {AST_NODE_PTR boxselfaccess = AST_new_node(AST_List, NULL);
AST_NODE_PTR self = AST_new_node(AST_Ident, "self");
AST_push_node(boxselfaccess, self);
AST_push_node(boxselfaccess, $3);
$$ = boxselfaccess;};
boxaccess: Ident '.' Ident {$$ = AST_new_node(AST_Call, NULL);} boxaccess: Ident '.' Ident {AST_NODE_PTR identlist = AST_new_node(AST_List, NULL);
| Ident '.' boxaccess {$$ = AST_new_node(AST_Ident, $1);}; AST_NODE_PTR ident1 = AST_new_node(AST_Ident, $1);
AST_NODE_PTR ident2 = AST_new_node(AST_Ident, $3);
AST_push_node(identlist,ident1);
AST_push_node(identlist,ident2);
$$ = identlist;}
| Ident '.' boxaccess {AST_NODE_PTR ident = AST_new_node(AST_Ident, $1);
AST_push_node($3,ident);
$$ = $3;};
boxcall: boxaccess argumentlist boxcall: boxaccess argumentlist {AST_NODE_PTR boxcall = AST_new_node(AST_Call, NULL);
| boxselfaccess argumentlist; AST_push_node(boxcall, $1);
AST_push_node(boxcall, $2);
$$ = boxcall;}
| boxselfaccess argumentlist {AST_NODE_PTR boxcall = AST_new_node(AST_Call, NULL);
AST_push_node(boxcall, $1);
AST_push_node(boxcall, $2);
$$ = boxcall;};
funcall: Ident argumentlist { DEBUG("Function call"); }; funcall: Ident argumentlist {AST_NODE_PTR funcall = AST_new_node(AST_Call, NULL);
AST_NODE_PTR ident = AST_new_node(AST_Ident, $1);
AST_push_node(funcall, ident);
AST_push_node(funcall, $2);
$$ = funcall;
DEBUG("Function call"); };
moduleimport: KeyImport ValStr { DEBUG("Module-Import"); }; moduleimport: KeyImport ValStr {$$ = AST_new_node(AST_Import, $2);
DEBUG("Module-Import"); };
statementlist: statement statementlist statementlist: statementlist statement {AST_push_node($1, $2);
| statement {$$ = $1;}; $$ = $1;}
| statement {AST_NODE_PTR list = AST_new_node(AST_List, NULL);
AST_push_node(list, $1);
$$ = list;};
statement: assign {$$ = $1;} statement: assign {$$ = $1;}
| decl {$$ = $1;} | decl {$$ = $1;}
@ -190,14 +301,20 @@ branch: branchif branchelseifs {AST_NODE_PTR branch = AST_new_node(AST_Stmt, NUL
AST_push_node(branch, $2); AST_push_node(branch, $2);
$$ = branch;} $$ = branch;}
| branchif branchelseifs branchelse { AST_NODE_PTR branch = AST_new_node(AST_IF, NULL);}; | branchif branchelseifs branchelse { AST_NODE_PTR branch = AST_new_node(AST_Stmt, NULL);
AST_push_node(branch, $1);
AST_push_node(branch, $2);
AST_push_node(branch, $3);
$$ = branch;};
while: KeyWhile expr '{' statementlist '}' { DEBUG("while"); }; while: KeyWhile expr '{' statementlist '}' { DEBUG("while"); };
identlist: Ident ',' identlist {AST_push_node($3, $1); identlist: Ident ',' identlist {AST_NODE_PTR ident = AST_new_node(AST_Ident, $1);
AST_push_node($3, ident);
$$ = $3;} $$ = $3;}
| Ident {AST_NODE_PTR list = AST_new_node(AST_List, NULL); | Ident {AST_NODE_PTR list = AST_new_node(AST_List, NULL);
AST_push_node(list, $1); AST_NODE_PTR ident = AST_new_node(AST_Ident, $1);
AST_push_node(list, ident);
$$ = list;}; $$ = list;};
decl: type ':' identlist {AST_NODE_PTR decl = AST_new_node(AST_Decl, NULL); decl: type ':' identlist {AST_NODE_PTR decl = AST_new_node(AST_Decl, NULL);
@ -211,7 +328,11 @@ decl: type ':' identlist {AST_NODE_PTR decl = AST_new_node(AST_Decl, NULL);
$$ = decl;} $$ = decl;}
definition: decl '=' expr { DEBUG("Definition"); }; definition: decl '=' expr { AST_NODE_PTR def = AST_new_node(AST_Def, NULL);
AST_push_node(def, $1);
AST_push_node(def, $3);
$$ = def;
DEBUG("Definition"); };
storagequalifier: KeyGlobal {$$ = AST_new_node(AST_Storage, "global");} storagequalifier: KeyGlobal {$$ = AST_new_node(AST_Storage, "global");}
| KeyStatic {$$ = AST_new_node(AST_Storage, "static");} | KeyStatic {$$ = AST_new_node(AST_Storage, "static");}
@ -229,7 +350,11 @@ assign: Ident '=' expr { AST_NODE_PTR assign = AST_new_node(AST_Assign, NULL);
sign: KeySigned {$$ = AST_new_node(AST_Sign, "signed");} sign: KeySigned {$$ = AST_new_node(AST_Sign, "signed");}
| KeyUnsigned{$$ = AST_new_node(AST_Sign, "unsigned");}; | KeyUnsigned{$$ = AST_new_node(AST_Sign, "unsigned");};
typedef: KeyType type':' Ident; typedef: KeyType type':' Ident {AST_NODE_PTR typeDef = AST_new_node(AST_Typedef, NULL);
AST_push_node(typeDef, $2);
AST_NODE_PTR ident = AST_new_node(AST_Ident, $4);
AST_push_node(typeDef, ident);
$$ = typeDef;};
scale: scale KeyShort {AST_NODE_PTR shortnode = AST_new_node(AST_Scale, "short"); scale: scale KeyShort {AST_NODE_PTR shortnode = AST_new_node(AST_Scale, "short");
AST_push_node($1, shortnode); AST_push_node($1, shortnode);
@ -264,18 +389,18 @@ typekind: Ident {$$ = AST_new_node(AST_Typekind, $1);}
| KeyInt {$$ = AST_new_node(AST_Typekind, "int");} | KeyInt {$$ = AST_new_node(AST_Typekind, "int");}
| KeyFloat {$$ = AST_new_node(AST_Typekind, "float");}; | KeyFloat {$$ = AST_new_node(AST_Typekind, "float");};
type: typekind {AST_NODE_PTR type = AST_new_node(AST_type, NULL); type: typekind {AST_NODE_PTR type = AST_new_node(AST_Type, NULL);
AST_push_node(type, $1); AST_push_node(type, $1);
$$ = type;} $$ = type;}
| scale typekind {AST_NODE_PTR type = AST_new_node(AST_type, NULL); | scale typekind {AST_NODE_PTR type = AST_new_node(AST_Type, NULL);
AST_push_node(type, $1); AST_push_node(type, $1);
AST_push_node(type, $2); AST_push_node(type, $2);
$$ = type;} $$ = type;}
| sign typekind {AST_NODE_PTR type = AST_new_node(AST_type, NULL); | sign typekind {AST_NODE_PTR type = AST_new_node(AST_Type, NULL);
AST_push_node(type, $1); AST_push_node(type, $1);
AST_push_node(type, $2); AST_push_node(type, $2);
$$ = type;} $$ = type;}
| sign scale typekind {AST_NODE_PTR type = AST_new_node(AST_type, NULL); | sign scale typekind {AST_NODE_PTR type = AST_new_node(AST_Type, NULL);
AST_push_node(type, $1); AST_push_node(type, $1);
AST_push_node(type, $2); AST_push_node(type, $2);
AST_push_node(type, $3); AST_push_node(type, $3);
@ -286,37 +411,70 @@ operation: oparith {$$ = $1;}
| opbool {$$ = $1;} | opbool {$$ = $1;}
| opbit {$$ = $1;}; | opbit {$$ = $1;};
oparith: expr '+' expr {AST_NODE_PTR add = AST_new_node{AST_Add, NULL}; oparith: expr '+' expr {AST_NODE_PTR add = AST_new_node(AST_Add, NULL);
AST_push_node(add, $1); AST_push_node(add, $1);
AST_push_node(add, $3); AST_push_node(add, $3);
$$ = add;} $$ = add;}
| expr '-' expr {AST_NODE_PTR subtract = AST_new_node{AST_Sub, NULL}; | expr '-' expr {AST_NODE_PTR subtract = AST_new_node(AST_Sub, NULL);
AST_push_node(subtract, $1); AST_push_node(subtract, $1);
AST_push_node(subtract, $3); AST_push_node(subtract, $3);
$$ = subtract;} $$ = subtract;}
| expr '*' expr {AST_NODE_PTR mul = AST_new_node{AST_Mul, NULL}; | expr '*' expr {AST_NODE_PTR mul = AST_new_node(AST_Mul, NULL);
AST_push_node(mul, $1); AST_push_node(mul, $1);
AST_push_node(mul, $3); AST_push_node(mul, $3);
$$ = mul;} $$ = mul;}
| expr '/' expr {AST_NODE_PTR div = AST_new_node{AST_Div, NULL}; | expr '/' expr {AST_NODE_PTR div = AST_new_node(AST_Div, NULL);
AST_push_node(div, $1); AST_push_node(div, $1);
AST_push_node(div, $3); AST_push_node(div, $3);
$$ = div;} $$ = div;}
| '-' expr %prec '*'; | '-' expr %prec '*'{AST_NODE_PTR negator = AST_new_node(AST_Negate, NULL);
AST_push_node(negator, $2);
$$ = negator;};
oplogic: expr OpEquals expr oplogic: expr OpEquals expr {AST_NODE_PTR equals = AST_new_node(AST_Eq, NULL);
| expr '<' expr AST_push_node(equals, $1);
| expr '>' expr; AST_push_node(equals, $3);
$$ = equals;}
| expr '<' expr {AST_NODE_PTR less = AST_new_node(AST_Less, NULL);
AST_push_node(less, $1);
AST_push_node(less, $3);
$$ = less;}
| expr '>' expr{AST_NODE_PTR greater = AST_new_node(AST_Greater, NULL);
AST_push_node(greater, $1);
AST_push_node(greater, $3);
$$ = greater;};
opbool: expr OpAnd expr opbool: expr OpAnd expr {AST_NODE_PTR and = AST_new_node(AST_BoolAnd, NULL);
| expr OpOr expr AST_push_node(and, $1);
| expr OpXor expr AST_push_node(and, $3);
| OpNot expr %prec OpAnd; $$ = and;}
| expr OpOr expr{AST_NODE_PTR or = AST_new_node(AST_BoolOr, NULL);
AST_push_node(or, $1);
AST_push_node(or, $3);
$$ = or;}
| expr OpXor expr{AST_NODE_PTR xor = AST_new_node(AST_BoolXor, NULL);
AST_push_node(xor, $1);
AST_push_node(xor, $3);
$$ = xor;}
| OpNot expr %prec OpAnd{AST_NODE_PTR not = AST_new_node(AST_BoolNot, NULL);
AST_push_node(not, $2);
$$ = not;};
opbit: expr OpBitand expr opbit: expr OpBitand expr {AST_NODE_PTR and = AST_new_node(AST_BitAnd, NULL);
| expr OpBitor expr AST_push_node(and, $1);
| expr OpBitxor expr AST_push_node(and, $3);
| OpBitnot expr %prec OpBitand; $$ = and;}
| expr OpBitor expr{AST_NODE_PTR or = AST_new_node(AST_BitOr, NULL);
AST_push_node(or, $1);
AST_push_node(or, $3);
$$ = or;}
| expr OpBitxor expr{AST_NODE_PTR xor = AST_new_node(AST_BitXor, NULL);
AST_push_node(xor, $1);
AST_push_node(xor, $3);
$$ = xor;}
| OpBitnot expr %prec OpBitand{AST_NODE_PTR not = AST_new_node(AST_BitNot, NULL);
AST_push_node(not, $2);
$$ = not;};
%% %%
int yyerror(char *s) { int yyerror(char *s) {