Support simple variable assignment
This commit is contained in:
		
							
								
								
									
										20
									
								
								Rakefile
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								Rakefile
									
									
									
									
									
								
							| @@ -44,13 +44,15 @@ task :convert do | |||||||
|   end |   end | ||||||
| end | end | ||||||
|  |  | ||||||
| STAGES.each do |stage| | rule /^build\/[[:alpha:]]+\/stage[[:digit:]]+$/ => ->(match) { | ||||||
|   previous = stage.delete_prefix('stage').to_i.pred |   "#{match}.s" | ||||||
|  | } do |t| | ||||||
|   file "build/valid/#{stage}" => "build/valid/#{stage}.s" do |t| |  | ||||||
|   sh CROSS_GCC, '-nostdlib', '-o', t.name, *t.prerequisites |   sh CROSS_GCC, '-nostdlib', '-o', t.name, *t.prerequisites | ||||||
| end | end | ||||||
|  |  | ||||||
|  | STAGES.each do |stage| | ||||||
|  |   previous = stage.delete_prefix('stage').to_i.pred | ||||||
|  |  | ||||||
|   file "build/valid/#{stage}.s" => ["build/boot/#{stage}", "boot/#{stage}.elna"] do |t| |   file "build/valid/#{stage}.s" => ["build/boot/#{stage}", "boot/#{stage}.elna"] do |t| | ||||||
|     exe, source = t.prerequisites |     exe, source = t.prerequisites | ||||||
|  |  | ||||||
| @@ -61,10 +63,6 @@ STAGES.each do |stage| | |||||||
|     IO.copy_stream last_stdout, t.name |     IO.copy_stream last_stdout, t.name | ||||||
|   end |   end | ||||||
|  |  | ||||||
|   file "build/boot/#{stage}" => "build/boot/#{stage}.s" do |t| |  | ||||||
|     sh CROSS_GCC, '-nostdlib', '-o', t.name, *t.prerequisites |  | ||||||
|   end |  | ||||||
|  |  | ||||||
|   file "build/boot/#{stage}.s" => ["build/valid/stage#{previous}", "boot/#{stage}.elna"] do |t| |   file "build/boot/#{stage}.s" => ["build/valid/stage#{previous}", "boot/#{stage}.elna"] do |t| | ||||||
|     exe, source = t.prerequisites |     exe, source = t.prerequisites | ||||||
|  |  | ||||||
| @@ -80,12 +78,6 @@ end | |||||||
| # Stage 1. | # Stage 1. | ||||||
| # | # | ||||||
|  |  | ||||||
| file 'build/valid/stage1' => ['build/valid', 'build/valid/stage1.s'] do |t| |  | ||||||
|   source = t.prerequisites.select { |prerequisite| prerequisite.end_with? '.s' } |  | ||||||
|  |  | ||||||
|   sh CROSS_GCC, '-nostdlib', '-o', t.name, *source |  | ||||||
| end |  | ||||||
|  |  | ||||||
| file 'build/valid/stage1.s' => ['build/boot/stage1', 'boot/stage1.s', 'build/valid'] do |t| | file 'build/valid/stage1.s' => ['build/boot/stage1', 'boot/stage1.s', 'build/valid'] do |t| | ||||||
|   source, exe, = t.prerequisites.partition { |prerequisite| prerequisite.end_with? '.s' } |   source, exe, = t.prerequisites.partition { |prerequisite| prerequisite.end_with? '.s' } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,6 +2,11 @@ | |||||||
| # v. 2.0. If a copy of the MPL was not distributed with this file, You can | # v. 2.0. If a copy of the MPL was not distributed with this file, You can | ||||||
| # obtain one at https://mozilla.org/MPL/2.0/. | # obtain one at https://mozilla.org/MPL/2.0/. | ||||||
|  |  | ||||||
|  | # Stage1 compiler. | ||||||
|  | # | ||||||
|  | # It supports declaring and calling procedures without arguments. | ||||||
|  | # A procedure name should start with an underscore. | ||||||
|  |  | ||||||
| .equ SOURCE_BUFFER_SIZE, 81920 | .equ SOURCE_BUFFER_SIZE, 81920 | ||||||
|  |  | ||||||
| .equ SYS_READ, 63 | .equ SYS_READ, 63 | ||||||
|   | |||||||
| @@ -4,8 +4,12 @@ | |||||||
|  |  | ||||||
| # Stage2 compiler. | # Stage2 compiler. | ||||||
| # | # | ||||||
| # It supports declaring and calling procedures without arguments. | # - Procedures without none or one argument. | ||||||
| # A procedure name should start with an underscore. | # - Goto statements. | ||||||
|  | # - Character and integer literals. | ||||||
|  | # - Passing local variables to procedures. | ||||||
|  | # - Local variables should have the format: v00, | ||||||
|  | #   where 00 is its offset from the sp register. | ||||||
|  |  | ||||||
| .section .rodata | .section .rodata | ||||||
|  |  | ||||||
|   | |||||||
| @@ -4,12 +4,8 @@ | |||||||
|  |  | ||||||
| # Stage3 compiler. | # Stage3 compiler. | ||||||
| # | # | ||||||
| # - Procedures without none or one argument. | # - Procedures with multiple arguments. | ||||||
| # - Goto statements. | # - Character literals with and without escaping. | ||||||
| # - Character and integer literals. |  | ||||||
| # - Passing local variables to procedures. |  | ||||||
| # - Local variables should have the format: v00, |  | ||||||
| #   where 00 is its offset from the sp register. |  | ||||||
|  |  | ||||||
| .section .rodata | .section .rodata | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										238
									
								
								boot/stage4.elna
									
									
									
									
									
								
							
							
						
						
									
										238
									
								
								boot/stage4.elna
									
									
									
									
									
								
							| @@ -2,14 +2,13 @@ | |||||||
| # v. 2.0. If a copy of the MPL was not distributed with this file, You can | # v. 2.0. If a copy of the MPL was not distributed with this file, You can | ||||||
| # obtain one at https://mozilla.org/MPL/2.0/. | # obtain one at https://mozilla.org/MPL/2.0/. | ||||||
|  |  | ||||||
| # Stage3 compiler. | # Stage4 compiler. | ||||||
| # | # | ||||||
| # - Procedures without none or one argument. | # - Taking value of local and global variables. Variables that doesn't begin | ||||||
| # - Goto statements. | #   with "v" are considered global. | ||||||
| # - Character and integer literals. | # - Simple variable assignment, e.g. v0 := 5 or v0 := global_variable; | ||||||
| # - Passing local variables to procedures. | #   7 words on the stack, 28 - 56, are reversed for procedure arguments (caller side). | ||||||
| # - Local variables should have the format: v00, | # - Take address unary operation "@". | ||||||
| #   where 00 is its offset from the sp register. |  | ||||||
|  |  | ||||||
| .section .rodata | .section .rodata | ||||||
|  |  | ||||||
| @@ -38,10 +37,10 @@ keyword_begin: .ascii "begin" | |||||||
| keyword_var: .ascii "var" | keyword_var: .ascii "var" | ||||||
|  |  | ||||||
| .type asm_prologue, @object | .type asm_prologue, @object | ||||||
| asm_prologue: .string "\taddi sp, sp, -32\n\tsw ra, 28(sp)\n\tsw s0, 24(sp)\n\taddi s0, sp, 32\n" | asm_prologue: .string "\taddi sp, sp, -64\n\tsw ra, 60(sp)\n\tsw s0, 56(sp)\n\taddi s0, sp, 64\n" | ||||||
|  |  | ||||||
| .type asm_epilogue, @object | .type asm_epilogue, @object | ||||||
| asm_epilogue: .string "\tlw ra, 28(sp)\n\tlw s0, 24(sp)\n\taddi sp, sp, 32\n\tret\n" | asm_epilogue: .string "\tlw ra, 60(sp)\n\tlw s0, 56(sp)\n\taddi sp, sp, 64\n\tret\n" | ||||||
|  |  | ||||||
| .type asm_type_directive, @object | .type asm_type_directive, @object | ||||||
| asm_type_directive: .string ".type " | asm_type_directive: .string ".type " | ||||||
| @@ -64,23 +63,26 @@ asm_li: .string "\tli " | |||||||
| .type asm_lw, @object | .type asm_lw, @object | ||||||
| asm_lw: .string "\tlw " | asm_lw: .string "\tlw " | ||||||
|  |  | ||||||
|  | .type asm_la, @object | ||||||
|  | asm_la: .string "\tla " | ||||||
|  |  | ||||||
| .type asm_sw, @object | .type asm_sw, @object | ||||||
| asm_sw: .string "\tsw " | asm_sw: .string "\tsw " | ||||||
|  |  | ||||||
| .type asm_mv, @object | .type asm_addi, @object | ||||||
| asm_mv: .string "mv " | asm_addi: .string "\taddi " | ||||||
|  |  | ||||||
| .type asm_t0, @object | .type asm_t0, @object | ||||||
| asm_t0: .string "t0" | asm_t0: .string "t0" | ||||||
|  |  | ||||||
| .type asm_a0, @object | .type asm_t1, @object | ||||||
| asm_a0: .string "a0" | asm_t1: .string "t1" | ||||||
|  |  | ||||||
| .type asm_comma, @object | .type asm_comma, @object | ||||||
| asm_comma: .string ", " | asm_comma: .string ", " | ||||||
|  |  | ||||||
| .type asm_sp, @object | .type asm_sp, @object | ||||||
| asm_sp: .string "(sp)" | asm_sp: .string "sp" | ||||||
|  |  | ||||||
| .section .bss | .section .bss | ||||||
|  |  | ||||||
| @@ -257,7 +259,7 @@ begin | |||||||
| 	_is_upper(); | 	_is_upper(); | ||||||
| 	sw a0, 4(sp) | 	sw a0, 4(sp) | ||||||
|  |  | ||||||
| 	_is_lower(v00); | 	_is_lower(v0); | ||||||
|  |  | ||||||
| 	lw t0, 0(sp) | 	lw t0, 0(sp) | ||||||
| 	xori t1, t0, '_' | 	xori t1, t0, '_' | ||||||
| @@ -292,7 +294,7 @@ begin | |||||||
| 	_is_alpha(); | 	_is_alpha(); | ||||||
| 	sw a0, 0(sp) | 	sw a0, 0(sp) | ||||||
|  |  | ||||||
| 	_is_digit(v04); | 	_is_digit(v4); | ||||||
|  |  | ||||||
| 	lw a1, 0(sp) | 	lw a1, 0(sp) | ||||||
| 	or a0, a0, a1 | 	or a0, a0, a1 | ||||||
| @@ -491,7 +493,7 @@ begin | |||||||
| 	la a0, asm_li | 	la a0, asm_li | ||||||
| 	_write_z(); | 	_write_z(); | ||||||
|  |  | ||||||
| 	la a0, asm_a0 | 	la a0, asm_t0 | ||||||
| 	_write_z(); | 	_write_z(); | ||||||
|  |  | ||||||
| 	la a0, asm_comma | 	la a0, asm_comma | ||||||
| @@ -509,7 +511,7 @@ begin | |||||||
| 	la a0, asm_li | 	la a0, asm_li | ||||||
| 	_write_z(); | 	_write_z(); | ||||||
|  |  | ||||||
| 	la a0, asm_a0 | 	la a0, asm_t0 | ||||||
| 	_write_z(); | 	_write_z(); | ||||||
|  |  | ||||||
| 	la a0, asm_comma | 	la a0, asm_comma | ||||||
| @@ -542,43 +544,51 @@ end; | |||||||
|  |  | ||||||
| proc _compile_variable_expression(); | proc _compile_variable_expression(); | ||||||
| begin | begin | ||||||
|  | 	_compile_designator(); | ||||||
|  |  | ||||||
| 	la a0, asm_lw | 	la a0, asm_lw | ||||||
| 	_write_z(); | 	_write_z(); | ||||||
|  |  | ||||||
| 	la a0, asm_a0 | 	la a0, asm_t0 | ||||||
| 	_write_z(); | 	_write_z(); | ||||||
|  |  | ||||||
| 	la a0, asm_comma | 	la a0, asm_comma | ||||||
| 	_write_z(); | 	_write_z(); | ||||||
|  |  | ||||||
| 	_advance_token(1); | 	_write_c('('); | ||||||
| 	_read_token(); | 	la a0, asm_t0 | ||||||
| 	_write_token(); |  | ||||||
| 	_advance_token(); |  | ||||||
|  |  | ||||||
| 	la a0, asm_sp |  | ||||||
| 	_write_z(); | 	_write_z(); | ||||||
|  |  | ||||||
|  | 	_write_c(')'); | ||||||
| 	_write_c('\n'); | 	_write_c('\n'); | ||||||
|  |  | ||||||
| end; | end; | ||||||
|  |  | ||||||
|  | proc _compile_address_expression(); | ||||||
|  | begin | ||||||
|  | 	# Skip the "@" sign. | ||||||
|  | 	_advance_token(1); | ||||||
|  | 	_compile_designator(); | ||||||
|  |  | ||||||
|  | end; | ||||||
|  |  | ||||||
| proc _compile_expression(); | proc _compile_expression(); | ||||||
| begin | begin | ||||||
| 	la t0, source_code_position | 	la t0, source_code_position | ||||||
| 	lw t0, (t0) | 	lw t0, (t0) | ||||||
| 	lb a0, (t0) | 	lb a0, (t0) | ||||||
|  | 	sw a0, 0(sp) | ||||||
|  |  | ||||||
| 	li t1, '\'' | 	li t1, '\'' | ||||||
| 	beq a0, t1, .compile_expression_character_literal | 	beq a0, t1, .compile_expression_character_literal | ||||||
|  |  | ||||||
| 	li t1, 'v' | 	li t1, '@' | ||||||
| 	beq a0, t1, .compile_expression_variable | 	beq a0, t1, .compile_expression_address | ||||||
|  |  | ||||||
| 	_is_digit(); | 	_is_digit(v0); | ||||||
| 	bnez a0, .compile_expression_integer_literal | 	bnez a0, .compile_expression_integer_literal | ||||||
|  |  | ||||||
| 	goto .compile_expression_end; | 	goto .compile_expression_variable; | ||||||
|  |  | ||||||
| .compile_expression_character_literal: | .compile_expression_character_literal: | ||||||
| 	_compile_character_literal(); | 	_compile_character_literal(); | ||||||
| @@ -588,9 +598,13 @@ begin | |||||||
| 	_compile_integer_literal(); | 	_compile_integer_literal(); | ||||||
| 	goto .compile_expression_end; | 	goto .compile_expression_end; | ||||||
|  |  | ||||||
|  | .compile_expression_address: | ||||||
|  | 	_compile_address_expression(); | ||||||
|  | 	goto .compile_expression_end; | ||||||
|  |  | ||||||
| .compile_expression_variable: | .compile_expression_variable: | ||||||
| 	_compile_variable_expression(); | 	_compile_variable_expression(); | ||||||
| 	goto .compile_expression_end;; | 	goto .compile_expression_end; | ||||||
|  |  | ||||||
| .compile_expression_end: | .compile_expression_end: | ||||||
| end; | end; | ||||||
| @@ -628,22 +642,24 @@ begin | |||||||
| 	la a0, asm_sw | 	la a0, asm_sw | ||||||
| 	_write_z(); | 	_write_z(); | ||||||
|  |  | ||||||
| 	la a0, asm_a0 | 	la a0, asm_t0 | ||||||
| 	_write_z(); | 	_write_z(); | ||||||
|  |  | ||||||
| 	la a0, asm_comma | 	la a0, asm_comma | ||||||
| 	_write_z(); | 	_write_z(); | ||||||
|  |  | ||||||
| 	# Calculate the stack offset: 20 - (4 * argument_counter) | 	# Calculate the stack offset: 52 - (4 * argument_counter) | ||||||
| 	lw t0, 8(sp) | 	lw t0, 8(sp) | ||||||
| 	li t1, 4 | 	li t1, 4 | ||||||
| 	mul t0, t0, t1 | 	mul t0, t0, t1 | ||||||
| 	li t1, 20 | 	li t1, 52 | ||||||
| 	sub a0, t1, t0 | 	sub a0, t1, t0 | ||||||
| 	_write_i(); | 	_write_i(); | ||||||
|  |  | ||||||
|  | 	_write_c('(') | ||||||
| 	la a0, asm_sp | 	la a0, asm_sp | ||||||
| 	_write_z(); | 	_write_z(); | ||||||
|  | 	_write_c(')') | ||||||
|  |  | ||||||
| 	_write_c('\n'); | 	_write_c('\n'); | ||||||
|  |  | ||||||
| @@ -683,17 +699,19 @@ begin | |||||||
| 	la a0, asm_comma | 	la a0, asm_comma | ||||||
| 	_write_z(); | 	_write_z(); | ||||||
|  |  | ||||||
| 	# Calculate the stack offset: 20 - (4 * argument_counter) | 	# Calculate the stack offset: 52 - (4 * argument_counter) | ||||||
| 	lw t0, 8(sp) | 	lw t0, 8(sp) | ||||||
| 	li t1, 4 | 	li t1, 4 | ||||||
| 	mul t0, t0, t1 | 	mul t0, t0, t1 | ||||||
| 	li t1, 20 | 	li t1, 52 | ||||||
| 	sub a0, t1, t0 | 	sub a0, t1, t0 | ||||||
| 	_write_i(); | 	_write_i(); | ||||||
|  |  | ||||||
|  | 	_write_c('('); | ||||||
| 	la a0, asm_sp | 	la a0, asm_sp | ||||||
| 	_write_z(); | 	_write_z(); | ||||||
|  |  | ||||||
|  | 	_write_c(')'); | ||||||
| 	_write_c('\n'); | 	_write_c('\n'); | ||||||
|  |  | ||||||
| 	goto .compile_call_finalize; | 	goto .compile_call_finalize; | ||||||
| @@ -702,7 +720,7 @@ begin | |||||||
| 	la a0, asm_call | 	la a0, asm_call | ||||||
| 	_write_z(); | 	_write_z(); | ||||||
|  |  | ||||||
| 	_write_s(v04, v00); | 	_write_s(v4, v0); | ||||||
|  |  | ||||||
| 	# Skip the right paren. | 	# Skip the right paren. | ||||||
| 	_advance_token(1); | 	_advance_token(1); | ||||||
| @@ -718,10 +736,143 @@ begin | |||||||
| 	la a0, asm_j | 	la a0, asm_j | ||||||
| 	_write_z(); | 	_write_z(); | ||||||
|  |  | ||||||
| 	_write_token(v00); | 	_write_token(v0); | ||||||
| 	_advance_token(); | 	_advance_token(); | ||||||
| end; | end; | ||||||
|  |  | ||||||
|  | proc _compile_local_designator(); | ||||||
|  | begin | ||||||
|  | 	# Skip "v" in the local variable name. | ||||||
|  | 	_advance_token(1); | ||||||
|  |  | ||||||
|  | 	la a0, asm_addi | ||||||
|  | 	_write_z(); | ||||||
|  |  | ||||||
|  | 	la a0, asm_t0 | ||||||
|  | 	_write_z(); | ||||||
|  |  | ||||||
|  | 	la a0, asm_comma | ||||||
|  | 	_write_z(); | ||||||
|  |  | ||||||
|  | 	la a0, asm_sp | ||||||
|  | 	_write_z(); | ||||||
|  |  | ||||||
|  | 	la a0, asm_comma | ||||||
|  | 	_write_z(); | ||||||
|  |  | ||||||
|  | 	# Read local variable stack offset and save it. | ||||||
|  | 	la t0, source_code_position | ||||||
|  | 	lw t0, (t0) | ||||||
|  | 	sw t0, 0(sp) | ||||||
|  |  | ||||||
|  | 	_read_token(); | ||||||
|  | 	sw a0, 4(sp) | ||||||
|  |  | ||||||
|  | 	_write_token(); | ||||||
|  | 	_advance_token(); | ||||||
|  |  | ||||||
|  | 	_write_c('\n'); | ||||||
|  |  | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | proc _compile_global_designator(); | ||||||
|  | begin | ||||||
|  | 	la a0, asm_la | ||||||
|  | 	_write_z(); | ||||||
|  |  | ||||||
|  | 	la a0, asm_t0 | ||||||
|  | 	_write_z(); | ||||||
|  |  | ||||||
|  | 	la a0, asm_comma | ||||||
|  | 	_write_z(); | ||||||
|  |  | ||||||
|  | 	_read_token(); | ||||||
|  | 	_write_token(); | ||||||
|  | 	_advance_token(); | ||||||
|  |  | ||||||
|  | 	_write_c('\n'); | ||||||
|  |  | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | proc _compile_designator(); | ||||||
|  | begin | ||||||
|  | 	la t0, source_code_position | ||||||
|  | 	lw t0, (t0) | ||||||
|  | 	lb a0, (t0) | ||||||
|  |  | ||||||
|  | 	li t1, 'v' | ||||||
|  | 	beq a0, t1, .compile_designator_local | ||||||
|  |  | ||||||
|  | 	goto .compile_designator_global; | ||||||
|  |  | ||||||
|  | .compile_designator_local: | ||||||
|  | 	_compile_local_designator(); | ||||||
|  | 	goto .compile_designator_end; | ||||||
|  |  | ||||||
|  | .compile_designator_global: | ||||||
|  | 	_compile_global_designator(); | ||||||
|  | 	goto .compile_designator_end; | ||||||
|  |  | ||||||
|  | .compile_designator_end: | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | proc _compile_assignment(); | ||||||
|  | begin | ||||||
|  | 	_compile_designator(); | ||||||
|  |  | ||||||
|  | 	# Save the assignee address on the stack. | ||||||
|  | 	la a0, asm_sw | ||||||
|  | 	_write_z(); | ||||||
|  |  | ||||||
|  | 	la a0, asm_t0 | ||||||
|  | 	_write_z(); | ||||||
|  |  | ||||||
|  | 	la a0, asm_comma | ||||||
|  | 	_write_z(); | ||||||
|  |  | ||||||
|  | 	_write_i(20); | ||||||
|  | 	_write_c('('); | ||||||
|  | 	la a0, asm_sp | ||||||
|  | 	_write_z(); | ||||||
|  | 	_write_c(')'); | ||||||
|  | 	_write_c('\n'); | ||||||
|  | 	# Skip the assignment sign (:=) with surrounding whitespaces. | ||||||
|  | 	_advance_token(4); | ||||||
|  |  | ||||||
|  | 	# Compile the assignment. | ||||||
|  | 	_compile_expression(); | ||||||
|  |  | ||||||
|  | 	la a0, asm_lw | ||||||
|  | 	_write_z(); | ||||||
|  |  | ||||||
|  | 	la a0, asm_t1 | ||||||
|  | 	_write_z(); | ||||||
|  |  | ||||||
|  | 	la a0, asm_comma | ||||||
|  | 	_write_z(); | ||||||
|  |  | ||||||
|  | 	_write_i(20); | ||||||
|  | 	_write_c('('); | ||||||
|  | 	la a0, asm_sp | ||||||
|  | 	_write_z(); | ||||||
|  | 	_write_c(')'); | ||||||
|  | 	_write_c('\n'); | ||||||
|  |  | ||||||
|  | 	la a0, asm_sw | ||||||
|  | 	_write_z(); | ||||||
|  |  | ||||||
|  | 	la a0, asm_t0 | ||||||
|  | 	_write_z(); | ||||||
|  |  | ||||||
|  | 	la a0, asm_comma | ||||||
|  | 	_write_z(); | ||||||
|  |  | ||||||
|  | 	_write_c('('); | ||||||
|  | 	la a0, asm_t1 | ||||||
|  | 	_write_z(); | ||||||
|  | 	_write_c(')'); | ||||||
|  | end; | ||||||
|  |  | ||||||
| proc _compile_statement(); | proc _compile_statement(); | ||||||
| begin | begin | ||||||
| 	# This is a call if the statement starts with an underscore. | 	# This is a call if the statement starts with an underscore. | ||||||
| @@ -737,6 +888,9 @@ begin | |||||||
| 	li t1, 'g' | 	li t1, 'g' | ||||||
| 	beq t0, t1, .compile_statement_goto | 	beq t0, t1, .compile_statement_goto | ||||||
|  |  | ||||||
|  | 	li t1, 'v' | ||||||
|  | 	beq t0, t1, .compile_statement_assignment | ||||||
|  |  | ||||||
| 	_compile_line(); | 	_compile_line(); | ||||||
| 	goto .compile_statement_end; | 	goto .compile_statement_end; | ||||||
|  |  | ||||||
| @@ -752,6 +906,12 @@ begin | |||||||
|  |  | ||||||
| 	goto .compile_statement_semicolon; | 	goto .compile_statement_semicolon; | ||||||
|  |  | ||||||
|  | .compile_statement_assignment: | ||||||
|  | 	_advance_token(1); | ||||||
|  | 	_compile_assignment(); | ||||||
|  |  | ||||||
|  | 	goto .compile_statement_semicolon; | ||||||
|  |  | ||||||
| .compile_statement_semicolon: | .compile_statement_semicolon: | ||||||
| 	_advance_token(2); | 	_advance_token(2); | ||||||
|  |  | ||||||
| @@ -789,13 +949,13 @@ begin | |||||||
| 	la a0, asm_type_directive | 	la a0, asm_type_directive | ||||||
| 	_write_z(); | 	_write_z(); | ||||||
|  |  | ||||||
| 	_write_token(v00); | 	_write_token(v0); | ||||||
|  |  | ||||||
| 	la a0, asm_type_function | 	la a0, asm_type_function | ||||||
| 	_write_z(); | 	_write_z(); | ||||||
|  |  | ||||||
| 	# Write procedure label, _procedure_name: | 	# Write procedure label, _procedure_name: | ||||||
| 	_write_token(v00); | 	_write_token(v0); | ||||||
|  |  | ||||||
| 	la a0, asm_colon | 	la a0, asm_colon | ||||||
| 	_write_z(); | 	_write_z(); | ||||||
|   | |||||||
							
								
								
									
										315
									
								
								boot/stage5.elna
									
									
									
									
									
								
							
							
						
						
									
										315
									
								
								boot/stage5.elna
									
									
									
									
									
								
							| @@ -2,14 +2,13 @@ | |||||||
| # v. 2.0. If a copy of the MPL was not distributed with this file, You can | # v. 2.0. If a copy of the MPL was not distributed with this file, You can | ||||||
| # obtain one at https://mozilla.org/MPL/2.0/. | # obtain one at https://mozilla.org/MPL/2.0/. | ||||||
|  |  | ||||||
| # Stage3 compiler. | # Stage4 compiler. | ||||||
| # | # | ||||||
| # - Procedures without none or one argument. | # - Taking value of local and global variables. Variables that doesn't begin | ||||||
| # - Goto statements. | #   with "v" are considered global. | ||||||
| # - Character and integer literals. | # - Simple variable assignment, e.g. v0 := 5 or v0 := global_variable; | ||||||
| # - Passing local variables to procedures. | #   7 words on the stack, 28 - 56, are reversed for procedure arguments (caller side). | ||||||
| # - Local variables should have the format: v00, | # - Take address unary operation "@". | ||||||
| #   where 00 is its offset from the sp register. |  | ||||||
|  |  | ||||||
| .section .rodata | .section .rodata | ||||||
|  |  | ||||||
| @@ -38,10 +37,10 @@ keyword_begin: .ascii "begin" | |||||||
| keyword_var: .ascii "var" | keyword_var: .ascii "var" | ||||||
|  |  | ||||||
| .type asm_prologue, @object | .type asm_prologue, @object | ||||||
| asm_prologue: .string "\taddi sp, sp, -32\n\tsw ra, 28(sp)\n\tsw s0, 24(sp)\n\taddi s0, sp, 32\n" | asm_prologue: .string "\taddi sp, sp, -64\n\tsw ra, 60(sp)\n\tsw s0, 56(sp)\n\taddi s0, sp, 64\n" | ||||||
|  |  | ||||||
| .type asm_epilogue, @object | .type asm_epilogue, @object | ||||||
| asm_epilogue: .string "\tlw ra, 28(sp)\n\tlw s0, 24(sp)\n\taddi sp, sp, 32\n\tret\n" | asm_epilogue: .string "\tlw ra, 60(sp)\n\tlw s0, 56(sp)\n\taddi sp, sp, 64\n\tret\n" | ||||||
|  |  | ||||||
| .type asm_type_directive, @object | .type asm_type_directive, @object | ||||||
| asm_type_directive: .string ".type " | asm_type_directive: .string ".type " | ||||||
| @@ -64,23 +63,26 @@ asm_li: .string "\tli " | |||||||
| .type asm_lw, @object | .type asm_lw, @object | ||||||
| asm_lw: .string "\tlw " | asm_lw: .string "\tlw " | ||||||
|  |  | ||||||
|  | .type asm_la, @object | ||||||
|  | asm_la: .string "\tla " | ||||||
|  |  | ||||||
| .type asm_sw, @object | .type asm_sw, @object | ||||||
| asm_sw: .string "\tsw " | asm_sw: .string "\tsw " | ||||||
|  |  | ||||||
| .type asm_mv, @object | .type asm_addi, @object | ||||||
| asm_mv: .string "mv " | asm_addi: .string "\taddi " | ||||||
|  |  | ||||||
| .type asm_t0, @object | .type asm_t0, @object | ||||||
| asm_t0: .string "t0" | asm_t0: .string "t0" | ||||||
|  |  | ||||||
| .type asm_a0, @object | .type asm_t1, @object | ||||||
| asm_a0: .string "a0" | asm_t1: .string "t1" | ||||||
|  |  | ||||||
| .type asm_comma, @object | .type asm_comma, @object | ||||||
| asm_comma: .string ", " | asm_comma: .string ", " | ||||||
|  |  | ||||||
| .type asm_sp, @object | .type asm_sp, @object | ||||||
| asm_sp: .string "(sp)" | asm_sp: .string "sp" | ||||||
|  |  | ||||||
| .section .bss | .section .bss | ||||||
|  |  | ||||||
| @@ -257,7 +259,7 @@ begin | |||||||
| 	_is_upper(); | 	_is_upper(); | ||||||
| 	sw a0, 4(sp) | 	sw a0, 4(sp) | ||||||
|  |  | ||||||
| 	_is_lower(v00); | 	_is_lower(v0); | ||||||
|  |  | ||||||
| 	lw t0, 0(sp) | 	lw t0, 0(sp) | ||||||
| 	xori t1, t0, '_' | 	xori t1, t0, '_' | ||||||
| @@ -292,7 +294,7 @@ begin | |||||||
| 	_is_alpha(); | 	_is_alpha(); | ||||||
| 	sw a0, 0(sp) | 	sw a0, 0(sp) | ||||||
|  |  | ||||||
| 	_is_digit(v04); | 	_is_digit(v4); | ||||||
|  |  | ||||||
| 	lw a1, 0(sp) | 	lw a1, 0(sp) | ||||||
| 	or a0, a0, a1 | 	or a0, a0, a1 | ||||||
| @@ -413,12 +415,7 @@ end; | |||||||
| proc _write_token(); | proc _write_token(); | ||||||
| begin | begin | ||||||
| 	sw a0, 0(sp) | 	sw a0, 0(sp) | ||||||
|  | 	_write_s(source_code_position, v0); | ||||||
| 	la a0, source_code_position |  | ||||||
| 	lw a0, (a0) |  | ||||||
| 	lw a1, 0(sp) |  | ||||||
| 	_write_s(); |  | ||||||
|  |  | ||||||
| 	lw a0, 0(sp) | 	lw a0, 0(sp) | ||||||
| end; | end; | ||||||
|  |  | ||||||
| @@ -488,14 +485,9 @@ end; | |||||||
|  |  | ||||||
| proc _compile_integer_literal(); | proc _compile_integer_literal(); | ||||||
| begin | begin | ||||||
| 	la a0, asm_li | 	_write_z(@asm_li); | ||||||
| 	_write_z(); | 	_write_z(@asm_t0); | ||||||
|  | 	_write_z(@asm_comma); | ||||||
| 	la a0, asm_a0 |  | ||||||
| 	_write_z(); |  | ||||||
|  |  | ||||||
| 	la a0, asm_comma |  | ||||||
| 	_write_z(); |  | ||||||
|  |  | ||||||
| 	_read_token(); | 	_read_token(); | ||||||
| 	_write_token(); | 	_write_token(); | ||||||
| @@ -506,14 +498,9 @@ end; | |||||||
|  |  | ||||||
| proc _compile_character_literal(); | proc _compile_character_literal(); | ||||||
| begin | begin | ||||||
| 	la a0, asm_li | 	_write_z(@asm_li); | ||||||
| 	_write_z(); | 	_write_z(@asm_t0); | ||||||
|  | 	_write_z(@asm_comma); | ||||||
| 	la a0, asm_a0 |  | ||||||
| 	_write_z(); |  | ||||||
|  |  | ||||||
| 	la a0, asm_comma |  | ||||||
| 	_write_z(); |  | ||||||
|  |  | ||||||
| 	_write_c('\''); | 	_write_c('\''); | ||||||
| 	_advance_token(1); | 	_advance_token(1); | ||||||
| @@ -542,43 +529,45 @@ end; | |||||||
|  |  | ||||||
| proc _compile_variable_expression(); | proc _compile_variable_expression(); | ||||||
| begin | begin | ||||||
| 	la a0, asm_lw | 	_compile_designator(); | ||||||
| 	_write_z(); |  | ||||||
|  |  | ||||||
| 	la a0, asm_a0 | 	_write_z(@asm_lw); | ||||||
| 	_write_z(); | 	_write_z(@asm_t0); | ||||||
|  | 	_write_z(@asm_comma); | ||||||
|  |  | ||||||
| 	la a0, asm_comma | 	_write_c('('); | ||||||
| 	_write_z(); | 	_write_z(@asm_t0); | ||||||
|  |  | ||||||
| 	_advance_token(1); |  | ||||||
| 	_read_token(); |  | ||||||
| 	_write_token(); |  | ||||||
| 	_advance_token(); |  | ||||||
|  |  | ||||||
| 	la a0, asm_sp |  | ||||||
| 	_write_z(); |  | ||||||
|  |  | ||||||
|  | 	_write_c(')'); | ||||||
| 	_write_c('\n'); | 	_write_c('\n'); | ||||||
|  |  | ||||||
| end; | end; | ||||||
|  |  | ||||||
|  | proc _compile_address_expression(); | ||||||
|  | begin | ||||||
|  | 	# Skip the "@" sign. | ||||||
|  | 	_advance_token(1); | ||||||
|  | 	_compile_designator(); | ||||||
|  |  | ||||||
|  | end; | ||||||
|  |  | ||||||
| proc _compile_expression(); | proc _compile_expression(); | ||||||
| begin | begin | ||||||
| 	la t0, source_code_position | 	la t0, source_code_position | ||||||
| 	lw t0, (t0) | 	lw t0, (t0) | ||||||
| 	lb a0, (t0) | 	lb a0, (t0) | ||||||
|  | 	sw a0, 0(sp) | ||||||
|  |  | ||||||
| 	li t1, '\'' | 	li t1, '\'' | ||||||
| 	beq a0, t1, .compile_expression_character_literal | 	beq a0, t1, .compile_expression_character_literal | ||||||
|  |  | ||||||
| 	li t1, 'v' | 	li t1, '@' | ||||||
| 	beq a0, t1, .compile_expression_variable | 	beq a0, t1, .compile_expression_address | ||||||
|  |  | ||||||
| 	_is_digit(); | 	_is_digit(v0); | ||||||
| 	bnez a0, .compile_expression_integer_literal | 	bnez a0, .compile_expression_integer_literal | ||||||
|  |  | ||||||
| 	goto .compile_expression_end; | 	goto .compile_expression_variable; | ||||||
|  |  | ||||||
| .compile_expression_character_literal: | .compile_expression_character_literal: | ||||||
| 	_compile_character_literal(); | 	_compile_character_literal(); | ||||||
| @@ -588,9 +577,13 @@ begin | |||||||
| 	_compile_integer_literal(); | 	_compile_integer_literal(); | ||||||
| 	goto .compile_expression_end; | 	goto .compile_expression_end; | ||||||
|  |  | ||||||
|  | .compile_expression_address: | ||||||
|  | 	_compile_address_expression(); | ||||||
|  | 	goto .compile_expression_end; | ||||||
|  |  | ||||||
| .compile_expression_variable: | .compile_expression_variable: | ||||||
| 	_compile_variable_expression(); | 	_compile_variable_expression(); | ||||||
| 	goto .compile_expression_end;; | 	goto .compile_expression_end; | ||||||
|  |  | ||||||
| .compile_expression_end: | .compile_expression_end: | ||||||
| end; | end; | ||||||
| @@ -604,9 +597,7 @@ begin | |||||||
|  |  | ||||||
| 	_read_token(); | 	_read_token(); | ||||||
| 	sw a0, 0(sp) | 	sw a0, 0(sp) | ||||||
| 	la t0, source_code_position | 	v4 := source_code_position | ||||||
| 	lw t0, (t0) |  | ||||||
| 	sw t0, 4(sp) |  | ||||||
|  |  | ||||||
| 	sw zero, 8(sp) | 	sw zero, 8(sp) | ||||||
|  |  | ||||||
| @@ -625,25 +616,21 @@ begin | |||||||
| 	_compile_expression(); | 	_compile_expression(); | ||||||
|  |  | ||||||
| 	# Save the argument on the stack. | 	# Save the argument on the stack. | ||||||
| 	la a0, asm_sw | 	_write_z(@asm_sw); | ||||||
| 	_write_z(); | 	_write_z(@asm_t0); | ||||||
|  | 	_write_z(@asm_comma); | ||||||
|  |  | ||||||
| 	la a0, asm_a0 | 	# Calculate the stack offset: 52 - (4 * argument_counter) | ||||||
| 	_write_z(); |  | ||||||
|  |  | ||||||
| 	la a0, asm_comma |  | ||||||
| 	_write_z(); |  | ||||||
|  |  | ||||||
| 	# Calculate the stack offset: 20 - (4 * argument_counter) |  | ||||||
| 	lw t0, 8(sp) | 	lw t0, 8(sp) | ||||||
| 	li t1, 4 | 	li t1, 4 | ||||||
| 	mul t0, t0, t1 | 	mul t0, t0, t1 | ||||||
| 	li t1, 20 | 	li t1, 52 | ||||||
| 	sub a0, t1, t0 | 	sub a0, t1, t0 | ||||||
| 	_write_i(); | 	_write_i(); | ||||||
|  |  | ||||||
| 	la a0, asm_sp | 	_write_c('('); | ||||||
| 	_write_z(); | 	_write_z(@asm_sp); | ||||||
|  | 	_write_c(')') | ||||||
|  |  | ||||||
| 	_write_c('\n'); | 	_write_c('\n'); | ||||||
|  |  | ||||||
| @@ -673,36 +660,34 @@ begin | |||||||
| 	addi t0, t0, -1 | 	addi t0, t0, -1 | ||||||
| 	sw t0, 8(sp) | 	sw t0, 8(sp) | ||||||
|  |  | ||||||
| 	la a0, asm_lw | 	_write_z(@asm_lw); | ||||||
| 	_write_z(); |  | ||||||
|  |  | ||||||
| 	_write_c('a'); | 	_write_c('a'); | ||||||
| 	lw a0, 8(sp) | 	lw a0, 8(sp) | ||||||
| 	_write_i(); | 	_write_i(); | ||||||
|  |  | ||||||
| 	la a0, asm_comma | 	_write_z(@asm_comma); | ||||||
| 	_write_z(); |  | ||||||
|  |  | ||||||
| 	# Calculate the stack offset: 20 - (4 * argument_counter) | 	# Calculate the stack offset: 52 - (4 * argument_counter) | ||||||
| 	lw t0, 8(sp) | 	lw t0, 8(sp) | ||||||
| 	li t1, 4 | 	li t1, 4 | ||||||
| 	mul t0, t0, t1 | 	mul t0, t0, t1 | ||||||
| 	li t1, 20 | 	li t1, 52 | ||||||
| 	sub a0, t1, t0 | 	sub a0, t1, t0 | ||||||
| 	_write_i(); | 	_write_i(); | ||||||
|  |  | ||||||
| 	la a0, asm_sp | 	_write_c('('); | ||||||
| 	_write_z(); | 	_write_z(@asm_sp); | ||||||
|  |  | ||||||
|  | 	_write_c(')'); | ||||||
| 	_write_c('\n'); | 	_write_c('\n'); | ||||||
|  |  | ||||||
| 	goto .compile_call_finalize; | 	goto .compile_call_finalize; | ||||||
|  |  | ||||||
| .compile_call_end: | .compile_call_end: | ||||||
| 	la a0, asm_call | 	_write_z(@asm_call); | ||||||
| 	_write_z(); |  | ||||||
|  |  | ||||||
| 	_write_s(v04, v00); | 	_write_s(v4, v0); | ||||||
|  |  | ||||||
| 	# Skip the right paren. | 	# Skip the right paren. | ||||||
| 	_advance_token(1); | 	_advance_token(1); | ||||||
| @@ -715,13 +700,111 @@ begin | |||||||
| 	_read_token(); | 	_read_token(); | ||||||
| 	sw a0, 0(sp) | 	sw a0, 0(sp) | ||||||
|  |  | ||||||
| 	la a0, asm_j | 	_write_z(@asm_j); | ||||||
| 	_write_z(); |  | ||||||
|  |  | ||||||
| 	_write_token(v00); | 	_write_token(v0); | ||||||
| 	_advance_token(); | 	_advance_token(); | ||||||
| end; | end; | ||||||
|  |  | ||||||
|  | proc _compile_local_designator(); | ||||||
|  | begin | ||||||
|  | 	# Skip "v" in the local variable name. | ||||||
|  | 	_advance_token(1); | ||||||
|  |  | ||||||
|  | 	_write_z(@asm_addi); | ||||||
|  | 	_write_z(@asm_t0); | ||||||
|  | 	_write_z(@asm_comma); | ||||||
|  | 	_write_z(@asm_sp); | ||||||
|  | 	_write_z(@asm_comma); | ||||||
|  |  | ||||||
|  | 	# Read local variable stack offset and save it. | ||||||
|  | 	v0 := source_code_position; | ||||||
|  |  | ||||||
|  | 	_read_token(); | ||||||
|  | 	sw a0, 4(sp) | ||||||
|  |  | ||||||
|  | 	_write_token(); | ||||||
|  | 	_advance_token(); | ||||||
|  |  | ||||||
|  | 	_write_c('\n'); | ||||||
|  |  | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | proc _compile_global_designator(); | ||||||
|  | begin | ||||||
|  | 	_write_z(@asm_la); | ||||||
|  | 	_write_z(@asm_t0); | ||||||
|  | 	_write_z(@asm_comma); | ||||||
|  |  | ||||||
|  | 	_read_token(); | ||||||
|  | 	_write_token(); | ||||||
|  | 	_advance_token(); | ||||||
|  |  | ||||||
|  | 	_write_c('\n'); | ||||||
|  |  | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | proc _compile_designator(); | ||||||
|  | begin | ||||||
|  | 	la t0, source_code_position | ||||||
|  | 	lw t0, (t0) | ||||||
|  | 	lb a0, (t0) | ||||||
|  |  | ||||||
|  | 	li t1, 'v' | ||||||
|  | 	beq a0, t1, .compile_designator_local | ||||||
|  |  | ||||||
|  | 	goto .compile_designator_global; | ||||||
|  |  | ||||||
|  | .compile_designator_local: | ||||||
|  | 	_compile_local_designator(); | ||||||
|  | 	goto .compile_designator_end; | ||||||
|  |  | ||||||
|  | .compile_designator_global: | ||||||
|  | 	_compile_global_designator(); | ||||||
|  | 	goto .compile_designator_end; | ||||||
|  |  | ||||||
|  | .compile_designator_end: | ||||||
|  | end; | ||||||
|  |  | ||||||
|  | proc _compile_assignment(); | ||||||
|  | begin | ||||||
|  | 	_compile_designator(); | ||||||
|  |  | ||||||
|  | 	# Save the assignee address on the stack. | ||||||
|  | 	_write_z(@asm_sw); | ||||||
|  | 	_write_z(@asm_t0); | ||||||
|  | 	_write_z(@asm_comma); | ||||||
|  |  | ||||||
|  | 	_write_i(20); | ||||||
|  | 	_write_c('('); | ||||||
|  | 	_write_z(@asm_sp); | ||||||
|  | 	_write_c(')'); | ||||||
|  | 	_write_c('\n'); | ||||||
|  | 	# Skip the assignment sign (:=) with surrounding whitespaces. | ||||||
|  | 	_advance_token(4); | ||||||
|  |  | ||||||
|  | 	# Compile the assignment. | ||||||
|  | 	_compile_expression(); | ||||||
|  |  | ||||||
|  | 	_write_z(@asm_lw); | ||||||
|  | 	_write_z(@asm_t1); | ||||||
|  | 	_write_z(@asm_comma); | ||||||
|  |  | ||||||
|  | 	_write_i(20); | ||||||
|  | 	_write_c('('); | ||||||
|  | 	_write_z(@asm_sp); | ||||||
|  | 	_write_c(')'); | ||||||
|  | 	_write_c('\n'); | ||||||
|  |  | ||||||
|  | 	_write_z(@asm_sw); | ||||||
|  | 	_write_z(@asm_t0); | ||||||
|  | 	_write_z(@asm_comma); | ||||||
|  |  | ||||||
|  | 	_write_c('('); | ||||||
|  | 	_write_z(@asm_t1); | ||||||
|  | 	_write_c(')'); | ||||||
|  | end; | ||||||
|  |  | ||||||
| proc _compile_statement(); | proc _compile_statement(); | ||||||
| begin | begin | ||||||
| 	# This is a call if the statement starts with an underscore. | 	# This is a call if the statement starts with an underscore. | ||||||
| @@ -737,6 +820,9 @@ begin | |||||||
| 	li t1, 'g' | 	li t1, 'g' | ||||||
| 	beq t0, t1, .compile_statement_goto | 	beq t0, t1, .compile_statement_goto | ||||||
|  |  | ||||||
|  | 	li t1, 'v' | ||||||
|  | 	beq t0, t1, .compile_statement_assignment | ||||||
|  |  | ||||||
| 	_compile_line(); | 	_compile_line(); | ||||||
| 	goto .compile_statement_end; | 	goto .compile_statement_end; | ||||||
|  |  | ||||||
| @@ -752,6 +838,12 @@ begin | |||||||
|  |  | ||||||
| 	goto .compile_statement_semicolon; | 	goto .compile_statement_semicolon; | ||||||
|  |  | ||||||
|  | .compile_statement_assignment: | ||||||
|  | 	_advance_token(1); | ||||||
|  | 	_compile_assignment(); | ||||||
|  |  | ||||||
|  | 	goto .compile_statement_semicolon; | ||||||
|  |  | ||||||
| .compile_statement_semicolon: | .compile_statement_semicolon: | ||||||
| 	_advance_token(2); | 	_advance_token(2); | ||||||
|  |  | ||||||
| @@ -789,30 +881,27 @@ begin | |||||||
| 	la a0, asm_type_directive | 	la a0, asm_type_directive | ||||||
| 	_write_z(); | 	_write_z(); | ||||||
|  |  | ||||||
| 	_write_token(v00); | 	_write_token(v0); | ||||||
|  |  | ||||||
| 	la a0, asm_type_function | 	la a0, asm_type_function | ||||||
| 	_write_z(); | 	_write_z(); | ||||||
|  |  | ||||||
| 	# Write procedure label, _procedure_name: | 	# Write procedure label, _procedure_name: | ||||||
| 	_write_token(v00); | 	_write_token(v0); | ||||||
|  |  | ||||||
| 	la a0, asm_colon | 	_write_z(@asm_colon); | ||||||
| 	_write_z(); |  | ||||||
|  |  | ||||||
| 	# Skip the function name and trailing parens, semicolon, "begin" and newline. | 	# Skip the function name and trailing parens, semicolon, "begin" and newline. | ||||||
| 	lw a0, 0(sp) | 	lw a0, 0(sp) | ||||||
| 	addi a0, a0, 10 | 	addi a0, a0, 10 | ||||||
| 	_advance_token(); | 	_advance_token(); | ||||||
|  |  | ||||||
| 	la a0, asm_prologue | 	_write_z(@asm_prologue); | ||||||
| 	_write_z(); |  | ||||||
|  |  | ||||||
| 	_compile_procedure_body(); | 	_compile_procedure_body(); | ||||||
|  |  | ||||||
| 	# Write the epilogue. | 	# Write the epilogue. | ||||||
| 	la a0, asm_epilogue | 	_write_z(@asm_epilogue); | ||||||
| 	_write_z(); |  | ||||||
|  |  | ||||||
| 	# Skip the "end" keyword, semicolon and newline. | 	# Skip the "end" keyword, semicolon and newline. | ||||||
| 	_advance_token(5); | 	_advance_token(5); | ||||||
| @@ -882,37 +971,22 @@ begin | |||||||
| 	li t1, '#' | 	li t1, '#' | ||||||
| 	beq t0, t1, .compile_comment | 	beq t0, t1, .compile_comment | ||||||
|  |  | ||||||
| 	la a0, source_code_position | 	# 8 is ".section" length. | ||||||
| 	lw a0, (a0) | 	_memcmp(source_code_position, @keyword_section, 8); | ||||||
| 	la a1, keyword_section |  | ||||||
| 	li a2, 8 # ".section" length. |  | ||||||
| 	_memcmp(); |  | ||||||
|  |  | ||||||
| 	beqz a0, .compile_section | 	beqz a0, .compile_section | ||||||
|  |  | ||||||
| 	la a0, source_code_position | 	# 5 is ".type" length. | ||||||
| 	lw a0, (a0) | 	_memcmp(source_code_position, @keyword_type, 5); | ||||||
| 	la a1, keyword_type |  | ||||||
| 	li a2, 5 # ".type" length. |  | ||||||
| 	_memcmp(); |  | ||||||
|  |  | ||||||
| 	beqz a0, .compile_type | 	beqz a0, .compile_type | ||||||
|  |  | ||||||
| 	la a0, source_code_position | 	# 5 is "proc " length. Space is needed to distinguish from "procedure". | ||||||
| 	lw a0, (a0) | 	_memcmp(source_code_position, @keyword_proc, 5); | ||||||
| 	la a1, keyword_proc |  | ||||||
| 	li a2, 5 # "proc " length. Space is needed to distinguish from "procedure". |  | ||||||
| 	_memcmp(); |  | ||||||
|  |  | ||||||
| 	beqz a0, .compile_procedure | 	beqz a0, .compile_procedure | ||||||
|  |  | ||||||
| 	la a0, source_code_position | 	# 6 is ".globl" length. | ||||||
| 	lw a0, (a0) | 	_memcmp(source_code_position, @keyword_global, 6); | ||||||
| 	la a1, keyword_global |  | ||||||
| 	li a2, 6 # ".globl" length. |  | ||||||
| 	_memcmp(); |  | ||||||
|  |  | ||||||
| 	beqz a0, .compile_global | 	beqz a0, .compile_global | ||||||
|  |  | ||||||
| 	# Not a known token, exit. | 	# Not a known token, exit. | ||||||
| 	goto .compile_end; | 	goto .compile_end; | ||||||
|  |  | ||||||
| @@ -959,9 +1033,8 @@ end; | |||||||
| proc _start(); | proc _start(); | ||||||
| begin | begin | ||||||
| 	# Read the source from the standard input. | 	# Read the source from the standard input. | ||||||
| 	la a0, source_code | 	# Second argument is buffer size. Modifying update the source_code definition. | ||||||
| 	li a1, 81920 # Buffer size. | 	_read_file(@source_code, 81920); | ||||||
| 	_read_file(); |  | ||||||
| 	_compile(); | 	_compile(); | ||||||
|  |  | ||||||
| 	_exit(0); | 	_exit(0); | ||||||
|   | |||||||
							
								
								
									
										1129
									
								
								boot/stage6.elna
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1129
									
								
								boot/stage6.elna
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,323 +0,0 @@ | |||||||
| # This Source Code Form is subject to the terms of the Mozilla Public License, |  | ||||||
| # v. 2.0. If a copy of the MPL was not distributed with this file, You can |  | ||||||
| # obtain one at https://mozilla.org/MPL/2.0/. -} |  | ||||||
| # frozen_string_literal: true |  | ||||||
|  |  | ||||||
| require 'pathname' |  | ||||||
| require 'uri' |  | ||||||
| require 'net/http' |  | ||||||
| require 'rake/clean' |  | ||||||
| require 'open3' |  | ||||||
| require 'etc' |  | ||||||
|  |  | ||||||
| GCC_VERSION = "15.1.0" |  | ||||||
| BINUTILS_VERSION = '2.44' |  | ||||||
| GLIBC_VERSION = '2.41' |  | ||||||
| KERNEL_VERSION = '5.15.181' |  | ||||||
|  |  | ||||||
| CLOBBER.include 'build' |  | ||||||
|  |  | ||||||
| class BuildTarget |  | ||||||
|   attr_accessor(:build, :gcc, :target, :tmp) |  | ||||||
|  |  | ||||||
|   def gxx |  | ||||||
|     @gcc.gsub 'c', '+' |  | ||||||
|   end |  | ||||||
|  |  | ||||||
|   def sysroot |  | ||||||
|     tmp + 'sysroot' |  | ||||||
|   end |  | ||||||
|  |  | ||||||
|   def rootfs |  | ||||||
|     tmp + 'rootfs' |  | ||||||
|   end |  | ||||||
|  |  | ||||||
|   def tools |  | ||||||
|     tmp + 'tools' |  | ||||||
|   end |  | ||||||
| end |  | ||||||
|  |  | ||||||
| def gcc_verbose(gcc_binary) |  | ||||||
|   read, write = IO.pipe |  | ||||||
|   sh({'LANG' => 'C'}, gcc_binary, '--verbose', err: write) |  | ||||||
|   write.close |  | ||||||
|   output = read.read |  | ||||||
|   read.close |  | ||||||
|   output |  | ||||||
| end |  | ||||||
|  |  | ||||||
| def find_build_target(gcc_version, task) |  | ||||||
|   gcc_binary = 'gcc' |  | ||||||
|   output = gcc_verbose gcc_binary |  | ||||||
|  |  | ||||||
|   if output.start_with? 'Apple clang' |  | ||||||
|     gcc_binary = "gcc-#{gcc_version.split('.').first}" |  | ||||||
|     output = gcc_verbose gcc_binary |  | ||||||
|   end |  | ||||||
|   result = output |  | ||||||
|     .lines |  | ||||||
|     .each_with_object(BuildTarget.new) do |line, accumulator| |  | ||||||
|       if line.start_with? 'Target: ' |  | ||||||
|         accumulator.build = line.split(' ').last.strip |  | ||||||
|       elsif line.start_with? 'COLLECT_GCC' |  | ||||||
|         accumulator.gcc = line.split('=').last.strip |  | ||||||
|       end |  | ||||||
|     end |  | ||||||
|   result.tmp = Pathname.new('./build') |  | ||||||
|   task.with_defaults target: 'riscv32-unknown-linux-gnu' |  | ||||||
|   result.target = task[:target] |  | ||||||
|   result |  | ||||||
| end |  | ||||||
|  |  | ||||||
| def download_and_unarchive(url, target) |  | ||||||
|   case File.extname url.path |  | ||||||
|   when '.bz2' |  | ||||||
|     archive_type = '-j' |  | ||||||
|     root_directory = File.basename url.path, '.tar.bz2' |  | ||||||
|   when '.xz' |  | ||||||
|     archive_type = '-J' |  | ||||||
|     root_directory = File.basename url.path, '.tar.xz' |  | ||||||
|   else |  | ||||||
|     raise "Unsupported archive type #{url.path}." |  | ||||||
|   end |  | ||||||
|  |  | ||||||
|   Net::HTTP.start(url.host, url.port, use_ssl: url.scheme == 'https') do |http| |  | ||||||
|     request = Net::HTTP::Get.new url.request_uri |  | ||||||
|  |  | ||||||
|     http.request request do |response| |  | ||||||
|       case response |  | ||||||
|       when Net::HTTPRedirection |  | ||||||
|         download_and_unarchive URI.parse(response['location']) |  | ||||||
|       when Net::HTTPSuccess |  | ||||||
|         Open3.popen2 'tar', '-C', target.to_path, archive_type, '-xv' do |stdin, stdout, wait_thread| |  | ||||||
|           Thread.new do |  | ||||||
|             stdout.each { |line| puts line } |  | ||||||
|           end |  | ||||||
|  |  | ||||||
|           response.read_body do |chunk| |  | ||||||
|             stdin.write chunk |  | ||||||
|           end |  | ||||||
|           stdin.close |  | ||||||
|  |  | ||||||
|           wait_thread.value |  | ||||||
|         end |  | ||||||
|       else |  | ||||||
|         response.error! |  | ||||||
|       end |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
|   target + root_directory |  | ||||||
| end |  | ||||||
|  |  | ||||||
| namespace :cross do |  | ||||||
|   desc 'Build cross binutils' |  | ||||||
|   task :binutils, [:target] do |_, args| |  | ||||||
|     options = find_build_target GCC_VERSION, args |  | ||||||
|     options.tools.mkpath |  | ||||||
|     source_directory = download_and_unarchive( |  | ||||||
|       URI.parse("https://ftp.gnu.org/gnu/binutils/binutils-#{BINUTILS_VERSION}.tar.xz"), |  | ||||||
|       options.tools) |  | ||||||
|  |  | ||||||
|     cwd = source_directory.dirname + 'build-binutils' |  | ||||||
|     cwd.mkpath |  | ||||||
|     options.rootfs.mkpath |  | ||||||
|  |  | ||||||
|     env = { |  | ||||||
|      'CC' => options.gcc, |  | ||||||
|      'CXX' => options.gxx |  | ||||||
|     } |  | ||||||
|     configure_options = [ |  | ||||||
|       "--prefix=#{options.rootfs.realpath}", |  | ||||||
|       "--target=#{options.target}", |  | ||||||
|       '--disable-nls', |  | ||||||
|       '--enable-gprofng=no', |  | ||||||
|       '--disable-werror', |  | ||||||
|       '--enable-default-hash-style=gnu', |  | ||||||
|       '--disable-libquadmath' |  | ||||||
|     ] |  | ||||||
|     configure = source_directory.relative_path_from(cwd) + 'configure' |  | ||||||
|     sh env, configure.to_path, *configure_options, chdir: cwd.to_path |  | ||||||
|     sh env, 'make', '-j', Etc.nprocessors.to_s, chdir: cwd.to_path |  | ||||||
|     sh env, 'make', 'install', chdir: cwd.to_path |  | ||||||
|   end |  | ||||||
|  |  | ||||||
|   desc 'Build stage 1 GCC' |  | ||||||
|   task :gcc1, [:target] do |_, args| |  | ||||||
|     options = find_build_target GCC_VERSION, args |  | ||||||
|     options.tools.mkpath |  | ||||||
|     source_directory = download_and_unarchive( |  | ||||||
|       URI.parse("https://gcc.gnu.org/pub/gcc/releases/gcc-#{GCC_VERSION}/gcc-#{GCC_VERSION}.tar.xz"), |  | ||||||
|       options.tools) |  | ||||||
|  |  | ||||||
|     cwd = source_directory.dirname + 'build-gcc' |  | ||||||
|     cwd.mkpath |  | ||||||
|     options.rootfs.mkpath |  | ||||||
|     options.sysroot.mkpath |  | ||||||
|  |  | ||||||
|     sh 'contrib/download_prerequisites', chdir: source_directory.to_path |  | ||||||
|     configure_options = [ |  | ||||||
|       "--prefix=#{options.rootfs.realpath}", |  | ||||||
|       "--with-sysroot=#{options.sysroot.realpath}", |  | ||||||
|       '--enable-languages=c,c++', |  | ||||||
|       '--disable-shared', |  | ||||||
|       '--with-arch=rv32imafdc', |  | ||||||
|       '--with-abi=ilp32d', |  | ||||||
|       '--with-tune=rocket', |  | ||||||
|       '--with-isa-spec=20191213', |  | ||||||
|       '--disable-bootstrap', |  | ||||||
|       '--disable-multilib', |  | ||||||
|       '--disable-libmudflap', |  | ||||||
|       '--disable-libssp', |  | ||||||
|       '--disable-libquadmath', |  | ||||||
|       '--disable-libsanitizer', |  | ||||||
|       '--disable-threads', |  | ||||||
|       '--disable-libatomic', |  | ||||||
|       '--disable-libgomp', |  | ||||||
|       '--disable-libvtv', |  | ||||||
|       '--disable-libstdcxx', |  | ||||||
|       '--disable-nls', |  | ||||||
|       '--with-newlib', |  | ||||||
|       '--without-headers', |  | ||||||
|       "--target=#{options.target}", |  | ||||||
|       "--build=#{options.build}", |  | ||||||
|       "--host=#{options.build}" |  | ||||||
|     ] |  | ||||||
|     flags = '-O2 -fPIC' |  | ||||||
|     env = { |  | ||||||
|       'CC' => options.gcc, |  | ||||||
|       'CXX' => options.gxx, |  | ||||||
|       'CFLAGS' => flags, |  | ||||||
|       'CXXFLAGS' => flags, |  | ||||||
|       'PATH' => "#{options.rootfs.realpath + 'bin'}:#{ENV['PATH']}" |  | ||||||
|     } |  | ||||||
|     configure = source_directory.relative_path_from(cwd) + 'configure' |  | ||||||
|     sh env, configure.to_path, *configure_options, chdir: cwd.to_path |  | ||||||
|     sh env, 'make', '-j', Etc.nprocessors.to_s, chdir: cwd.to_path |  | ||||||
|     sh env, 'make', 'install', chdir: cwd.to_path |  | ||||||
|   end |  | ||||||
|  |  | ||||||
|   desc 'Copy glibc headers' |  | ||||||
|   task :headers, [:target] do |_, args| |  | ||||||
|     options = find_build_target GCC_VERSION, args |  | ||||||
|     options.tools.mkpath |  | ||||||
|  |  | ||||||
|     source_directory = download_and_unarchive( |  | ||||||
|       URI.parse("https://ftp.gnu.org/gnu/glibc/glibc-#{GLIBC_VERSION}.tar.xz"), |  | ||||||
|       options.tools) |  | ||||||
|     include_directory = options.tools + 'include' |  | ||||||
|  |  | ||||||
|     include_directory.mkpath |  | ||||||
|     cp (source_directory + 'elf/elf.h'), (include_directory + 'elf.h') |  | ||||||
|   end |  | ||||||
|  |  | ||||||
|   desc 'Build linux kernel' |  | ||||||
|   task :kernel, [:target] do |_, args| |  | ||||||
|     options = find_build_target GCC_VERSION, args |  | ||||||
|     options.tools.mkpath |  | ||||||
|  |  | ||||||
|     cwd = download_and_unarchive( |  | ||||||
|       URI.parse("https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-#{KERNEL_VERSION}.tar.xz"), |  | ||||||
|       options.tools) |  | ||||||
|  |  | ||||||
|     env = { |  | ||||||
|       'CROSS_COMPILE' => "#{options.target}-", |  | ||||||
|       'ARCH' => 'riscv', |  | ||||||
|       'PATH' => "#{options.rootfs.realpath + 'bin'}:#{ENV['PATH']}", |  | ||||||
|       'HOSTCFLAGS' => "-D_UUID_T -D__GETHOSTUUID_H -I#{options.tools.realpath + 'include'}" |  | ||||||
|     } |  | ||||||
|     sh env, 'make', 'rv32_defconfig', chdir: cwd.to_path |  | ||||||
|     sh env, 'make', '-j', Etc.nprocessors.to_s, chdir: cwd.to_path |  | ||||||
|     sh env, 'make', 'headers', chdir: cwd.to_path |  | ||||||
|  |  | ||||||
|     user_directory = options.sysroot + 'usr' |  | ||||||
|  |  | ||||||
|     user_directory.mkpath |  | ||||||
|     cp_r (cwd + 'usr/include'), (user_directory + 'include') |  | ||||||
|   end |  | ||||||
|  |  | ||||||
|   desc 'Build glibc' |  | ||||||
|   task :glibc, [:target] do |_, args| |  | ||||||
|     options = find_build_target GCC_VERSION, args |  | ||||||
|     source_directory = options.tools + "glibc-#{GLIBC_VERSION}" |  | ||||||
|     configure_options = [ |  | ||||||
|       '--prefix=/usr', |  | ||||||
|       "--host=#{options.target}", |  | ||||||
|       "--target=#{options.target}", |  | ||||||
|       "--build=#{options.build}", |  | ||||||
|       "--enable-kernel=#{KERNEL_VERSION}", |  | ||||||
|       "--with-headers=#{options.sysroot.realpath + 'usr/include'}", |  | ||||||
|       '--disable-nscd', |  | ||||||
|       '--disable-libquadmath', |  | ||||||
|       '--disable-libitm', |  | ||||||
|       '--disable-werror', |  | ||||||
|       'libc_cv_forced_unwind=yes' |  | ||||||
|     ] |  | ||||||
|     bin = options.rootfs.realpath + 'bin' |  | ||||||
|     env = { |  | ||||||
|       'PATH' => "#{bin}:#{ENV['PATH']}", |  | ||||||
|       'MAKE' => 'make' # Otherwise it uses gnumake which can be different and too old. |  | ||||||
|     } |  | ||||||
|     cwd = source_directory.dirname + 'build-glibc' |  | ||||||
|     cwd.mkpath |  | ||||||
|  |  | ||||||
|     configure = source_directory.relative_path_from(cwd) +'./configure' |  | ||||||
|     sh env, configure.to_path, *configure_options, chdir: cwd.to_path |  | ||||||
|     sh env, 'make', '-j', Etc.nprocessors.to_s, chdir: cwd.to_path |  | ||||||
|     sh env, 'make', "install_root=#{options.sysroot.realpath}", 'install', chdir: cwd.to_path |  | ||||||
|   end |  | ||||||
|  |  | ||||||
|   desc 'Build stage 2 GCC' |  | ||||||
|   task :gcc2, [:target] do |_, args| |  | ||||||
|     options = find_build_target GCC_VERSION, args |  | ||||||
|     source_directory = options.tools + "gcc-#{GCC_VERSION}" |  | ||||||
|     cwd = options.tools + 'build-gcc' |  | ||||||
|  |  | ||||||
|     rm_rf cwd |  | ||||||
|     cwd.mkpath |  | ||||||
|  |  | ||||||
|     configure_options = [ |  | ||||||
|       "--prefix=#{options.rootfs.realpath}", |  | ||||||
|       "--with-sysroot=#{options.sysroot.realpath}", |  | ||||||
|       '--enable-languages=c,c++,lto', |  | ||||||
|       '--enable-lto', |  | ||||||
|       '--enable-shared', |  | ||||||
|       '--with-arch=rv32imafdc', |  | ||||||
|       '--with-abi=ilp32d', |  | ||||||
|       '--with-tune=rocket', |  | ||||||
|       '--with-isa-spec=20191213', |  | ||||||
|       '--disable-bootstrap', |  | ||||||
|       '--disable-multilib', |  | ||||||
|       '--enable-checking=release', |  | ||||||
|       '--disable-libssp', |  | ||||||
|       '--disable-libquadmath', |  | ||||||
|       '--enable-threads=posix', |  | ||||||
|       '--with-default-libstdcxx-abi=new', |  | ||||||
|       '--disable-nls', |  | ||||||
|       "--target=#{options.target}", |  | ||||||
|       "--build=#{options.build}", |  | ||||||
|       "--host=#{options.build}" |  | ||||||
|  |  | ||||||
|     ] |  | ||||||
|     flags = '-O2 -fPIC' |  | ||||||
|     env = { |  | ||||||
|       'CFLAGS' => flags, |  | ||||||
|       'CXXFLAGS' => flags, |  | ||||||
|       'PATH' => "#{options.rootfs.realpath + 'bin'}:#{ENV['PATH']}" |  | ||||||
|     } |  | ||||||
|     configure = source_directory.relative_path_from(cwd) + 'configure' |  | ||||||
|     sh env, configure.to_path, *configure_options, chdir: cwd.to_path |  | ||||||
|     sh env, 'make', '-j', Etc.nprocessors.to_s, chdir: cwd.to_path |  | ||||||
|     sh env, 'make', 'install', chdir: cwd.to_path |  | ||||||
|   end |  | ||||||
| end |  | ||||||
|  |  | ||||||
| desc 'Build cross toolchain' |  | ||||||
| task cross: [ |  | ||||||
|   'cross:binutils', |  | ||||||
|   'cross:gcc1', |  | ||||||
|   'cross:headers', |  | ||||||
|   'cross:kernel', |  | ||||||
|   'cross:glibc', |  | ||||||
|   'cross:gcc2' |  | ||||||
| ] do |  | ||||||
| end |  | ||||||
		Reference in New Issue
	
	Block a user