Add arrays
This commit is contained in:
@@ -6,6 +6,7 @@ namespace Nub.Lang.Backend.Custom;
|
||||
public class Generator
|
||||
{
|
||||
private const string Entrypoint = "main";
|
||||
private const bool ZeroBasedIndexing = false;
|
||||
|
||||
private readonly List<DefinitionNode> _definitions;
|
||||
private readonly SymbolTable _symbolTable;
|
||||
@@ -69,6 +70,10 @@ public class Generator
|
||||
}
|
||||
|
||||
_builder.AppendLine("""
|
||||
array_out_of_bounds:
|
||||
mov rax, 60
|
||||
mov rdi, 69
|
||||
syscall
|
||||
|
||||
strcmp:
|
||||
xor rdx, rdx
|
||||
@@ -204,6 +209,9 @@ public class Generator
|
||||
{
|
||||
switch (statement)
|
||||
{
|
||||
case ArrayIndexAssignmentNode arrayIndexAssignment:
|
||||
GenerateArrayIndexAssignment(arrayIndexAssignment, func);
|
||||
break;
|
||||
case FuncCallStatementNode funcCallStatement:
|
||||
GenerateFuncCall(funcCallStatement.FuncCall, func);
|
||||
break;
|
||||
@@ -230,6 +238,15 @@ public class Generator
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateArrayIndexAssignment(ArrayIndexAssignmentNode arrayIndexAssignment, LocalFunc func)
|
||||
{
|
||||
GenerateExpression(arrayIndexAssignment.Value, func);
|
||||
_builder.AppendLine(" push rax");
|
||||
GenerateArrayIndexPointerAccess(arrayIndexAssignment.Identifier, arrayIndexAssignment.Index, func);
|
||||
_builder.AppendLine(" pop rdx");
|
||||
_builder.AppendLine(" mov [rax], rdx");
|
||||
}
|
||||
|
||||
private void GenerateIf(IfNode ifStatement, LocalFunc func)
|
||||
{
|
||||
var endLabel = _labelFactory.Create();
|
||||
@@ -298,6 +315,12 @@ public class Generator
|
||||
{
|
||||
switch (expression)
|
||||
{
|
||||
case ArrayIndexAccessNode arrayIndexAccess:
|
||||
GenerateArrayIndexAccess(arrayIndexAccess, func);
|
||||
break;
|
||||
case ArrayInitializerNode arrayInitializer:
|
||||
GenerateArrayInitializer(arrayInitializer, func);
|
||||
break;
|
||||
case BinaryExpressionNode binaryExpression:
|
||||
GenerateBinaryExpression(binaryExpression, func);
|
||||
break;
|
||||
@@ -318,6 +341,28 @@ public class Generator
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateArrayIndexAccess(ArrayIndexAccessNode arrayIndexAccess, LocalFunc func)
|
||||
{
|
||||
GenerateArrayIndexPointerAccess(arrayIndexAccess.Identifier, arrayIndexAccess.Index, func);
|
||||
_builder.AppendLine(" mov rax, [rax]");
|
||||
}
|
||||
|
||||
private void GenerateArrayInitializer(ArrayInitializerNode arrayInitializer, LocalFunc func)
|
||||
{
|
||||
_builder.AppendLine($"""
|
||||
mov rax, 9
|
||||
mov rdi, 0
|
||||
mov rsi, {8 + arrayInitializer.Length * 8}
|
||||
mov rdx, 3
|
||||
mov r10, 34
|
||||
mov r8, -1
|
||||
mov r9, 0
|
||||
syscall
|
||||
|
||||
mov QWORD [rax], {arrayInitializer.Length}
|
||||
""");
|
||||
}
|
||||
|
||||
private void GenerateBinaryExpression(BinaryExpressionNode binaryExpression, LocalFunc func)
|
||||
{
|
||||
GenerateExpression(binaryExpression.Left, func);
|
||||
@@ -576,4 +621,31 @@ public class Generator
|
||||
|
||||
_builder.AppendLine(" syscall");
|
||||
}
|
||||
|
||||
private void GenerateArrayIndexPointerAccess(IdentifierNode identifier, ExpressionNode index, LocalFunc func)
|
||||
{
|
||||
GenerateExpression(index, func);
|
||||
_builder.AppendLine(" push rax");
|
||||
GenerateIdentifier(identifier, func);
|
||||
_builder.AppendLine(" pop rbx");
|
||||
|
||||
// rcx now holds the length of the array which we can use to check bounds
|
||||
_builder.AppendLine(" mov rcx, [rax]");
|
||||
_builder.AppendLine(" cmp rbx, rcx");
|
||||
if (ZeroBasedIndexing)
|
||||
{
|
||||
_builder.AppendLine(" jge array_out_of_bounds");
|
||||
_builder.AppendLine(" cmp rbx, 0");
|
||||
}
|
||||
else
|
||||
{
|
||||
_builder.AppendLine(" jg array_out_of_bounds");
|
||||
_builder.AppendLine(" cmp rbx, 1");
|
||||
}
|
||||
_builder.AppendLine(" jl array_out_of_bounds");
|
||||
|
||||
_builder.AppendLine(" inc rbx");
|
||||
_builder.AppendLine(" shl rbx, 3");
|
||||
_builder.AppendLine(" add rax, rbx");
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ public class SymbolTable
|
||||
{
|
||||
private readonly List<Func> _funcDefinitions = [];
|
||||
private readonly List<GlobalVariable> _globalVariables = [];
|
||||
private LabelFactory _labelFactory;
|
||||
private readonly LabelFactory _labelFactory;
|
||||
|
||||
public readonly Dictionary<string, string> Strings = [];
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ public class Lexer
|
||||
["else"] = Symbol.Else,
|
||||
["while"] = Symbol.While,
|
||||
["return"] = Symbol.Return,
|
||||
["new"] = Symbol.New,
|
||||
};
|
||||
|
||||
private static readonly Dictionary<char[], Symbol> Chians = new()
|
||||
|
||||
@@ -38,4 +38,5 @@ public enum Symbol
|
||||
Minus,
|
||||
Star,
|
||||
ForwardSlash,
|
||||
New,
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Nub.Lang.Frontend.Parsing;
|
||||
|
||||
public class ArrayIndexAccessNode(IdentifierNode identifier, ExpressionNode index) : ExpressionNode
|
||||
{
|
||||
public IdentifierNode Identifier { get; } = identifier;
|
||||
public ExpressionNode Index { get; } = index;
|
||||
|
||||
public override string ToString() => $"{Identifier}[{Index}]";
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Nub.Lang.Frontend.Parsing;
|
||||
|
||||
public class ArrayIndexAssignmentNode(IdentifierNode identifier, ExpressionNode index, ExpressionNode value) : StatementNode
|
||||
{
|
||||
public IdentifierNode Identifier { get; } = identifier;
|
||||
public ExpressionNode Index { get; } = index;
|
||||
public ExpressionNode Value { get; } = value;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Nub.Lang.Frontend.Parsing;
|
||||
|
||||
public class ArrayInitializerNode(long length, Type innerType) : ExpressionNode
|
||||
{
|
||||
public long Length { get; } = length;
|
||||
public Type InnerType { get; } = innerType;
|
||||
}
|
||||
@@ -4,8 +4,5 @@ public class IdentifierNode(string identifier) : ExpressionNode
|
||||
{
|
||||
public string Identifier { get; } = identifier;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Identifier;
|
||||
}
|
||||
public override string ToString() => Identifier;
|
||||
}
|
||||
@@ -149,6 +149,15 @@ public class Parser
|
||||
|
||||
return new FuncCallStatementNode(new FuncCall(identifier.Value, parameters));
|
||||
}
|
||||
case Symbol.OpenBracket:
|
||||
{
|
||||
var index = ParseExpression();
|
||||
ExpectSymbol(Symbol.CloseBracket);
|
||||
ExpectSymbol(Symbol.Assign);
|
||||
var value = ParseExpression();
|
||||
ExpectSymbol(Symbol.Semicolon);
|
||||
return new ArrayIndexAssignmentNode(new IdentifierNode(identifier.Value), index, value);
|
||||
}
|
||||
case Symbol.Assign:
|
||||
{
|
||||
var value = ParseExpression();
|
||||
@@ -310,10 +319,32 @@ public class Parser
|
||||
return new LiteralNode(literal.Value, literal.Type);
|
||||
case IdentifierToken identifier:
|
||||
return ParseExpressionIdentifier(identifier);
|
||||
case SymbolToken { Symbol: Symbol.OpenParen }:
|
||||
var expression = ParseExpression();
|
||||
ExpectSymbol(Symbol.CloseParen);
|
||||
return expression;
|
||||
case SymbolToken symbolToken:
|
||||
{
|
||||
switch (symbolToken.Symbol)
|
||||
{
|
||||
case Symbol.OpenParen:
|
||||
{
|
||||
var expression = ParseExpression();
|
||||
ExpectSymbol(Symbol.CloseParen);
|
||||
return expression;
|
||||
}
|
||||
case Symbol.New:
|
||||
{
|
||||
var type = ParseType();
|
||||
ExpectSymbol(Symbol.OpenParen);
|
||||
var size = ExpectLiteral();
|
||||
if (size.Type is not PrimitiveType { Kind: PrimitiveTypeKind.Int64 })
|
||||
{
|
||||
throw new Exception($"Array initializer size must be an {PrimitiveTypeKind.Int64}");
|
||||
}
|
||||
ExpectSymbol(Symbol.CloseParen);
|
||||
return new ArrayInitializerNode(long.Parse(size.Value), type);
|
||||
}
|
||||
default:
|
||||
throw new Exception($"Unknown symbol: {symbolToken.Symbol}");
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw new Exception($"Unexpected token type {token.GetType().Name}");
|
||||
}
|
||||
@@ -321,6 +352,13 @@ public class Parser
|
||||
|
||||
private ExpressionNode ParseExpressionIdentifier(IdentifierToken identifier)
|
||||
{
|
||||
if (TryExpectSymbol(Symbol.OpenBracket))
|
||||
{
|
||||
var index = ParseExpression();
|
||||
ExpectSymbol(Symbol.CloseBracket);
|
||||
return new ArrayIndexAccessNode(new IdentifierNode(identifier.Value), index);
|
||||
}
|
||||
|
||||
if (TryExpectSymbol(Symbol.OpenParen))
|
||||
{
|
||||
List<ExpressionNode> parameters = [];
|
||||
@@ -356,30 +394,42 @@ public class Parser
|
||||
private Type ParseType()
|
||||
{
|
||||
var name = ExpectIdentifier().Value;
|
||||
if (name == "Func")
|
||||
|
||||
switch (name)
|
||||
{
|
||||
List<Type> typeArguments = [];
|
||||
if (TryExpectSymbol(Symbol.LessThan))
|
||||
case "Func":
|
||||
{
|
||||
while (!TryExpectSymbol(Symbol.GreaterThan))
|
||||
List<Type> typeArguments = [];
|
||||
if (TryExpectSymbol(Symbol.LessThan))
|
||||
{
|
||||
var type = ParseType();
|
||||
typeArguments.Add(type);
|
||||
TryExpectSymbol(Symbol.Comma);
|
||||
while (!TryExpectSymbol(Symbol.GreaterThan))
|
||||
{
|
||||
var type = ParseType();
|
||||
typeArguments.Add(type);
|
||||
TryExpectSymbol(Symbol.Comma);
|
||||
}
|
||||
}
|
||||
|
||||
var returnType = Optional<Type>.OfNullable(typeArguments.LastOrDefault());
|
||||
|
||||
return new DelegateType(typeArguments.Take(typeArguments.Count - 1).ToList(), returnType);
|
||||
}
|
||||
case "String":
|
||||
{
|
||||
return new StringType();
|
||||
}
|
||||
case "Array":
|
||||
{
|
||||
ExpectSymbol(Symbol.LessThan);
|
||||
var innerType = ParseType();
|
||||
ExpectSymbol(Symbol.GreaterThan);
|
||||
return new ArrayType(innerType);
|
||||
}
|
||||
default:
|
||||
{
|
||||
return PrimitiveType.Parse(name);
|
||||
}
|
||||
|
||||
var returnType = Optional<Type>.OfNullable(typeArguments.LastOrDefault());
|
||||
|
||||
return new DelegateType(typeArguments.Take(typeArguments.Count - 1).ToList(), returnType);
|
||||
}
|
||||
|
||||
if (name == "String")
|
||||
{
|
||||
return new StringType();
|
||||
}
|
||||
|
||||
return PrimitiveType.Parse(name);
|
||||
}
|
||||
|
||||
private Token ExpectToken()
|
||||
|
||||
@@ -83,6 +83,9 @@ public class ExpressionTyper
|
||||
{
|
||||
switch (statement)
|
||||
{
|
||||
case ArrayIndexAssignmentNode arrayIndexAssignment:
|
||||
PopulateArrayIndexAssignment(arrayIndexAssignment);
|
||||
break;
|
||||
case FuncCallStatementNode funcCall:
|
||||
PopulateFuncCallStatement(funcCall);
|
||||
break;
|
||||
@@ -109,6 +112,13 @@ public class ExpressionTyper
|
||||
}
|
||||
}
|
||||
|
||||
private void PopulateArrayIndexAssignment(ArrayIndexAssignmentNode arrayIndexAssignment)
|
||||
{
|
||||
PopulateIdentifier(arrayIndexAssignment.Identifier);
|
||||
PopulateExpression(arrayIndexAssignment.Index);
|
||||
PopulateExpression(arrayIndexAssignment.Value);
|
||||
}
|
||||
|
||||
private void PopulateFuncCallStatement(FuncCallStatementNode funcCall)
|
||||
{
|
||||
foreach (var parameter in funcCall.FuncCall.Parameters)
|
||||
@@ -168,6 +178,12 @@ public class ExpressionTyper
|
||||
{
|
||||
switch (expression)
|
||||
{
|
||||
case ArrayIndexAccessNode arrayIndexAccess:
|
||||
PopulateArrayIndexAccess(arrayIndexAccess);
|
||||
break;
|
||||
case ArrayInitializerNode arrayInitializer:
|
||||
PopulateArrayInitializer(arrayInitializer);
|
||||
break;
|
||||
case BinaryExpressionNode binaryExpression:
|
||||
PopulateBinaryExpression(binaryExpression);
|
||||
break;
|
||||
@@ -188,6 +204,30 @@ public class ExpressionTyper
|
||||
}
|
||||
}
|
||||
|
||||
private void PopulateArrayIndexAccess(ArrayIndexAccessNode arrayIndexAccess)
|
||||
{
|
||||
PopulateExpression(arrayIndexAccess.Index);
|
||||
PopulateIdentifier(arrayIndexAccess.Identifier);
|
||||
|
||||
var variable = _variables.FirstOrDefault(v => v.Name == arrayIndexAccess.Identifier.Identifier);
|
||||
if (variable == null)
|
||||
{
|
||||
throw new Exception($"Variable {arrayIndexAccess.Identifier} is not defined");
|
||||
}
|
||||
|
||||
if (variable.Type is not ArrayType arrayType)
|
||||
{
|
||||
throw new Exception($"Variable {arrayIndexAccess.Identifier} is not an array type");
|
||||
}
|
||||
|
||||
arrayIndexAccess.Type = arrayType.InnerType;
|
||||
}
|
||||
|
||||
private void PopulateArrayInitializer(ArrayInitializerNode arrayInitializer)
|
||||
{
|
||||
arrayInitializer.Type = arrayInitializer.InnerType;
|
||||
}
|
||||
|
||||
private void PopulateBinaryExpression(BinaryExpressionNode binaryExpression)
|
||||
{
|
||||
PopulateExpression(binaryExpression.Left);
|
||||
|
||||
@@ -41,6 +41,18 @@ public record StringType : Type
|
||||
public override string ToString() => "String";
|
||||
}
|
||||
|
||||
public record ArrayType : Type
|
||||
{
|
||||
public ArrayType(Type innerType)
|
||||
{
|
||||
InnerType = innerType;
|
||||
}
|
||||
|
||||
public Type InnerType { get; }
|
||||
|
||||
public override string ToString() => $"{InnerType}";
|
||||
}
|
||||
|
||||
public record DelegateType : Type
|
||||
{
|
||||
public DelegateType(List<Type> parameters, Optional<Type> returnType)
|
||||
|
||||
311
input/core/util.asm
Normal file
311
input/core/util.asm
Normal file
@@ -0,0 +1,311 @@
|
||||
;*********************************************************************
|
||||
; util.asm
|
||||
; Version: 1.2
|
||||
; Author: mjbrusso
|
||||
; Contributors: AlessandroFonseca
|
||||
; Licensed under the MIT license (see "license.txt").
|
||||
;*********************************************************************
|
||||
global printint
|
||||
|
||||
SYS_READ: equ 0
|
||||
SYS_WRITE: equ 1
|
||||
SYS_EXIT: equ 60
|
||||
|
||||
STDIN: equ 0
|
||||
STDOUT: equ 1
|
||||
|
||||
LINEFEED: equ 0x0A
|
||||
|
||||
section .text
|
||||
|
||||
;*********************************************************************
|
||||
; void exit(int64 code)
|
||||
;
|
||||
; Description:
|
||||
; Quit program
|
||||
;
|
||||
; Arguments:
|
||||
; rdi: int64 code: Exit code (0=Success, >0=Error)
|
||||
;
|
||||
; Returns:
|
||||
; This function does not return
|
||||
;
|
||||
;*********************************************************************
|
||||
exit:
|
||||
mov rax, SYS_EXIT ; rax: system call number
|
||||
syscall
|
||||
;*********************************************************************
|
||||
|
||||
;*********************************************************************
|
||||
; void exit0()
|
||||
;
|
||||
; Description:
|
||||
; Quit program with status code = 0
|
||||
;
|
||||
; Arguments:
|
||||
; None
|
||||
;
|
||||
; Returns:
|
||||
; This function does not return
|
||||
;
|
||||
;*********************************************************************
|
||||
exit0:
|
||||
xor rdi, rdi ; rdi = 0
|
||||
jmp exit ; TCO: tail call optimization
|
||||
;*********************************************************************
|
||||
|
||||
|
||||
;*********************************************************************
|
||||
; int64 strlen(char *s)
|
||||
;
|
||||
; Description:
|
||||
; Calculates the length of string ( excluding the terminating null)
|
||||
;
|
||||
; Arguments:
|
||||
; rdi: char *s: address of a null-terminated string (array of chars terminated by 0)
|
||||
;
|
||||
; Returns:
|
||||
; rax: int64: string size
|
||||
;
|
||||
;*********************************************************************
|
||||
strlen:
|
||||
xor rax, rax ; rax=0; // reset counter
|
||||
.loop: ; do{
|
||||
cmp byte [rdi], 0 ; if (*s==0); // If zero, skip loop
|
||||
je strlen.end ; break;
|
||||
inc rax ; rax++; // increment counter
|
||||
inc rdi ; s++; // advance to the next char
|
||||
jmp strlen.loop ; }while(true);
|
||||
.end:
|
||||
ret ; return rax;
|
||||
;*********************************************************************
|
||||
|
||||
|
||||
;*********************************************************************
|
||||
; void itoa(int64 value, char *s)
|
||||
;
|
||||
; Description:
|
||||
; Converts an integer to a null-terminated string.
|
||||
;
|
||||
; Arguments:
|
||||
; rdi: int64 value: Integer value to convert.
|
||||
; rsi: char *s: Memory address where to store the resulting string.
|
||||
;
|
||||
; Returns:
|
||||
; rax: int64: string size
|
||||
;
|
||||
;*********************************************************************
|
||||
itoa:
|
||||
test rdi, rdi ; value = rdi
|
||||
jz itoa.iszero ; value==0 has a direct solution
|
||||
jns itoa.notneg ; if(value <0 )
|
||||
mov byte [rsi], '-' ; *s = '-'
|
||||
neg rdi ; value = -value
|
||||
inc rsi ; s++
|
||||
.notneg:
|
||||
mov r9b, 1 ; bool leftzero=true
|
||||
mov r10, 10 ; base = 10
|
||||
mov rcx, 1000000000000000000 ; divisor = 1000000000000000000
|
||||
mov r8, 19 ; cont = 19 // Will repeat 19 times
|
||||
.loop: ; do{
|
||||
mov rax, rdi ; dividend[0..31] = value
|
||||
xor rdx, rdx ; dividend[32..63] = 0
|
||||
idiv rcx ; rax=(rdx:rax)/rcx ; rdx=(rdx:rax)%rcx
|
||||
test al, al ; digit = rax[0..7]
|
||||
jnz itoa.notdigit0 ; if(digit!=0)
|
||||
test r9b, r9b ; if(leftzero)
|
||||
jnz itoa.nextdigit ; continue
|
||||
jmp itoa.digit0
|
||||
.notdigit0:
|
||||
xor r9b, r9b ; leftzero = false
|
||||
.digit0:
|
||||
add eax, 48 ; digit = '0' + digit
|
||||
mov rdi, rdx ; value %= divisor
|
||||
mov byte [rsi], al ; *p = digit
|
||||
inc rsi ; p++
|
||||
.nextdigit:
|
||||
mov rax, rcx ; dividend[0..31] = value
|
||||
xor rdx, rdx ; dividend[32..63] = 0
|
||||
idiv r10 ; rax=(rdx:rax)/10 ; rdx=(rdx:rax)%10
|
||||
mov rcx, rax ; divisor /= 10
|
||||
dec r8 ; cont--
|
||||
jne itoa.loop ; }while(cont!=0)
|
||||
.end:
|
||||
mov byte [rsi], 0 ; *p = '\0'
|
||||
ret
|
||||
.iszero:
|
||||
mov word [rsi], 0x0030 ; *p = "0" (x86 is little endian)
|
||||
ret
|
||||
;*********************************************************************
|
||||
|
||||
|
||||
;*********************************************************************
|
||||
; int64 atoi(char *s)
|
||||
;
|
||||
; Description:
|
||||
; Convert string to integer.
|
||||
;
|
||||
; Arguments:
|
||||
; rdi: char *s: Address of a null-terminated string (array of chars terminated by 0)
|
||||
;
|
||||
; Returns:
|
||||
; rax: int64: integer value
|
||||
;*********************************************************************
|
||||
atoi:
|
||||
push r12 ; r12 is callee saved
|
||||
mov r12, rdi ; rdi is caller saved
|
||||
call strlen
|
||||
lea rdi, [r12+rax-1] ; char *p = &s[strlen(string)]; //scans string backward
|
||||
xor rax, rax ; result value
|
||||
mov rdx, 1 ; multiplier
|
||||
.beginloop:
|
||||
cmp rdi, r12 ; while(p>=s){
|
||||
jl atoi.end ;
|
||||
xor rcx, rcx ;
|
||||
mov cl, byte [rdi] ; cl = current char
|
||||
cmp cl, '-' ; if(cl=='-')
|
||||
jne atoi.notneg ;
|
||||
neg rax ; rax=-rax
|
||||
jmp atoi.end ;
|
||||
.notneg:
|
||||
cmp cl, '9' ; if(!isdigit(cl)) nextdigit
|
||||
jg atoi.endloop ;
|
||||
sub cl, '0' ;
|
||||
jl atoi.endloop ;
|
||||
imul rcx, rdx ; digit_value = current_char * multiplier
|
||||
add rax, rcx ; result += digit_value
|
||||
imul rdx, 10 ; multiplier *= 10
|
||||
.endloop:
|
||||
dec rdi ; previous char //scans string backward
|
||||
jmp atoi.beginloop ; }
|
||||
.end:
|
||||
pop r12 ; restore r12
|
||||
ret
|
||||
;*********************************************************************
|
||||
|
||||
|
||||
;*********************************************************************
|
||||
; void endl()
|
||||
;
|
||||
; Description:
|
||||
; Prints a newline (line break)
|
||||
;
|
||||
; Arguments:
|
||||
; None
|
||||
;
|
||||
; Returns:
|
||||
; Nothing
|
||||
;
|
||||
;*********************************************************************
|
||||
endl:
|
||||
lea rdi, [endl.str] ; print the string
|
||||
call printstr
|
||||
ret
|
||||
|
||||
;*********************************************************************
|
||||
|
||||
|
||||
;*********************************************************************
|
||||
; void printstr(char *s)
|
||||
;
|
||||
; Description:
|
||||
; Print a string
|
||||
;
|
||||
; Arguments:
|
||||
; rdi: char *s: address of a null-terminated string (array of chars terminated by 0)
|
||||
;
|
||||
; Returns:
|
||||
; Nothing
|
||||
;
|
||||
;*********************************************************************
|
||||
printstr:
|
||||
push r15 ; r15 is callee saved
|
||||
mov r15, rdi ; save copy (rdi should be caller saved)
|
||||
call strlen
|
||||
mov rdx, rax ; string size
|
||||
mov rsi, r15 ; string
|
||||
mov rax, SYS_WRITE ; system call number
|
||||
mov rdi, STDOUT ; file descriptor
|
||||
syscall ; system call
|
||||
pop r15
|
||||
ret
|
||||
;*********************************************************************
|
||||
|
||||
|
||||
;*********************************************************************
|
||||
; void printint(int64 n)
|
||||
;
|
||||
; Description:
|
||||
; Print integer number (decimal)
|
||||
;
|
||||
; Arguments:
|
||||
; rdi: int64 n: Value to print
|
||||
;
|
||||
; Returns:
|
||||
; Nothing
|
||||
;
|
||||
;*********************************************************************
|
||||
printint:
|
||||
sub rsp, 40 ; stack allocate a temp string
|
||||
mov rsi, rsp ; rdi=value, rsi=&str[0]
|
||||
call itoa
|
||||
mov rdi, rsp ; rdi=&str[0]
|
||||
call printstr ; print number
|
||||
add rsp, 40 ; deallocate the string
|
||||
ret
|
||||
;*********************************************************************
|
||||
|
||||
|
||||
;*********************************************************************
|
||||
; int64 readstr(char *s, int64 maxsize)
|
||||
;
|
||||
; Description:
|
||||
; Read up to *maxsize* chars from standard input into a string.
|
||||
;
|
||||
; Arguments:
|
||||
; rdi: char *s: address of a string (array of chars)
|
||||
; rsi: int64 maxsize: input size limit
|
||||
;
|
||||
; Returns:
|
||||
; rax: int64: Number of characters read
|
||||
;
|
||||
;*********************************************************************
|
||||
readstr:
|
||||
mov r8, rdi ; copy of buffer address
|
||||
mov rax, SYS_READ ; system call number
|
||||
mov rdx, rsi ; pointer to buffer
|
||||
mov rsi, rdi ; max size
|
||||
mov rdi, STDIN ; file descriptor
|
||||
syscall ; system call
|
||||
dec rax ; removing trailing newline char
|
||||
mov byte [r8+rax], 0 ; replace with '\0'
|
||||
ret
|
||||
;*********************************************************************
|
||||
|
||||
|
||||
;*********************************************************************
|
||||
; int64 readint()
|
||||
;
|
||||
; Description:
|
||||
; Read int64 from standard input
|
||||
;
|
||||
; Arguments:
|
||||
; None
|
||||
;
|
||||
; Returns:
|
||||
; rax: int64: The value entered
|
||||
;
|
||||
;*********************************************************************
|
||||
readint:
|
||||
sub rsp, 40 ; char s[40]
|
||||
mov rdi, rsp ; rdi = &s[0]
|
||||
mov rsi, 21 ; max input size
|
||||
call readstr ; read number as string
|
||||
mov rdi, rsp ;
|
||||
call atoi ; rax = atoi(s)
|
||||
add rsp, 40 ; deallocate s from stack
|
||||
ret
|
||||
;*********************************************************************
|
||||
|
||||
section .data
|
||||
endl.str: db LINEFEED, 0
|
||||
1
input/core/util.nub
Normal file
1
input/core/util.nub
Normal file
@@ -0,0 +1 @@
|
||||
extern func printint(val: int64);
|
||||
@@ -1,9 +1,10 @@
|
||||
import "core";
|
||||
|
||||
func main() {
|
||||
let i = 1;
|
||||
while i <= 10 {
|
||||
println("uwu");
|
||||
i = i + 1;
|
||||
}
|
||||
let x = new Array<String>(2);
|
||||
x[1] = "test1";
|
||||
x[2] = "test2";
|
||||
|
||||
println(x[1]);
|
||||
println(x[2]);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/bin/sh
|
||||
nasm -g -felf64 out.asm -o out.o
|
||||
nasm -g -felf64 ../input/core/strlen.asm -o strlen.o
|
||||
nasm -g -felf64 ../input/core/util.asm -o util.o
|
||||
|
||||
ld -o out strlen.o out.o
|
||||
ld -o out strlen.o util.o out.o
|
||||
|
||||
Reference in New Issue
Block a user