Implement branching
This commit is contained in:
parent
c8025ff723
commit
3f494cef6d
@ -4,34 +4,18 @@ using Mono.Cecil.Rocks;
|
|||||||
using Parser.Binding;
|
using Parser.Binding;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Parser.Emitting
|
namespace Parser.Emitting
|
||||||
{
|
{
|
||||||
public class MethodInterfaceDescription
|
|
||||||
{
|
|
||||||
public MethodInterfaceDescription(ImmutableArray<ParameterSymbol> inputDescription, ImmutableArray<ParameterSymbol> outputDescription, MethodDefinition method)
|
|
||||||
{
|
|
||||||
InputDescription = inputDescription;
|
|
||||||
OutputDescription = outputDescription;
|
|
||||||
Method = method;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ImmutableArray<ParameterSymbol> InputDescription { get; }
|
|
||||||
|
|
||||||
public ImmutableArray<ParameterSymbol> OutputDescription { get; }
|
|
||||||
|
|
||||||
public MethodDefinition Method { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Emitter
|
public class Emitter
|
||||||
{
|
{
|
||||||
private Dictionary<string, TypeReference> _knownTypes = new Dictionary<string, TypeReference>();
|
private Dictionary<string, TypeReference> _knownTypes = new Dictionary<string, TypeReference>();
|
||||||
private Dictionary<string, MethodInterfaceDescription> _functions = new Dictionary<string, MethodInterfaceDescription>();
|
private Dictionary<string, MethodInterfaceDescription> _functions = new Dictionary<string, MethodInterfaceDescription>();
|
||||||
private MethodReference? _consoleWriteLineReference;
|
private MethodReference? _consoleWriteLineReference;
|
||||||
private MethodReference? _dispReference;
|
private MethodReference? _dispReference;
|
||||||
|
private MethodReference? _mObjectToBool;
|
||||||
private MethodReference? _stringToMObject;
|
private MethodReference? _stringToMObject;
|
||||||
private MethodReference? _doubleToMObject;
|
private MethodReference? _doubleToMObject;
|
||||||
private MethodReference? _getItemFromDictionary;
|
private MethodReference? _getItemFromDictionary;
|
||||||
@ -44,6 +28,8 @@ namespace Parser.Emitting
|
|||||||
private MethodReference? _dictionaryCtorReference = null;
|
private MethodReference? _dictionaryCtorReference = null;
|
||||||
private Dictionary<BoundBinaryOperatorKind, MethodReference> _binaryOperations = new Dictionary<BoundBinaryOperatorKind, MethodReference>();
|
private Dictionary<BoundBinaryOperatorKind, MethodReference> _binaryOperations = new Dictionary<BoundBinaryOperatorKind, MethodReference>();
|
||||||
private Dictionary<BoundUnaryOperatorKind, MethodReference> _unaryOperations = new Dictionary<BoundUnaryOperatorKind, MethodReference>();
|
private Dictionary<BoundUnaryOperatorKind, MethodReference> _unaryOperations = new Dictionary<BoundUnaryOperatorKind, MethodReference>();
|
||||||
|
private Dictionary<BoundLabel, int> _labels = new Dictionary<BoundLabel, int>();
|
||||||
|
private Dictionary<int, BoundLabel> _forwardLabelsToFix = new Dictionary<int, BoundLabel>();
|
||||||
|
|
||||||
private static TypeReference ResolveAndImportType(
|
private static TypeReference ResolveAndImportType(
|
||||||
string typeName,
|
string typeName,
|
||||||
@ -206,6 +192,13 @@ namespace Parser.Emitting
|
|||||||
assemblies: assemblies,
|
assemblies: assemblies,
|
||||||
assemblyDefinition: assemblyDefinition);
|
assemblyDefinition: assemblyDefinition);
|
||||||
|
|
||||||
|
_mObjectToBool = ResolveAndImportMethod(
|
||||||
|
typeName: "Parser.MFunctions.MHelpers",
|
||||||
|
methodName: "ToBool",
|
||||||
|
parameterTypeNames: new[] { "Parser.Objects.MObject" },
|
||||||
|
assemblies: assemblies,
|
||||||
|
assemblyDefinition: assemblyDefinition);
|
||||||
|
|
||||||
_stringToMObject = ResolveAndImportMethod(
|
_stringToMObject = ResolveAndImportMethod(
|
||||||
typeName: "Parser.Objects.MObject",
|
typeName: "Parser.Objects.MObject",
|
||||||
methodName: "CreateCharArray",
|
methodName: "CreateCharArray",
|
||||||
@ -315,6 +308,9 @@ namespace Parser.Emitting
|
|||||||
{
|
{
|
||||||
var ilProcessor = methodDefinition.Body.GetILProcessor();
|
var ilProcessor = methodDefinition.Body.GetILProcessor();
|
||||||
|
|
||||||
|
_labels.Clear();
|
||||||
|
_forwardLabelsToFix.Clear();
|
||||||
|
|
||||||
// Local #0 is the dictionary with actual local variables.
|
// Local #0 is the dictionary with actual local variables.
|
||||||
_currentLocals = new VariableDefinition(_stringMObjectDictionary);
|
_currentLocals = new VariableDefinition(_stringMObjectDictionary);
|
||||||
ilProcessor.Body.Variables.Add(_currentLocals);
|
ilProcessor.Body.Variables.Add(_currentLocals);
|
||||||
@ -331,6 +327,7 @@ namespace Parser.Emitting
|
|||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// The following locals are "output variables".
|
// The following locals are "output variables".
|
||||||
_currentOutputVariables.Clear();
|
_currentOutputVariables.Clear();
|
||||||
if (function.OutputDescription.Length > 0)
|
if (function.OutputDescription.Length > 0)
|
||||||
@ -359,50 +356,89 @@ namespace Parser.Emitting
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var (index, target) in _forwardLabelsToFix)
|
||||||
|
{
|
||||||
|
var targetIndex = _labels[target];
|
||||||
|
ilProcessor.Body.Instructions[index].Operand = ilProcessor.Body.Instructions[targetIndex];
|
||||||
|
}
|
||||||
|
|
||||||
ilProcessor.Emit(OpCodes.Ret);
|
ilProcessor.Emit(OpCodes.Ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmitBlockStatement(BoundBlockStatement block, MethodDefinition methodDefinition)
|
private void EmitBlockStatement(BoundBlockStatement block, MethodDefinition methodDefinition)
|
||||||
{
|
{
|
||||||
var index = 0;
|
var ilProcessor = methodDefinition.Body.GetILProcessor();
|
||||||
while (index < block.Statements.Length)
|
foreach (var statement in block.Statements)
|
||||||
{
|
{
|
||||||
var statement = block.Statements[index];
|
|
||||||
switch (statement.Kind)
|
switch (statement.Kind)
|
||||||
{
|
{
|
||||||
case BoundNodeKind.GotoStatement:
|
case BoundNodeKind.GotoStatement:
|
||||||
throw new NotImplementedException("Gotos are not supported.");
|
EmitGoto((BoundGotoStatement)statement, ilProcessor);
|
||||||
|
break;
|
||||||
case BoundNodeKind.ConditionalGotoStatement:
|
case BoundNodeKind.ConditionalGotoStatement:
|
||||||
throw new NotImplementedException("Conditional gotos are not supported.");
|
EmitConditionalGoto((BoundConditionalGotoStatement)statement, ilProcessor);
|
||||||
|
break;
|
||||||
case BoundNodeKind.LabelStatement:
|
case BoundNodeKind.LabelStatement:
|
||||||
throw new NotImplementedException("Labels are not supported.");
|
EmitLabelStatement((BoundLabelStatement)statement, ilProcessor);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
EmitStatement(statement, methodDefinition);
|
EmitStatement(statement, ilProcessor);
|
||||||
index++;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmitStatement(BoundStatement node, MethodDefinition methodDefinition)
|
private void EmitLabelStatement(BoundLabelStatement node, ILProcessor ilProcessor)
|
||||||
|
{
|
||||||
|
_labels[node.Label] = ilProcessor.Body.Instructions.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitGoto(BoundGotoStatement node, ILProcessor ilProcessor)
|
||||||
|
{
|
||||||
|
if (_labels.TryGetValue(node.Label, out var target))
|
||||||
|
{
|
||||||
|
ilProcessor.Emit(OpCodes.Br, ilProcessor.Body.Instructions[target]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_forwardLabelsToFix.Add(ilProcessor.Body.Instructions.Count, node.Label);
|
||||||
|
ilProcessor.Emit(OpCodes.Br, Instruction.Create(OpCodes.Nop));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitConditionalGoto(BoundConditionalGotoStatement node, ILProcessor ilProcessor)
|
||||||
|
{
|
||||||
|
EmitExpression(node.Condition, ilProcessor);
|
||||||
|
ilProcessor.Emit(OpCodes.Call, _mObjectToBool);
|
||||||
|
var instruction = node.GotoIfTrue ? OpCodes.Brtrue : OpCodes.Brfalse;
|
||||||
|
if (_labels.TryGetValue(node.Label, out var target))
|
||||||
|
{
|
||||||
|
ilProcessor.Emit(instruction, ilProcessor.Body.Instructions[target]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_forwardLabelsToFix.Add(ilProcessor.Body.Instructions.Count, node.Label);
|
||||||
|
ilProcessor.Emit(instruction, Instruction.Create(OpCodes.Nop));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitStatement(BoundStatement node, ILProcessor ilProcessor)
|
||||||
{
|
{
|
||||||
switch (node.Kind)
|
switch (node.Kind)
|
||||||
{
|
{
|
||||||
case BoundNodeKind.EmptyStatement:
|
case BoundNodeKind.EmptyStatement:
|
||||||
break;
|
break;
|
||||||
case BoundNodeKind.ExpressionStatement:
|
case BoundNodeKind.ExpressionStatement:
|
||||||
EmitExpressionStatement((BoundExpressionStatement)node, methodDefinition);
|
EmitExpressionStatement((BoundExpressionStatement)node, ilProcessor);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new NotImplementedException($"Invalid statement kind '{node.Kind}'.");
|
throw new NotImplementedException($"Invalid statement kind '{node.Kind}'.");
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmitExpressionStatement(BoundExpressionStatement node, MethodDefinition methodDefinition)
|
private void EmitExpressionStatement(BoundExpressionStatement node, ILProcessor ilProcessor)
|
||||||
{
|
{
|
||||||
var ilProcessor = methodDefinition.Body.GetILProcessor();
|
EmitExpression(node.Expression, ilProcessor);
|
||||||
EmitExpression(node.Expression, methodDefinition);
|
|
||||||
if (node.DiscardResult)
|
if (node.DiscardResult)
|
||||||
{
|
{
|
||||||
ilProcessor.Emit(OpCodes.Pop);
|
ilProcessor.Emit(OpCodes.Pop);
|
||||||
@ -413,44 +449,42 @@ namespace Parser.Emitting
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmitExpression(BoundExpression node, MethodDefinition methodDefinition)
|
private void EmitExpression(BoundExpression node, ILProcessor ilProcessor)
|
||||||
{
|
{
|
||||||
switch (node.Kind) {
|
switch (node.Kind) {
|
||||||
case BoundNodeKind.AssignmentExpression:
|
case BoundNodeKind.AssignmentExpression:
|
||||||
EmitAssignmentExpression((BoundAssignmentExpression)node, methodDefinition);
|
EmitAssignmentExpression((BoundAssignmentExpression)node, ilProcessor);
|
||||||
break;
|
break;
|
||||||
case BoundNodeKind.BinaryOperationExpression:
|
case BoundNodeKind.BinaryOperationExpression:
|
||||||
EmitBinaryOperationExpression((BoundBinaryOperationExpression)node, methodDefinition);
|
EmitBinaryOperationExpression((BoundBinaryOperationExpression)node, ilProcessor);
|
||||||
break;
|
break;
|
||||||
case BoundNodeKind.FunctionCallExpression:
|
case BoundNodeKind.FunctionCallExpression:
|
||||||
EmitFunctionCallExpression((BoundFunctionCallExpression)node, methodDefinition);
|
EmitFunctionCallExpression((BoundFunctionCallExpression)node, ilProcessor);
|
||||||
break;
|
break;
|
||||||
case BoundNodeKind.IdentifierNameExpression:
|
case BoundNodeKind.IdentifierNameExpression:
|
||||||
EmitIdentifierNameExpression((BoundIdentifierNameExpression)node, methodDefinition);
|
EmitIdentifierNameExpression((BoundIdentifierNameExpression)node, ilProcessor);
|
||||||
break;
|
break;
|
||||||
case BoundNodeKind.NumberLiteralExpression:
|
case BoundNodeKind.NumberLiteralExpression:
|
||||||
EmitNumberLiteralExpression((BoundNumberLiteralExpression)node, methodDefinition);
|
EmitNumberLiteralExpression((BoundNumberLiteralExpression)node, ilProcessor);
|
||||||
break;
|
break;
|
||||||
case BoundNodeKind.StringLiteralExpression:
|
case BoundNodeKind.StringLiteralExpression:
|
||||||
EmitStringLiteralExpression((BoundStringLiteralExpression)node, methodDefinition);
|
EmitStringLiteralExpression((BoundStringLiteralExpression)node, ilProcessor);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new NotImplementedException($"Invalid node kind '{node.Kind}'.");
|
throw new NotImplementedException($"Invalid node kind '{node.Kind}'.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmitBinaryOperationExpression(BoundBinaryOperationExpression node, MethodDefinition methodDefinition)
|
private void EmitBinaryOperationExpression(BoundBinaryOperationExpression node, ILProcessor ilProcessor)
|
||||||
{
|
{
|
||||||
var ilProcessor = methodDefinition.Body.GetILProcessor();
|
|
||||||
var method = _binaryOperations[node.Op.Kind];
|
var method = _binaryOperations[node.Op.Kind];
|
||||||
EmitExpression(node.Left, methodDefinition);
|
EmitExpression(node.Left, ilProcessor);
|
||||||
EmitExpression(node.Right, methodDefinition);
|
EmitExpression(node.Right, ilProcessor);
|
||||||
ilProcessor.Emit(OpCodes.Call, method);
|
ilProcessor.Emit(OpCodes.Call, method);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmitAssignmentExpression(BoundAssignmentExpression node, MethodDefinition methodDefinition)
|
private void EmitAssignmentExpression(BoundAssignmentExpression node, ILProcessor ilProcessor)
|
||||||
{
|
{
|
||||||
var ilProcessor = methodDefinition.Body.GetILProcessor();
|
|
||||||
if (node.Left.Kind != BoundNodeKind.IdentifierNameExpression)
|
if (node.Left.Kind != BoundNodeKind.IdentifierNameExpression)
|
||||||
{
|
{
|
||||||
throw new Exception("Assignment to complex lvalues is not supported.");
|
throw new Exception("Assignment to complex lvalues is not supported.");
|
||||||
@ -458,42 +492,38 @@ namespace Parser.Emitting
|
|||||||
var left = ((BoundIdentifierNameExpression)node.Left);
|
var left = ((BoundIdentifierNameExpression)node.Left);
|
||||||
ilProcessor.Emit(OpCodes.Ldloc_0);
|
ilProcessor.Emit(OpCodes.Ldloc_0);
|
||||||
ilProcessor.Emit(OpCodes.Ldstr, left.Name);
|
ilProcessor.Emit(OpCodes.Ldstr, left.Name);
|
||||||
EmitExpression(node.Right, methodDefinition);
|
EmitExpression(node.Right, ilProcessor);
|
||||||
ilProcessor.Emit(OpCodes.Callvirt, _putItemIntoDictionary);
|
ilProcessor.Emit(OpCodes.Callvirt, _putItemIntoDictionary);
|
||||||
ilProcessor.Emit(OpCodes.Ldloc_0);
|
ilProcessor.Emit(OpCodes.Ldloc_0);
|
||||||
ilProcessor.Emit(OpCodes.Ldstr, left.Name);
|
ilProcessor.Emit(OpCodes.Ldstr, left.Name);
|
||||||
ilProcessor.Emit(OpCodes.Callvirt, _getItemFromDictionary);
|
ilProcessor.Emit(OpCodes.Callvirt, _getItemFromDictionary);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmitIdentifierNameExpression(BoundIdentifierNameExpression node, MethodDefinition methodDefinition)
|
private void EmitIdentifierNameExpression(BoundIdentifierNameExpression node, ILProcessor ilProcessor)
|
||||||
{
|
{
|
||||||
var ilProcessor = methodDefinition.Body.GetILProcessor();
|
|
||||||
ilProcessor.Emit(OpCodes.Ldloc_0);
|
ilProcessor.Emit(OpCodes.Ldloc_0);
|
||||||
ilProcessor.Emit(OpCodes.Ldstr, node.Name);
|
ilProcessor.Emit(OpCodes.Ldstr, node.Name);
|
||||||
ilProcessor.Emit(OpCodes.Callvirt, _getItemFromDictionary);
|
ilProcessor.Emit(OpCodes.Callvirt, _getItemFromDictionary);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmitNumberLiteralExpression(BoundNumberLiteralExpression node, MethodDefinition methodDefinition)
|
private void EmitNumberLiteralExpression(BoundNumberLiteralExpression node, ILProcessor ilProcessor)
|
||||||
{
|
{
|
||||||
var ilProcessor = methodDefinition.Body.GetILProcessor();
|
|
||||||
ilProcessor.Emit(OpCodes.Ldc_R8, node.Value);
|
ilProcessor.Emit(OpCodes.Ldc_R8, node.Value);
|
||||||
ilProcessor.Emit(OpCodes.Call, _doubleToMObject);
|
ilProcessor.Emit(OpCodes.Call, _doubleToMObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmitStringLiteralExpression(BoundStringLiteralExpression node, MethodDefinition methodDefinition)
|
private void EmitStringLiteralExpression(BoundStringLiteralExpression node, ILProcessor ilProcessor)
|
||||||
{
|
{
|
||||||
var ilProcessor = methodDefinition.Body.GetILProcessor();
|
|
||||||
ilProcessor.Emit(OpCodes.Ldstr, node.Value);
|
ilProcessor.Emit(OpCodes.Ldstr, node.Value);
|
||||||
ilProcessor.Emit(OpCodes.Call, _stringToMObject);
|
ilProcessor.Emit(OpCodes.Call, _stringToMObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmitFunctionCallExpression(BoundFunctionCallExpression node, MethodDefinition methodDefinition)
|
private void EmitFunctionCallExpression(BoundFunctionCallExpression node, ILProcessor ilProcessor)
|
||||||
{
|
{
|
||||||
var ilProcessor = methodDefinition.Body.GetILProcessor();
|
|
||||||
if (node.Name.Kind == BoundNodeKind.IdentifierNameExpression
|
if (node.Name.Kind == BoundNodeKind.IdentifierNameExpression
|
||||||
&& ((BoundIdentifierNameExpression)node.Name).Name == "disp")
|
&& ((BoundIdentifierNameExpression)node.Name).Name == "disp")
|
||||||
{
|
{
|
||||||
EmitExpression(node.Arguments[0], methodDefinition);
|
EmitExpression(node.Arguments[0], ilProcessor);
|
||||||
ilProcessor.Emit(OpCodes.Call, _dispReference);
|
ilProcessor.Emit(OpCodes.Call, _dispReference);
|
||||||
ilProcessor.Emit(OpCodes.Ldnull);
|
ilProcessor.Emit(OpCodes.Ldnull);
|
||||||
}
|
}
|
||||||
@ -504,7 +534,7 @@ namespace Parser.Emitting
|
|||||||
{
|
{
|
||||||
if (i < node.Arguments.Length)
|
if (i < node.Arguments.Length)
|
||||||
{
|
{
|
||||||
EmitExpression(node.Arguments[i], methodDefinition);
|
EmitExpression(node.Arguments[i], ilProcessor);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
22
Parser/Emitting/MethodInterfaceDescription.cs
Normal file
22
Parser/Emitting/MethodInterfaceDescription.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using Mono.Cecil;
|
||||||
|
using Parser.Binding;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
|
||||||
|
namespace Parser.Emitting
|
||||||
|
{
|
||||||
|
public class MethodInterfaceDescription
|
||||||
|
{
|
||||||
|
public MethodInterfaceDescription(ImmutableArray<ParameterSymbol> inputDescription, ImmutableArray<ParameterSymbol> outputDescription, MethodDefinition method)
|
||||||
|
{
|
||||||
|
InputDescription = inputDescription;
|
||||||
|
OutputDescription = outputDescription;
|
||||||
|
Method = method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImmutableArray<ParameterSymbol> InputDescription { get; }
|
||||||
|
|
||||||
|
public ImmutableArray<ParameterSymbol> OutputDescription { get; }
|
||||||
|
|
||||||
|
public MethodDefinition Method { get; }
|
||||||
|
}
|
||||||
|
}
|
@ -12,5 +12,16 @@ namespace Parser.MFunctions
|
|||||||
Console.WriteLine(obj);
|
Console.WriteLine(obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool ToBool(MObject operand)
|
||||||
|
{
|
||||||
|
return operand switch
|
||||||
|
{
|
||||||
|
MDoubleNumber { Value: var value } => value != 0.0,
|
||||||
|
MLogical { Value: var value } => value,
|
||||||
|
MCharArray { Chars: var value } => value.Length > 0,
|
||||||
|
_ => throw new System.Exception($"Unknown MObject type {operand.GetType()}"),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,21 @@
|
|||||||
x = 2;
|
x = 2;
|
||||||
f(x);
|
f(x);
|
||||||
|
x = 5;
|
||||||
|
f(x);
|
||||||
|
x = 3;
|
||||||
f(x);
|
f(x);
|
||||||
|
|
||||||
function f(x)
|
function f(x)
|
||||||
disp('X was');
|
disp('X was');
|
||||||
disp(x);
|
disp(x);
|
||||||
|
if x > 3
|
||||||
|
disp('greater than 3!');
|
||||||
|
elseif x < 3
|
||||||
|
disp('less than 3!');
|
||||||
|
else
|
||||||
|
disp('exactly 3!');
|
||||||
|
end
|
||||||
x = x + 1;
|
x = x + 1;
|
||||||
disp('X is');
|
disp('X + 1 is');
|
||||||
disp(x);
|
disp(x);
|
||||||
end
|
end
|
Loading…
x
Reference in New Issue
Block a user