Add string literals
This commit is contained in:
9
Gemfile
9
Gemfile
@@ -1,9 +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
|
|
||||||
|
|
||||||
source 'https://rubygems.org'
|
|
||||||
|
|
||||||
gem 'term-ansicolor', '~> 1.2'
|
|
||||||
gem 'rake', '~> 13.2'
|
|
22
Gemfile.lock
22
Gemfile.lock
@@ -1,22 +0,0 @@
|
|||||||
GEM
|
|
||||||
remote: https://rubygems.org/
|
|
||||||
specs:
|
|
||||||
bigdecimal (3.1.9)
|
|
||||||
rake (13.2.1)
|
|
||||||
sync (0.5.0)
|
|
||||||
term-ansicolor (1.11.2)
|
|
||||||
tins (~> 1.0)
|
|
||||||
tins (1.38.0)
|
|
||||||
bigdecimal
|
|
||||||
sync
|
|
||||||
|
|
||||||
PLATFORMS
|
|
||||||
ruby
|
|
||||||
x86_64-linux
|
|
||||||
|
|
||||||
DEPENDENCIES
|
|
||||||
rake (~> 13.2)
|
|
||||||
term-ansicolor (~> 1.2)
|
|
||||||
|
|
||||||
BUNDLED WITH
|
|
||||||
2.6.7
|
|
18
Rakefile
18
Rakefile
@@ -6,8 +6,6 @@
|
|||||||
require 'open3'
|
require 'open3'
|
||||||
require 'rake/clean'
|
require 'rake/clean'
|
||||||
|
|
||||||
SYSROOT = '../eugenios/build/sysroot'
|
|
||||||
QEMU = 'qemu-riscv32'
|
|
||||||
STAGES = Dir.glob('boot/stage*.elna').collect { |stage| File.basename stage, '.elna' }.sort
|
STAGES = Dir.glob('boot/stage*.elna').collect { |stage| File.basename stage, '.elna' }.sort
|
||||||
|
|
||||||
CLEAN.include 'build/boot', 'build/valid'
|
CLEAN.include 'build/boot', 'build/valid'
|
||||||
@@ -19,6 +17,10 @@ def compile(input, output)
|
|||||||
sh ENV.fetch('CC', 'gcc'), '-nostdlib', '-o', output, input
|
sh ENV.fetch('CC', 'gcc'), '-nostdlib', '-o', output, input
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def run(exe)
|
||||||
|
ENV.fetch('QEMU', '').split << exe
|
||||||
|
end
|
||||||
|
|
||||||
task default: :boot
|
task default: :boot
|
||||||
|
|
||||||
desc 'Final stage'
|
desc 'Final stage'
|
||||||
@@ -31,9 +33,8 @@ task boot: "boot/#{STAGES.last}.elna" do |t|
|
|||||||
source = groupped['.elna']
|
source = groupped['.elna']
|
||||||
|
|
||||||
cat_arguments = ['cat', source]
|
cat_arguments = ['cat', source]
|
||||||
compiler_arguments = [QEMU, '-L', SYSROOT, exe]
|
|
||||||
diff_arguments = ['diff', '-Nur', '--text', expected, '-']
|
diff_arguments = ['diff', '-Nur', '--text', expected, '-']
|
||||||
Open3.pipeline(cat_arguments, compiler_arguments, diff_arguments)
|
Open3.pipeline(cat_arguments, run(exe), diff_arguments)
|
||||||
end
|
end
|
||||||
|
|
||||||
desc 'Convert previous stage language into the current stage language'
|
desc 'Convert previous stage language into the current stage language'
|
||||||
@@ -60,8 +61,7 @@ STAGES.each do |stage|
|
|||||||
exe, source = t.prerequisites
|
exe, source = t.prerequisites
|
||||||
|
|
||||||
cat_arguments = ['cat', source]
|
cat_arguments = ['cat', source]
|
||||||
compiler_arguments = [QEMU, '-L', SYSROOT, exe]
|
last_stdout, wait_threads = Open3.pipeline_r(cat_arguments, run(exe))
|
||||||
last_stdout, wait_threads = Open3.pipeline_r(cat_arguments, compiler_arguments)
|
|
||||||
|
|
||||||
IO.copy_stream last_stdout, t.name
|
IO.copy_stream last_stdout, t.name
|
||||||
end
|
end
|
||||||
@@ -70,8 +70,7 @@ STAGES.each do |stage|
|
|||||||
exe, source = t.prerequisites
|
exe, source = t.prerequisites
|
||||||
|
|
||||||
cat_arguments = ['cat', source]
|
cat_arguments = ['cat', source]
|
||||||
compiler_arguments = [QEMU, '-L', SYSROOT, exe]
|
last_stdout, wait_threads = Open3.pipeline_r(cat_arguments, run(exe))
|
||||||
last_stdout, wait_threads = Open3.pipeline_r(cat_arguments, compiler_arguments)
|
|
||||||
|
|
||||||
IO.copy_stream last_stdout, t.name
|
IO.copy_stream last_stdout, t.name
|
||||||
end
|
end
|
||||||
@@ -85,8 +84,7 @@ file 'build/valid/stage1.s' => ['build/boot/stage1', 'boot/stage1.s', 'build/val
|
|||||||
source, exe, = t.prerequisites.partition { |prerequisite| prerequisite.end_with? '.s' }
|
source, exe, = t.prerequisites.partition { |prerequisite| prerequisite.end_with? '.s' }
|
||||||
|
|
||||||
cat_arguments = ['cat', *source]
|
cat_arguments = ['cat', *source]
|
||||||
compiler_arguments = [QEMU, '-L', SYSROOT, *exe]
|
last_stdout, wait_threads = Open3.pipeline_r(cat_arguments, run(exe.first))
|
||||||
last_stdout, wait_threads = Open3.pipeline_r(cat_arguments, compiler_arguments)
|
|
||||||
|
|
||||||
IO.copy_stream last_stdout, t.name
|
IO.copy_stream last_stdout, t.name
|
||||||
end
|
end
|
||||||
|
209
boot/stage6.elna
209
boot/stage6.elna
@@ -1,9 +1,10 @@
|
|||||||
# ihis Source Code Form is subject to the terms of the Mozilla Public License,
|
# 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
|
# 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/.
|
||||||
|
|
||||||
# Stage 6 compiler.
|
# Stage 6 compiler.
|
||||||
#
|
#
|
||||||
|
# - String literals.
|
||||||
|
|
||||||
.section .rodata
|
.section .rodata
|
||||||
|
|
||||||
@@ -43,6 +44,9 @@ asm_type_directive: .string ".type "
|
|||||||
.type asm_type_function, @object
|
.type asm_type_function, @object
|
||||||
asm_type_function: .string ", @function\n"
|
asm_type_function: .string ", @function\n"
|
||||||
|
|
||||||
|
.type asm_type_object, @object
|
||||||
|
asm_type_object: .string ", @object\n"
|
||||||
|
|
||||||
.type asm_colon, @object
|
.type asm_colon, @object
|
||||||
asm_colon: .string ":\n"
|
asm_colon: .string ":\n"
|
||||||
|
|
||||||
@@ -112,19 +116,110 @@ asm_comma: .string ", "
|
|||||||
.type asm_sp, @object
|
.type asm_sp, @object
|
||||||
asm_sp: .string "sp"
|
asm_sp: .string "sp"
|
||||||
|
|
||||||
|
.type asm_rodata, @object
|
||||||
|
asm_rodata: .string ".section .rodata\n"
|
||||||
|
|
||||||
|
.type asm_strings, @object
|
||||||
|
asm_strings: .string "strings"
|
||||||
|
|
||||||
|
.type asm_ascii, @object
|
||||||
|
asm_ascii: .string " .ascii "
|
||||||
|
|
||||||
.section .bss
|
.section .bss
|
||||||
|
|
||||||
# When modifiying also change the read size in the entry point procedure.
|
# When modifiying also change the read size in the entry point procedure.
|
||||||
.type source_code, @object
|
.type source_code, @object
|
||||||
source_code: .zero 81920
|
source_code: .zero 81920
|
||||||
|
|
||||||
|
.type compiler_strings, @object
|
||||||
|
compiler_strings: .zero 8192
|
||||||
|
|
||||||
.section .data
|
.section .data
|
||||||
|
|
||||||
|
.type compiler_strings_position, @object
|
||||||
|
compiler_strings_position: .word compiler_strings
|
||||||
|
|
||||||
|
.type compiler_strings_length, @object
|
||||||
|
compiler_strings_length: .word 0
|
||||||
|
|
||||||
.type source_code_position, @object
|
.type source_code_position, @object
|
||||||
source_code_position: .word source_code
|
source_code_position: .word source_code
|
||||||
|
|
||||||
.section .text
|
.section .text
|
||||||
|
|
||||||
|
# Calculates and returns the string token length between quotes, including the
|
||||||
|
# escaping slash characters.
|
||||||
|
#
|
||||||
|
# Parameters:
|
||||||
|
# a0 - String token pointer.
|
||||||
|
#
|
||||||
|
# Returns the length in a0.
|
||||||
|
proc _string_length();
|
||||||
|
begin
|
||||||
|
# Reset the counter.
|
||||||
|
v0 := 0;
|
||||||
|
|
||||||
|
.string_length_loop:
|
||||||
|
v88 := v88 + 1;
|
||||||
|
|
||||||
|
lw t0, 88(sp)
|
||||||
|
lb t0, (t0)
|
||||||
|
|
||||||
|
li t1, '"'
|
||||||
|
beq t0, t1, .string_length_end
|
||||||
|
|
||||||
|
v0 := v0 + 1;
|
||||||
|
goto .string_length_loop;
|
||||||
|
|
||||||
|
.string_length_end:
|
||||||
|
return v0
|
||||||
|
end;
|
||||||
|
|
||||||
|
# Adds a string to the global, read-only string storage.
|
||||||
|
#
|
||||||
|
# Parameters:
|
||||||
|
# a0 - String token.
|
||||||
|
#
|
||||||
|
# Returns the offset from the beginning of the storage to the new string in a0.
|
||||||
|
proc _add_string();
|
||||||
|
begin
|
||||||
|
v0 := v88 + 1;
|
||||||
|
v4 := compiler_strings_length;
|
||||||
|
|
||||||
|
.add_string_loop:
|
||||||
|
lw t0, 0(sp)
|
||||||
|
lb t1, (t0)
|
||||||
|
li t2, '"'
|
||||||
|
|
||||||
|
beq t1, t2, .add_string_end
|
||||||
|
|
||||||
|
la t2, compiler_strings_position
|
||||||
|
lw t3, (t2)
|
||||||
|
sb t1, (t3)
|
||||||
|
|
||||||
|
addi t3, t3, 1
|
||||||
|
sw t3, (t2)
|
||||||
|
|
||||||
|
addi t0, t0, 1
|
||||||
|
sw t0, 0(sp)
|
||||||
|
|
||||||
|
li t2, '\\'
|
||||||
|
bne t1, t2, .add_string_increment
|
||||||
|
|
||||||
|
goto .add_string_loop;
|
||||||
|
|
||||||
|
.add_string_increment:
|
||||||
|
la t2, compiler_strings_length
|
||||||
|
lw t4, (t2)
|
||||||
|
addi t4, t4, 1
|
||||||
|
sw t4, (t2)
|
||||||
|
|
||||||
|
goto .add_string_loop;
|
||||||
|
|
||||||
|
.add_string_end:
|
||||||
|
return v4
|
||||||
|
end;
|
||||||
|
|
||||||
# Reads standard input into a buffer.
|
# Reads standard input into a buffer.
|
||||||
# a0 - Buffer pointer.
|
# a0 - Buffer pointer.
|
||||||
# a1 - Buffer size.
|
# a1 - Buffer size.
|
||||||
@@ -595,6 +690,37 @@ begin
|
|||||||
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
proc _compile_string_literal();
|
||||||
|
begin
|
||||||
|
_string_length(source_code_position);
|
||||||
|
sw a0, 0(sp)
|
||||||
|
|
||||||
|
_add_string(source_code_position);
|
||||||
|
sw a0, 4(sp)
|
||||||
|
|
||||||
|
_advance_token(v0 + 2);
|
||||||
|
|
||||||
|
_write_z(@asm_la);
|
||||||
|
_write_register('t', 0);
|
||||||
|
_write_z(@asm_comma);
|
||||||
|
_write_z(@asm_strings);
|
||||||
|
_write_c('\n');
|
||||||
|
|
||||||
|
_write_z(@asm_li);
|
||||||
|
_write_register('t', 1);
|
||||||
|
_write_z(@asm_comma);
|
||||||
|
_write_i(v4);
|
||||||
|
_write_c('\n');
|
||||||
|
|
||||||
|
_write_z(@asm_add);
|
||||||
|
_write_register('t', 0);
|
||||||
|
_write_z(@asm_comma);
|
||||||
|
_write_register('t', 0);
|
||||||
|
_write_z(@asm_comma);
|
||||||
|
_write_register('t', 1);
|
||||||
|
_write_c('\n');
|
||||||
|
end;
|
||||||
|
|
||||||
proc _compile_term();
|
proc _compile_term();
|
||||||
begin
|
begin
|
||||||
la t0, source_code_position
|
la t0, source_code_position
|
||||||
@@ -614,6 +740,9 @@ begin
|
|||||||
li t1, '~'
|
li t1, '~'
|
||||||
beq a0, t1, .compile_term_not
|
beq a0, t1, .compile_term_not
|
||||||
|
|
||||||
|
li t1, '"'
|
||||||
|
beq a0, t1, .compile_term_string_literal
|
||||||
|
|
||||||
_is_digit(v0);
|
_is_digit(v0);
|
||||||
bnez a0, .compile_term_integer_literal
|
bnez a0, .compile_term_integer_literal
|
||||||
|
|
||||||
@@ -639,6 +768,10 @@ begin
|
|||||||
_compile_not_expression();
|
_compile_not_expression();
|
||||||
goto .compile_term_end;
|
goto .compile_term_end;
|
||||||
|
|
||||||
|
.compile_term_string_literal:
|
||||||
|
_compile_string_literal();
|
||||||
|
goto .compile_term_end;
|
||||||
|
|
||||||
.compile_term_variable:
|
.compile_term_variable:
|
||||||
_compile_variable_expression();
|
_compile_variable_expression();
|
||||||
goto .compile_term_end;
|
goto .compile_term_end;
|
||||||
@@ -1336,63 +1469,99 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
# Process the source code and print the generated code.
|
# Process the source code and print the generated code.
|
||||||
proc _compile();
|
proc _compile_module();
|
||||||
begin
|
begin
|
||||||
.compile_loop:
|
.compile_module_loop:
|
||||||
_skip_newlines();
|
_skip_newlines();
|
||||||
|
|
||||||
la t0, source_code_position
|
la t0, source_code_position
|
||||||
lw t0, (t0)
|
lw t0, (t0)
|
||||||
lb t0, (t0)
|
lb t0, (t0)
|
||||||
beqz t0, .compile_end
|
beqz t0, .compile_module_end
|
||||||
li t1, '#'
|
li t1, '#'
|
||||||
beq t0, t1, .compile_comment
|
beq t0, t1, .compile_module_comment
|
||||||
|
|
||||||
# 8 is ".section" length.
|
# 8 is ".section" length.
|
||||||
_memcmp(source_code_position, @keyword_section, 8);
|
_memcmp(source_code_position, @keyword_section, 8);
|
||||||
beqz a0, .compile_section
|
beqz a0, .compile_module_section
|
||||||
|
|
||||||
# 5 is ".type" length.
|
# 5 is ".type" length.
|
||||||
_memcmp(source_code_position, @keyword_type, 5);
|
_memcmp(source_code_position, @keyword_type, 5);
|
||||||
beqz a0, .compile_type
|
beqz a0, .compile_module_type
|
||||||
|
|
||||||
# 5 is "proc " length. Space is needed to distinguish from "procedure".
|
# 5 is "proc " length. Space is needed to distinguish from "procedure".
|
||||||
_memcmp(source_code_position, @keyword_proc, 5);
|
_memcmp(source_code_position, @keyword_proc, 5);
|
||||||
beqz a0, .compile_procedure
|
beqz a0, .compile_module_procedure
|
||||||
|
|
||||||
# 6 is ".globl" length.
|
# 6 is ".globl" length.
|
||||||
_memcmp(source_code_position, @keyword_global, 6);
|
_memcmp(source_code_position, @keyword_global, 6);
|
||||||
beqz a0, .compile_global
|
beqz a0, .compile_module_global
|
||||||
|
|
||||||
# Not a known token, exit.
|
# Not a known token, exit.
|
||||||
goto .compile_end;
|
goto .compile_module_end;
|
||||||
|
|
||||||
.compile_section:
|
.compile_module_section:
|
||||||
_compile_section();
|
_compile_section();
|
||||||
|
|
||||||
goto .compile_loop;
|
goto .compile_module_loop;
|
||||||
|
|
||||||
.compile_type:
|
.compile_module_type:
|
||||||
_compile_type();
|
_compile_type();
|
||||||
|
|
||||||
goto .compile_loop;
|
goto .compile_module_loop;
|
||||||
|
|
||||||
.compile_global:
|
.compile_module_global:
|
||||||
_compile_line();
|
_compile_line();
|
||||||
|
|
||||||
goto .compile_loop;
|
goto .compile_module_loop;
|
||||||
|
|
||||||
.compile_comment:
|
.compile_module_comment:
|
||||||
_skip_comment();
|
_skip_comment();
|
||||||
|
|
||||||
goto .compile_loop;
|
goto .compile_module_loop;
|
||||||
|
|
||||||
.compile_procedure:
|
.compile_module_procedure:
|
||||||
_compile_procedure();
|
_compile_procedure();
|
||||||
|
|
||||||
goto .compile_loop;
|
goto .compile_module_loop;
|
||||||
|
|
||||||
|
.compile_module_end:
|
||||||
|
end;
|
||||||
|
|
||||||
|
proc _compile();
|
||||||
|
begin
|
||||||
|
_compile_module();
|
||||||
|
|
||||||
|
_write_z(@asm_rodata);
|
||||||
|
_write_z(@asm_type_directive);
|
||||||
|
_write_z(@asm_strings);
|
||||||
|
_write_z(@asm_type_object);
|
||||||
|
_write_z(@asm_strings);
|
||||||
|
_write_c(':');
|
||||||
|
_write_z(@asm_ascii);
|
||||||
|
_write_c('"');
|
||||||
|
|
||||||
|
la t0, compiler_strings
|
||||||
|
sw t0, 0(sp)
|
||||||
|
|
||||||
|
.compile_loop:
|
||||||
|
lw t0, 0(sp)
|
||||||
|
la t1, compiler_strings_position
|
||||||
|
lw t1, (t1)
|
||||||
|
bge t0, t1, .compile_end
|
||||||
|
|
||||||
|
lb a0, (t0)
|
||||||
|
|
||||||
|
addi t0, t0, 1
|
||||||
|
sw t0, 0(sp)
|
||||||
|
|
||||||
|
_write_c();
|
||||||
|
|
||||||
|
j .compile_loop
|
||||||
|
|
||||||
.compile_end:
|
.compile_end:
|
||||||
|
_write_c('"');
|
||||||
|
_write_c('\n');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
# Terminates the program. a0 contains the return code.
|
# Terminates the program. a0 contains the return code.
|
||||||
|
1260
boot/stage7.elna
Normal file
1260
boot/stage7.elna
Normal file
File diff suppressed because it is too large
Load Diff
1260
boot/stage8.elna
Normal file
1260
boot/stage8.elna
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user