first asm gen lets gooo

This commit is contained in:
victor 2025-04-29 19:00:46 +02:00
parent d46febe6fc
commit aac7ef9fbc
11 changed files with 722 additions and 234 deletions

View File

@ -7,6 +7,7 @@ MEMDIR := $(COREDIR)/mem
SYSCALLDIR := $(COREDIR)/syscall
FILEDIR := $(COREDIR)/file
PARSEDIR := $(SRCDIR)/parse
VARDIR := $(PARSEDIR)/vars
# Define source files
MATHSRC := $(addprefix $(MATHDIR)/, $(addsuffix .s, \
@ -29,11 +30,15 @@ SYSCALLSRC := $(addprefix $(SYSCALLDIR)/, $(addsuffix .s, \
))
PARSESRC := $(addprefix $(PARSEDIR)/, $(addsuffix .s, \
parse debug_token create_expressions debug_expression \
lexer \
lexer lex_load lex_err \
))
VARSRC := $(addprefix $(VARDIR)/, $(addsuffix .s, \
get_vars insert_var \
))
# Collect all source files - now using the file variables, not directory variables
SRC := $(SRCDIR)/start.s $(MATHSRC) $(STRSRC) $(PRINTSRC) $(FILESRC) $(PARSESRC) $(SYSCALLSRC) $(MEMSRC)
SRC := $(SRCDIR)/start.s $(MATHSRC) $(STRSRC) $(PRINTSRC) $(FILESRC) $(VARSRC) $(PARSESRC) $(SYSCALLSRC) $(MEMSRC)
OBJDIR := obj
OBJ := $(patsubst %.s,$(OBJDIR)/%.o,$(notdir $(SRC)))
@ -68,6 +73,9 @@ $(OBJDIR)/%.o: $(FILEDIR)/%.s
$(OBJDIR)/%.o: $(PARSEDIR)/%.s
nasm -felf64 -F dwarf -g $< -o $@
$(OBJDIR)/%.o: $(VARDIR)/%.s
nasm -felf64 -F dwarf -g $< -o $@
$(OBJDIR):
mkdir -p $@

View File

@ -2,9 +2,10 @@
%define LEX_VAR_CNT 4
%define LEX_EXPR 8
%define LEX_VAR 16
%define LEX_OUT 24
%define LEX_EXPR_IDX 24
%define LEX_OUT 32
%define LEX_SIZE 32
%define LEX_SIZE 64
%define VAR_NAME 0
%define VAR_OFFS 8
@ -19,4 +20,5 @@
; .var_cnt 4
; .expr* 8
; .vars 16
; .output** 24
; .expr_idx 24
; .output** 32

3
src/inc/regs.s Normal file
View File

@ -0,0 +1,3 @@
section .data
REG_RAX: db "rax", 0

View File

@ -4,12 +4,6 @@ section .data
token: db 0xa, "Token ", 0
type: db "type = ", 0
value: db "value = ", 0
VAL_CONST: db "const", 0
VAL_VAR: db "variable", 0
VAL_OP_ADD: db "operator '+'", 0
VAL_OP_SUB: db "operator '-'", 0
VAL_OP_LOAD: db "operator '='", 0
VAL_FUNC: db "function call", 0
section .text
global print_tokens
@ -18,7 +12,14 @@ section .text
extern putchar
extern putnumberendl
extern get_split_count
extern VAL_CONST
extern VAL_VAR
extern VAL_OP_ADD
extern VAL_OP_SUB
extern VAL_OP_LOAD
extern VAL_FUNC
global print_token_type
print_token_type: ; (rdi: int)
cmp rdi, TOK_LOAD
je .tok_load

31
src/parse/lex_err.s Normal file
View File

@ -0,0 +1,31 @@
%define LEX_ERROR 0xa, "[LEX_ERROR] "
section .data
EEXPECT: db LEX_ERROR, "expected: ", 0
EUNDEFINED: db LEX_ERROR, "undefined: ", 0
section .text
extern putstr
extern putendl
extern exit
extern print_token_type
global lex_eundefined
lex_eundefined: ; (rdi: tok_val*)
push rdi
mov rdi, EUNDEFINED
call putstr
pop rdi
call putendl
mov rdi, 1
call exit
global lex_eexpect
lex_eexpect: ; (rdi: tok_type)
push rdi
mov rdi, EEXPECT
call putstr
pop rdi
call print_token_type
mov rdi, 1
call exit

201
src/parse/lex_load.s Normal file
View File

@ -0,0 +1,201 @@
%include "./src/inc/lexer.s"
%include "./src/inc/expression.s"
%include "./src/inc/token.s"
%include "./src/inc/regs.s"
section .text
extern malloc
extern err_malloc
extern exit
extern putstr
extern create_expressions
extern strcmp
extern VAL_OP_LOAD
extern VAL_OP_ADD
extern VAL_VAR
extern VAL_CONST
extern putchar
extern putnumber
extern putendl
extern get_vars
extern insert_var
extern insert_mov
extern load_var_rax
extern load_rax_var
extern op_const_rax
extern op_var_rax
extern xor_reg
extern look_up_var
extern lex_eexpect
extern lex_eundefined
global lex_load
; look_up_var: ; rax: OFF_S (rdi: vars*, rsi: name*, rdx: n)
process_var: ; (rdi: lex*, rsi: name*, rdx: tok_op)
push rbp
mov rbp, rsp
sub rsp, 16
push rdx
push rdi
; !!! will exit if var not defined
call look_up_var
pop rdi
pop rdx
mov rdi, rax
mov rsi, rdx
call op_var_rax
mov rsp, rbp
pop rbp
ret
process_token: ; rax: new_last_tok_type (rdi: lex*, rsi: *tok, rdx: last_tok_type)
cmp rdx, TOK_VAR
je .expect_operator
cmp rdx, TOK_CONST
je .expect_operator
cmp rdx, TOK_ADD
je .expect_value
cmp rdx, TOK_SUB
je .expect_value
.expect_value:
cmp qword [rsi + TOK_TYPE], TOK_VAR
je .process_var
cmp qword [rsi + TOK_TYPE], TOK_CONST
je .process_const
mov rdi, VAL_VAR
call lex_eexpect
.process_var:
mov rsi, [rsi + TOK_VALUE]
call process_var
mov rax, TOK_VAR
jmp .done
.process_const:
mov rsi, [rsi + TOK_VALUE]
mov rsi, rdx
call op_const_rax
mov rax, TOK_CONST
jmp .done
.expect_operator:
cmp qword [rsi + TOK_TYPE], TOK_ADD
je .process_add
cmp qword [rsi + TOK_TYPE], TOK_SUB
je .process_sub
mov rdi, VAL_OP_ADD
call lex_eexpect
.process_add:
mov rax, TOK_ADD
jmp .done
.process_sub:
mov rax, TOK_SUB
.done:
ret
is_assignment: ; rax: OFF_S (rdi: expr*)
xor rax, rax
mov rcx, [rdi + EXPR_TOK_CNT]
mov rdx, [rdi + EXPR_TOK]
cmp qword [rdx + TOK_TYPE], TOK_VAR
jne .done
cmp qword [rdx + TOK_TYPE + SIZE_TOK], TOK_LOAD
jne .done
mov rax, 1
.done:
ret
lex_load: ; (rdi: lex*)
push rbp
mov rbp, rsp
sub rsp, 48
; store lexer
mov [rbp - 8], rdi
; store expression based on lexer expression index
mov rsi, [rdi + LEX_EXPR]
mov rax, [rdi + LEX_EXPR_IDX]
imul rax, EXPR_SIZE
lea rsi, [rsi + rax]
mov [rbp - 16], rsi
; store tok_cnt
mov rsi, [rsi + EXPR_TOK_CNT]
mov [rbp - 24], rsi
; local var store last token type
mov qword [rbp - 32], -1
mov rdi, [rbp - 16]
push rdi
call is_assignment
test rax, rax
jz .done_false
mov rdi, [rbp - 8]
mov rsi, [rbp - 16]
mov rsi, [rsi + EXPR_TOK]
mov rsi, [rsi + TOK_VALUE]
call look_up_var
mov [rbp - 40], rax
mov rdi, [rbp - 16]
mov rdi, [rdi + EXPR_TOK]
mov rdi, [rdi + TOK_VALUE]
mov rdi, REG_RAX
call xor_reg
pop rdi
; advance token ptr
mov rsi, [rdi + EXPR_TOK]
xor rcx, rcx
add rcx, 2
lea rsi, [rsi + SIZE_TOK * 2]
.loop_tokens:
cmp rcx, [rbp - 24]
je .done_true
push rcx
push rsi
mov rdx, [rbp - 32]
mov rdi, [rbp - 8]
call process_token
pop rsi
mov [rbp - 32], rax
add rsi, SIZE_TOK
pop rcx
inc rcx
jmp .loop_tokens
.done_true:
mov rdi, [rbp - 40]
call load_rax_var
mov rax, 1
.done_false:
mov rsp, rbp
pop rbp
ret

View File

@ -2,16 +2,7 @@
%include "./src/inc/lexer.s"
%include "./src/inc/expression.s"
%include "./src/inc/asm_output.s"
%define LEX_ERROR 0xa, "[LEX_ERROR] "
section .data
EEXPECT: db LEX_ERROR, "expected: ", 0
MOV: db "mov ", 0
OPEN_STACK_VAR: db "[rbp - ", 0
CLOSE_STACK_VAR: db "], ", 0
%include "./src/inc/regs.s"
section .text
extern malloc
@ -21,139 +12,25 @@ section .text
extern create_expressions
extern strcmp
extern VAL_OP_LOAD
extern VAL_OP_ADD
extern VAL_VAR
extern VAL_CONST
extern putchar
extern putnumber
extern putendl
extern get_vars
extern insert_var
extern insert_mov
extern load_var_rax
extern load_rax_var
extern add_const_rax
extern add_var_rax
extern sub_const_rax
extern sub_var_rax
extern xor_reg
extern lex_load
extern lex_eundefined
lex_eexpect: ; (rdi: tok_type)
push rdi
mov rdi, EEXPECT
call putstr
pop rdi
call putstr
mov rdi, 1
call exit
count_vars: ; rdi: lex*
push rbp
mov rbp, rsp
sub rsp, 16
push rbx
push r12
xor r12, r12
mov rbx, [rdi + LEX_EXPR]
xor rcx, rcx
push rcx
.loop_expr:
pop rcx
cmp ecx, dword [rdi + LEX_EXPR_CNT]
je .done
mov rax, EXPR_SIZE
mul rcx
lea rax, [rbx + rax]
mov rdx, [rax + EXPR_TOK_CNT]
inc rcx
push rcx
xor rcx, rcx
mov rax, [rax + EXPR_TOK]
.loop_toks:
cmp rcx, rdx
je .loop_expr
cmp qword [rax + TOK_TYPE], TOK_VAR
jne .no_var
inc r12
.no_var:
inc rcx
add rax, SIZE_TOK
jmp .loop_toks
.done:
mov dword [rdi + LEX_VAR_CNT], r12d
pop r12
pop rbx
mov rsp, rbp
pop rbp
ret
get_vars: ; (rdi: lex*)
push rbp
mov rbp, rsp
sub rsp, 32
push rbx
push r12
xor r12, r12
xor r9, r9
call count_vars
mov [rbp - 24], rdi ; store lex
mov eax, dword [rdi + LEX_VAR_CNT]
mov [rbp - 32], rax
mov rdi, VAR_SIZE
mul rdi
mov rdi, rax
call malloc
cmp rax, 0
je err_malloc
mov rdi, [rbp - 24]
mov [rdi + LEX_VAR], rax
mov eax, dword [rdi + LEX_EXPR_CNT]
mov [rbp - 8], eax
mov rax, [rdi + LEX_EXPR]
mov [rbp - 16], rax
xor rcx, rcx
push rcx
.loop_expr:
pop rcx
cmp ecx, dword [rdi + LEX_EXPR_CNT]
je .done
mov rax, EXPR_SIZE
mul rcx
mov rbx, [rbp - 16]
lea rax, [rbx + rax]
mov rdx, [rax + EXPR_TOK_CNT]
inc rcx
push rcx
xor rcx, rcx
mov rax, [rax + EXPR_TOK]
.loop_toks:
cmp rcx, rdx
je .loop_expr
cmp qword [rax + TOK_TYPE], TOK_VAR
jne .skip_alloc
mov rbx, [rbp - 24]
mov rbx, [rbx + LEX_VAR]
lea rbx, [rbx + r12]
mov r8, [rax + TOK_VALUE]
mov [rbx + VAR_NAME], r8
inc r9
mov rax, r8
mov rax, 8
push rdx
mul r9
pop rdx
mov [rbx + VAR_OFFS], rax
mov rax, r8
.skip_alloc:
add rax, SIZE_TOK
inc rcx
jmp .loop_toks
.done:
pop r12
pop rbx
mov rsp, rbp
pop rbp
ret
global lex
lex: ; rax: lex* (rdi: char *file_content)
@ -169,6 +46,7 @@ lex: ; rax: lex* (rdi: char *file_content)
call malloc
cmp rax, 0
je err_malloc
mov [rbp - 24], rax ; store lex on stack
lea rsi, [rbp - 16] ; int* expr_cnt
@ -183,25 +61,22 @@ lex: ; rax: lex* (rdi: char *file_content)
call get_vars
xor rcx, rcx
mov rax, [rbp - 24]
lea rcx, [rax + LEX_EXPR_IDX]
.process_expressions:
mov rdi, [rbp - 24]
mov esi, [rdi + LEX_EXPR_CNT]
cmp ecx, esi
cmp dword [rcx], esi
je .done
mov rbx, [rdi + LEX_EXPR]
mov rax, EXPR_SIZE
mul rcx
push rcx
mov rdi, [rbx + rax + EXPR_TOK]
mov rdx, [rbp - 24]
call lex_assignment
call lex_load
pop rcx
inc rcx
inc dword [rcx]
jmp .process_expressions
.done:
@ -210,95 +85,35 @@ lex: ; rax: lex* (rdi: char *file_content)
pop rbp
ret
lex_assignment: ; (rdi: tok*, rsi: n, rdx: lex*)
push rbp
mov rbp, rsp
sub rsp, 32
mov [rbp - 16], rdi ; store tok array
mov rdi, [rdx + LEX_VAR_CNT]
mov [rbp - 8], edi ; var_cnt
mov rdi, [rdx + LEX_VAR]
mov [rbp - 24], rdi ; vars
; check first token: if not TOK_VAR, cant be assign
mov rdi, [rbp - 16]
mov rdx, [rdi + TOK_TYPE]
cmp rdx, TOK_VAR
jne .done_false
xor rcx, rcx
push rdi
mov rsi, [rdi + TOK_VALUE]
mov rdi, [rbp - 24]
mov rdx, [rbp - 8]
call look_up_var
push rax
mov rdi, MOV
call putstr
mov rdi, OPEN_STACK_VAR
call putstr
pop rdi
call putnumber
mov rdi, CLOSE_STACK_VAR
call putstr
pop rdi
add rdi, SIZE_TOK
mov rdx, [rdi + TOK_TYPE]
cmp rdx, TOK_LOAD
jne .err_found
add rdi, SIZE_TOK
mov rdx, [rdi + TOK_TYPE]
cmp rdx, TOK_CONST
je .print_const
cmp rdx, TOK_VAR
je .done_true
.done_false:
mov rax, 0
ret
.done_true:
mov rsp, rbp
pop rbp
cmp rcx, rsi
jne .done_false
mov rax, 1
ret
.err_found:
mov rdi, VAL_OP_LOAD
call lex_eexpect
.print_const:
mov rdi, [rdi + TOK_VALUE]
call putendl
jmp .done_true
look_up_var: ; rax: bool (rdi: vars*, rsi: name*, rdx: n)
global look_up_var
look_up_var: ; rax: bool (rdi: lex*, rsi: name*)
push rbp
mov rbp, rsp
xor rax, rax
xor rcx, rcx
mov edx, dword [rdi + LEX_VAR_CNT]
mov rdi, [rdi + LEX_VAR]
.loop_vars:
cmp rcx, rdx
je .done
cmp [rdi], rsi
je .not_found
push rdi
mov rdi, [rdi]
call strcmp
pop rdi
cmp rax, 0
je .found
inc rcx
add rdi, VAR_SIZE
jmp .loop_vars
.not_found:
mov rdi, rsi
call lex_eundefined
.found:
mov rax, [rdi + VAR_OFFS]
.done:

View File

@ -21,6 +21,7 @@ section .data
OP_ASSIGN: db "=", 0
OP_ADD: db "+", 0
OP_SUB: db "-", 0
OP_PRINT: db "print", 0
section .text
@ -71,6 +72,10 @@ parse: ; rax: tok* (rdi: char**)
call strcmp
cmp rax, 0
je .is_assign
mov rsi, OP_SUB
call strcmp
cmp rax, 0
je .is_sub
mov rsi, OP_ADD
call strcmp
cmp rax, 0
@ -92,6 +97,12 @@ parse: ; rax: tok* (rdi: char**)
mov rdi, TOK_LOAD
jmp .set_token
.is_sub:
pop rcx
push rdi
mov rdi, TOK_SUB
jmp .set_token
.is_add:
pop rcx
push rdi

185
src/parse/vars/get_vars.s Normal file
View File

@ -0,0 +1,185 @@
%include "./src/inc/token.s"
%include "./src/inc/lexer.s"
%include "./src/inc/expression.s"
section .text
extern malloc
extern err_malloc
extern strcmp
global count_vars
global get_vars
got_var: ; rax: bool (rdi: lex*, rsi: name*)
push r12
push r13
mov r12, [rdi + LEX_VAR]
lea r13, [rdi + LEX_VAR_CNT]
xor rcx, rcx
.loop_vars:
cmp ecx, [r13d]
je .doesnt_have
mov rdi, [r12 + VAR_NAME]
push rcx
call strcmp
pop rcx
cmp rax, 0
je .does_have
inc rcx
add r12, VAR_SIZE
jmp .loop_vars
.does_have:
mov rax, 1
jmp .done
.doesnt_have:
xor rax, rax
inc dword [r13d]
.done:
pop r13
pop r12
ret
count_vars: ; rdi: lex*
push rbp
mov rbp, rsp
sub rsp, 16
push rbx
push r12
xor r12, r12
mov rbx, [rdi + LEX_EXPR]
xor rcx, rcx
push rcx
.loop_expr:
pop rcx
cmp ecx, dword [rdi + LEX_EXPR_CNT]
je .done
mov rax, EXPR_SIZE
mul rcx
lea rax, [rbx + rax]
mov rdx, [rax + EXPR_TOK_CNT]
inc rcx
push rcx
xor rcx, rcx
mov rax, [rax + EXPR_TOK]
.loop_toks:
cmp rcx, rdx
je .loop_expr
cmp qword [rax + TOK_TYPE], TOK_VAR
jne .no_var
inc r12
.no_var:
inc rcx
add rax, SIZE_TOK
jmp .loop_toks
.done:
mov dword [rdi + LEX_VAR_CNT], r12d
pop r12
pop rbx
mov rsp, rbp
pop rbp
ret
get_vars: ; (rdi: lex*)
push rbp
mov rbp, rsp
sub rsp, 32
push rbx
push r12
xor r12, r12
xor r9, r9
call count_vars
mov [rbp - 24], rdi ; store lex
mov eax, dword [rdi + LEX_VAR_CNT]
mov [rbp - 32], rax
mov dword [rdi + LEX_VAR_CNT], 0
mov rdi, VAR_SIZE
mul rdi
mov rdi, rax
call malloc
cmp rax, 0
je err_malloc
mov rdi, [rbp - 24]
mov [rdi + LEX_VAR], rax
mov eax, dword [rdi + LEX_EXPR_CNT]
mov [rbp - 8], eax
mov rax, [rdi + LEX_EXPR]
mov [rbp - 16], rax
xor rcx, rcx
push rcx
.loop_expr:
pop rcx
cmp ecx, dword [rdi + LEX_EXPR_CNT]
je .done
mov rax, EXPR_SIZE
mul rcx
mov rbx, [rbp - 16]
lea rax, [rbx + rax]
mov rdx, [rax + EXPR_TOK_CNT]
inc rcx
push rcx
xor rcx, rcx
mov rax, [rax + EXPR_TOK]
.loop_toks:
cmp rcx, rdx
je .loop_expr
push rdx
cmp qword [rax + TOK_TYPE], TOK_VAR
jne .skip_alloc
mov rbx, [rbp - 24] ; load lex
mov rbx, [rbx + LEX_VAR]
mov r8, rax
push rax
push rdi
push rcx
mov rdi, [rbp - 24]
mov rsi, [rax + TOK_VALUE]
push r9
call got_var
pop r9
pop rcx
pop rdi
cmp rax, 1
je .skip_alloc
mov rax, VAR_SIZE
mul r9
lea rbx, [rbx + rax]
pop rax
mov r8, [rax + TOK_VALUE]
mov [rbx + VAR_NAME], r8
mov r8, rax
inc r9
mov rax, 8
mul r9
mov [rbx + VAR_OFFS], rax
.skip_alloc:
mov rax, r8
add rax, SIZE_TOK
inc rcx
pop rdx
jmp .loop_toks
.done:
pop r12
pop rbx
mov rsp, rbp
pop rbp
ret

230
src/parse/vars/insert_var.s Normal file
View File

@ -0,0 +1,230 @@
%include "./src/inc/token.s"
%include "./src/inc/regs.s"
section .data
INST_MOV: db "mov ", 0
INST_ADD: db "add ", 0
INST_SUB: db "sub ", 0
INST_XOR: db "xor ", 0
OPEN_STACK_VAR: db "[rbp-", 0
CLOSE_STACK_VAR: db "]", 0
SEP_INST: db ", ", 0
section .text
extern putstr
extern putnumber
extern putchar
extern putendl
extern VAL_CONST
extern VAL_VAR
extern VAL_OP_ADD
extern VAL_OP_SUB
extern VAL_OP_LOAD
extern VAL_FUNC
global insert_xor
insert_xor:
mov rdi, INST_XOR
call putstr
ret
global insert_mov
insert_mov:
mov rdi, INST_MOV
call putstr
ret
global insert_add
insert_add:
mov rdi, INST_ADD
call putstr
ret
global insert_sub
insert_sub:
mov rdi, INST_SUB
call putstr
ret
global xor_reg
xor_reg: ; rdi: char*
push rbx
mov rbx, rdi
call insert_xor
mov rdi, rbx
call putstr
mov rdi, SEP_INST
call putstr
mov rdi, rbx
call putendl
pop rbx
ret
global load_rax_var
load_rax_var: ; (rdi: OFF_S)
push rdi
call insert_mov
pop rdi
call insert_var
mov rdi, SEP_INST
call putstr
mov rdi, REG_RAX
call putendl
ret
global load_var_rax
load_var_rax: ; (rdi: OFF_S)
push rdi
call insert_mov
mov rdi, REG_RAX
call putstr
mov rdi , SEP_INST
call putstr
pop rdi
call insert_var_endl
mov rdi, '\n'
call putchar
ret
global op_const_rax
op_const_rax: ; (rdi: char *, rsi: op)
push rdi
cmp rsi, TOK_SUB
je .sub
jmp .add
.sub:
call insert_sub
jmp .done
.add:
call insert_add
.done:
mov rdi, REG_RAX
call putstr
mov rdi, SEP_INST
call putstr
pop rdi
call putendl
ret
global op_var_rax
op_var_rax: ; (rdi: OFF_S, rsi: op)
push rdi
cmp rsi, TOK_SUB
je .sub
jmp .add
.sub:
call insert_sub
jmp .done
.add:
call insert_add
.done:
mov rdi, REG_RAX
call putstr
mov rdi, SEP_INST
call putstr
pop rdi
call insert_var_endl
ret
global sub_var_rax
sub_var_rax: ; (rdi: OFF_S)
push rdi
call insert_sub
mov rdi, REG_RAX
call putstr
mov rdi , SEP_INST
call putstr
pop rdi
call insert_var_endl
ret
global add_rax_var
add_rax_var: ; (rdi: OFF_S)
push rdi
call insert_add
pop rdi
call insert_var
mov rdi , SEP_INST
call putstr
mov rdi, REG_RAX
call putendl
ret
global sub_rax_var
sub_rax_var: ; (rdi: OFF_S)
push rdi
call insert_sub
pop rdi
call insert_var
mov rdi , SEP_INST
call putstr
mov rdi, REG_RAX
call putendl
ret
global insert_var
insert_var_endl: ; (rdi: OFF_S)
push rdi
mov rdi, OPEN_STACK_VAR
call putstr
pop rdi
call putnumber
mov rdi, CLOSE_STACK_VAR
call putendl
ret
global insert_var
insert_var: ; (rdi: OFF_S)
push rdi
mov rdi, OPEN_STACK_VAR
call putstr
pop rdi
call putnumber
mov rdi, CLOSE_STACK_VAR
call putstr
ret

View File

@ -1 +1,2 @@
a = 5
a = 6
b = 5 - 2 + 6 + a