Is align instruction necessary in LLVM IR code? - clang

When using clang++ to generate IR code, it will contain align x instruction, and the memory of variables and struct is aligned. Such as:
struct CT {
char c1;
bool b1;
int i1;
double d1; // 8
char c2;
int i2;
};
int main() {
char c1 = 'a';
int i1 = 2;
char c2 = 'b';
char c3 = 'c';
int i2 = 4;
printf("address of c1 = %p ;\n", &c1);
printf("address of i1 = %p ;\n", &i1);
printf("address of c2 = %p ;\n", &c2);
printf("address of c3 = %p ;\n", &c3);
printf("address of i2 = %p ;\n", &i2);
return 0;
}
It will generate IR code (with align instructions):
source_filename = "oper.cpp"
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.15.0"
#.str = private unnamed_addr constant [22 x i8] c"address of c1 = %p ;\0A\00", align 1
#.str.1 = private unnamed_addr constant [22 x i8] c"address of i1 = %p ;\0A\00", align 1
#.str.2 = private unnamed_addr constant [22 x i8] c"address of c2 = %p ;\0A\00", align 1
#.str.3 = private unnamed_addr constant [22 x i8] c"address of c3 = %p ;\0A\00", align 1
#.str.4 = private unnamed_addr constant [22 x i8] c"address of i2 = %p ;\0A\00", align 1
; Function Attrs: noinline norecurse optnone ssp uwtable
define i32 #main() #0 {
%1 = alloca i32, align 4
%2 = alloca i8, align 1
%3 = alloca i32, align 4
%4 = alloca i8, align 1
%5 = alloca i8, align 1
%6 = alloca i32, align 4
store i32 0, i32* %1, align 4
store i8 97, i8* %2, align 1
store i32 2, i32* %3, align 4
store i8 98, i8* %4, align 1
store i8 99, i8* %5, align 1
store i32 4, i32* %6, align 4
%7 = call i32 (i8*, ...) #printf(i8* getelementptr inbounds ([22 x i8], [22 x i8]* #.str, i64 0, i64 0), i8* %2)
%8 = call i32 (i8*, ...) #printf(i8* getelementptr inbounds ([22 x i8], [22 x i8]* #.str.1, i64 0, i64 0), i32* %3)
%9 = call i32 (i8*, ...) #printf(i8* getelementptr inbounds ([22 x i8], [22 x i8]* #.str.2, i64 0, i64 0), i8* %4)
%10 = call i32 (i8*, ...) #printf(i8* getelementptr inbounds ([22 x i8], [22 x i8]* #.str.3, i64 0, i64 0), i8* %5)
%11 = call i32 (i8*, ...) #printf(i8* getelementptr inbounds ([22 x i8], [22 x i8]* #.str.4, i64 0, i64 0), i32* %6)
ret i32 0
}
declare i32 #printf(i8*, ...) #1
This will output:
address of c1 = 0x7ffee900328b ;
address of i1 = 0x7ffee9003284 ;
address of c2 = 0x7ffee9003283 ;
address of c3 = 0x7ffee9003282 ;
address of i2 = 0x7ffee900327c ;
We can see that the memory of variables is aligned.
But if you delete the align instruction of IR code, it will run correctly too, and the memory of variables is also aligned. Such as below IR code:
source_filename = "oper.cpp"
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.15.0"
#.str = private unnamed_addr constant [22 x i8] c"address of c1 = %p ;\0A\00"
#.str.1 = private unnamed_addr constant [22 x i8] c"address of i1 = %p ;\0A\00"
#.str.2 = private unnamed_addr constant [22 x i8] c"address of c2 = %p ;\0A\00"
#.str.3 = private unnamed_addr constant [22 x i8] c"address of c3 = %p ;\0A\00"
#.str.4 = private unnamed_addr constant [22 x i8] c"address of i2 = %p ;\0A\00"
; Function Attrs: noinline norecurse optnone ssp uwtable
define i32 #main() #0 {
%1 = alloca i32
%2 = alloca i8
%3 = alloca i32
%4 = alloca i8
%5 = alloca i8
%6 = alloca i32
store i32 0, i32* %1
store i8 97, i8* %2
store i32 2, i32* %3
store i8 98, i8* %4
store i8 99, i8* %5
store i32 4, i32* %6
%7 = call i32 (i8*, ...) #printf(i8* getelementptr inbounds ([22 x i8], [22 x i8]* #.str, i64 0, i64 0), i8* %2)
%8 = call i32 (i8*, ...) #printf(i8* getelementptr inbounds ([22 x i8], [22 x i8]* #.str.1, i64 0, i64 0), i32* %3)
%9 = call i32 (i8*, ...) #printf(i8* getelementptr inbounds ([22 x i8], [22 x i8]* #.str.2, i64 0, i64 0), i8* %4)
%10 = call i32 (i8*, ...) #printf(i8* getelementptr inbounds ([22 x i8], [22 x i8]* #.str.3, i64 0, i64 0), i8* %5)
%11 = call i32 (i8*, ...) #printf(i8* getelementptr inbounds ([22 x i8], [22 x i8]* #.str.4, i64 0, i64 0), i32* %6)
ret i32 0
}
declare i32 #printf(i8*, ...) #1
This will also output the aligned address of variables, no matter you use clang command or LLJIT(Tool's API of LLVM).
My Question:
We could not add align instruction to IR code? LLVM JIT will add it automatically?

Related

Fortran subroutine NaN issue when multiple outputs are assigned to the same variable in the main program

I tend to use temporary variables to "ignore" some subroutine outputs in Fortran. Since Fortran doesn't have a command like tilde (~) in Matlab, I have to get the outputs fron the subroutine but I assign them to the same temporary variable with the right size. It has been my preference to make things look cleaner, no practical purposes.
So far for years I had no problems with it; today, I am having issues. It turns out, when I assign the outputs to the same variable (temp1), C_DU is a matrix with all zero although it shouldn't be so.
My question is, is it bad practive to assign multiple subroutine outputs to the same variable in the main code? Why is everything suddenly becoming zero when I do that? I appreciate any help.
Below is a minimum working example:
program example
implicit none
real(kind=8) :: temp1(3,3)
real(kind=8) :: temp2(3,3)
real(kind=8) :: temp3(3,3)
real(kind=8) :: temp4(3,3)
real(kind=8) :: temp5(3,3)
real(kind=8) :: r_PN_U(3)
call r_calc(4.2d0, &
0d0, 0d0, &
0d0, 0d0, &
0d0, 0d0, &
0d0, &
0d0, 0d0, &
0d0, &
0d0, 0d0, &
0d0, 0d0, &
r_PN_U, &
temp1, temp1, temp1, temp1, temp1)
call r_calc(4.2d0, &
0d0, 0d0, &
0d0, 0d0, &
0d0, 0d0, &
0d0, &
0d0, 0d0, &
0d0, &
0d0, 0d0, &
0d0, 0d0, &
r_PN_U, &
temp1, temp2, temp3, temp4, temp5)
end program example
subroutine r_calc(rin, &
e, ed, &
f, fd, &
v, vd, &
vp, &
w, wd, &
wp, &
theta, thetad, &
y_pos, z_pos, &
r_PN_U, &
C_DU_theta, C_DU_beta, C_DU_zeta, C_DU, C_UD)
implicit none
real(kind=8), intent(in) :: rin
real(kind=8), intent(in) :: e, ed
real(kind=8), intent(in) :: f, fd
real(kind=8), intent(in) :: v, vd
real(kind=8), intent(in) :: vp
real(kind=8), intent(in) :: w, wd
real(kind=8), intent(in) :: wp
real(kind=8), intent(in) :: theta, thetad
real(kind=8), intent(in) :: y_pos, z_pos
real(kind=8), intent(out) :: r_PN_U(3)
real(kind=8), intent(out) :: C_DU_theta(3,3)
real(kind=8), intent(out) :: C_DU_beta (3,3)
real(kind=8), intent(out) :: C_DU_zeta (3,3)
real(kind=8), intent(out) :: C_DU (3,3)
real(kind=8), intent(out) :: C_UD (3,3)
real(kind=8) :: beta, zeta
beta = -atan(wp) ! [rad], flap down angle
zeta = atan(vp) ! [rad], lead angle
call angle2dcm(theta, beta, zeta, C_DU_theta, C_DU_beta, C_DU_zeta, C_DU)
print *, C_DU ! gives all zero in the first call, correct values in the second call
C_UD = transpose(C_DU)
r_PN_U = [rin+e+f, v, w] + matmul(C_UD, [0d0, y_pos, z_pos])
end subroutine r_calc
subroutine angle2dcm(phi, theta, psi, C_phi, C_theta, C_psi, C_out)
implicit none
! Calculates the direction cosine matrix in psi - theta - phi (3 - 2 - 1) order
! Difference from "angle2dcm" subroutine is the extra outputs
real(kind=8), intent(in) :: phi, theta, psi
real(kind=8), intent(out) :: C_psi(3,3), C_theta(3,3), C_phi(3,3), C_out(3,3)
C_phi(1,1:3) = [1d0, 0d0, 0d0]
C_phi(2,1:3) = [0d0, cos(phi), sin(phi)]
C_phi(3,1:3) = [0d0, -sin(phi), cos(phi)]
C_theta(1,1:3) = [cos(theta), 0d0, -sin(theta)]
C_theta(2,1:3) = [ 0d0, 1d0, 0d0]
C_theta(3,1:3) = [sin(theta), 0d0, cos(theta)]
C_psi(1,1:3) = [ cos(psi), sin(psi), 0d0]
C_psi(2,1:3) = [-sin(psi), cos(psi), 0d0]
C_psi(3,1:3) = [ 0d0, 0d0, 1d0]
C_out = matmul(C_phi, matmul(C_theta,C_psi)) ! psi - theta - phi (3 - 2 - 1) order
end subroutine angle2dcm
It is illegal to assign the same variable as multiple actual arguments that may be changed in the subroutine. It is called aliasing and is forbidden in Fortran. Because your code is not standard conforming, the output can be anything.
Use different variables for each argument.

Erlang records printing

I am writing a program in erlang and I created this record:
-record(tree, {node, left, right}).
I want to print a list of different trees, and this is how prints it:
[{tree,x1,{x3,0,1},{tree,x2,1,{x3,0,1}}}, {tree,x1,{tree,x3,0,1},{tree,x3,{x2,1,0},1}}]
Is there an easy to print it without the word "tree"? (the name of the record).
Sure I can just define it as a tuple and not a record, but I want to try to work with a record so the code will be more organized.
Yes, there is. Inside shell you can use:
Eshell V9.1 (abort with ^G)
1> Trees = [
{tree, x1, {x3, 0, 1}, {tree, x2, 1, {x3, 0, 1}}},
{tree, x1, {tree, x3, 0, 1}, {tree, x3, {x2, 1, 0}, 1}}
].
[{tree,x1,{x3,0,1},{tree,x2,1,{x3,0,1}}},{tree,x1,{tree,x3,0,1},{tree,x3,{x2,1,0},1}}]
2> Format = fun({tree, Node, Left, Right}, F) ->
{
Node,
if
element(1, Left) == tree -> F(Left, F);
true -> Left
end,
if
element(1, Right) == tree -> F(Right, F);
true -> Right
end
}
end.
#Fun<erl_eval.12.99386804>
3> [Format(X, Format) || X <- Trees].
[
{{x3, 0, 1}, {1, {x3, 0, 1}}},
{{0, 1}, {{x2, 1, 0}, 1}}
]
And in your module you can place for example a format/1 function:
-module(tree).
-record(tree, {node, left, right}).
-export([format/1]).
format(#tree{node = Node, left = L, right = R}) ->
{Node, maybe_format(L), maybe_format(R)};
format([#tree{}=Tree | Trees]) ->
[format(Tree) | format(Trees)];
format([]) ->
[].
maybe_format(X) when erlang:is_record(X, tree) ->
format(X);
maybe_format(X) ->
X.
And use it in shell or wherever you want:
Eshell V9.1 (abort with ^G)
% Compile my module which is inside current directory:
1> c(tree).
{ok,tree}
% format single tree:
2> tree:format({tree, node, left, right}).
{node,left,right}
% format list of trees:
3> tree:format([{tree,x1,{x3,0,1},{tree,x2,1,{x3,0,1}}}, {tree,x1,{tree,x3,0,1},{tree,x3,{x2,1,0},1}}]).
[
{x1, {x3, 0, 1}, {x2, 1, {x3, 0, 1}}},
{x1, {x3, 0, 1}, {x3, {x2, 1, 0}, 1}}
]

Recurrence relation solution for relations with two interdependent variables

I came across the following problem in an online challenge.
Consider the following vectors:
x = [3, 4, ...]
y = [2, 3, ...]
Such that for i >= 2:
x[i] = x[i-1] + 3 * y[i-2]
y[i] = 2 * y[i-1] + 2 * x[i-2]
What is x[10^15] ?
While the problem has a very straightforward solution, the problem is the 10^15 value which cannot be calculated in a small time. Only thing I can think of is that we have to derive a polynomial from the recurrence relation - However this isn't easy to do. Am I missing something?
The problem statement can be express as matrix multiplication as follows:
A= [
[1, 0, 0, 3],
[1, 0, 0, 0],
[0, 2, 2, 0],
[0, 0, 1, 0]
]
[xn+1, xn, yn+1, yn] = A*[xn, xn-1, yn, yn-1]
=> [xn+1, xn, yn+1, yn] = A^(n-1) * [x1, x0, y1, y0]
[x1, x0, y1, y0] = [4, 3, 3, 2]
While not mentioned in the problem, since the matrix multiplication exceeds integer limits, the solution needs to be expressed in as remainder of some prime number. Let the prime number be 1000000007. But how can we not exceed the integer limits while multiplying? Consider the following:
(X * Y) mod p = ((X mod p) * (Y mod p)) mod p
Now, X = A^n
Let, A^n mod p = B
Now, B = B mod p
So,
(X * Y) mod p =
((X mod p) * (Y mod p)) mod p
=> ((A^n mod p) * (Y mod p)) mod p
=> ( B * (Y mod p)) mod p
=> ((B mod p) * (Y mod p)) mod p
=> (B * Y) mod p
So a simple python implementation would be:
import numpy as np
p = 1000000007
A= np.array([
[1, 0, 0, 3],
[1, 0, 0, 0],
[0, 2, 2, 0],
[0, 0, 1, 0]
])
Y = np.array([4, 3, 3, 2])
# We will use binary exponentiation for fast matrix multiplication
# See: https://cp-algorithms.com/algebra/binary-exp.html
# The `power` list is the array of A's powers needed for that
powers = []
powers.append(A % p)
for i in range(1, 50): # Till 50 since 10^15 ~= 2^50
Ap = powers[i - 1]
powers.append(Ap.dot(Ap) % p)
def solve(n):
pow_of_a = n - 3
index = 0
prod = np.identity(4)
while (pow_of_a > 0):
if (pow_of_a & 1) == 1:
prod = prod.dot(powers[index])
pow_of_a >>= 1
index += 1
B = prod % p
print(B.dot(Y) % p)

Clang takes very long time to compile LLVM IR large arrays

I am trying to compile LLVM IR code that contains a few large arrays (400 elements). When I try to compile this with clang (not run, just compile) - it takes longer than 10 minutes.
IR Code
define i32 #main() {
%j = alloca double
%i = alloca double
%foo = alloca [400 x double]
%B = alloca [400 x [400 x double]]
%A = alloca [400 x [400 x double]]
%1 = insertvalue [400 x double] undef, double 0.000000e+00, 0
%2 = insertvalue [400 x [400 x double]] undef, [400 x double] %1, 0
store [400 x [400 x double]] %2, [400 x [400 x double]]* %A
%3 = insertvalue [400 x double] undef, double 0.000000e+00, 0
%4 = insertvalue [400 x double] undef, double 0.000000e+00, 0
%5 = insertvalue [400 x [400 x double]] undef, [400 x double] %4, 0
store [400 x [400 x double]] %5, [400 x [400 x double]]* %B
%6 = insertvalue [400 x double] undef, double 0.000000e+00, 0
store [400 x double] %6, [400 x double]* %foo
store double 0.000000e+00, double* %i
ret i32 0
}
Command to run: clang out.ll -o built
Edit
I think this has to do with clang trying to create the arrays or something. As I make bigger arrays, clang builds take longer but, running the programs takes about the same amount of time. It does not really make sense to me why this would happen but, it does appear to be what is happening.
Versions
LLVM: Apple LLVM version 9.0.0 (clang-900.0.39.2)
Clang: clang version 6.0.0 (tags/RELEASE_600/final)
(added from comments)
How do I make this take less time? ... It seems weird that it would take this long. I know there is a way to make it take less time because, for example, C is able to make arrays that big and it will compile in no time.
Edit 2
I tried implementing malloc in order to have the arrays allocated on the heap instead of the stack. Here is some new IR Code. My question is where is this being allocated? When I generate multidimensional arrays it is still really slow - in that case how would I speed it up again?
%foo = alloca [400 x [400 x double]]
%calltmp1 = call i8* #malloc(i64 10240000)
%4 = bitcast i8* %calltmp1 to [400 x [400 x double]]*
%5 = getelementptr [400 x [400 x double]], [400 x [400 x double]]* %4, i32 0, i32 0
%calltmp2 = call i8* #malloc(i64 25600)
%6 = bitcast i8* %calltmp2 to [400 x double]*
%7 = getelementptr [400 x double], [400 x double]* %6, i32 0, i32 0
store double 1.000000e+00, double* %7
%8 = getelementptr [400 x double], [400 x double]* %6, i32 0, i32 1
store double 1.000000e+00, double* %8
%9 = getelementptr [400 x double], [400 x double]* %6, i32 0, i32 1
store double 1.000000e+00, double* %9
%initialized_array3 = load [400 x double], [400 x double]* %6
store [400 x double] %initialized_array3, [400 x double]* %5
%initialized_array4 = load [400 x [400 x double]], [400 x [400 x double]]* %4
store [400 x [400 x double]] %initialized_array4, [400 x [400 x double]]* %foo
Edit 3
Sorry for all the edits but, I think the extra info is helpful.
Here is some more IR Code I generated:
%foo = alloca [400 x [400 x double]]
store [400 x [400 x double]] undef, [400 x [400 x double]]* %foo
%0 = getelementptr [400 x [400 x double]], [400 x [400 x double]]* %foo, i32 0, i32 0
%1 = getelementptr [400 x double], [400 x double]* %0, i32 0, i32 0
store double 1.598000e+03, double* %1
This is almost identical to this IR Code generated form c:
%1 = alloca [400 x [400 x i32]], align 16
%2 = alloca i32*, align 8
%3 = getelementptr inbounds [400 x [400 x i32]], [400 x [400 x i32]]* %1, i64 0, i64 0
%4 = getelementptr inbounds [400 x i32], [400 x i32]* %3, i64 0, i64 0
store i32 1, i32* %4, align 16
However, the c code compiles in less than a second and mine takes too long to even be able to tell. This is because of line 2 in the first code snippet (below for reference). Why does that cause clang to run so slowly?
Line slowing it down:
store [400 x [400 x double]] undef, [400 x [400 x double]]* %foo

FParsec only parses expr between parentheses

I am coding a parser (for learning pourpuses).
I want it to parse constructions like
let myVar be 40 plus 2
and
let myVar be (40 plus 2)
With no problems... but my parser does not "understand" the former. It sees the 40 and thinks "well, it's a Literal Numeric 40".
When I put parentheses, my parser works great.
I am having a hard time to understand why.
Parser:
type value =
| Boolean of bool
| Numeric of float
| String of string
type arithmetic = Sum | Sub | Mul | Div | Pow
type logic = And | Or | Equal | NotEqual | Greater | Smaller
type identifier =
| Identifier of string
type expression =
| Literal of value
| Arithmetic of expression * arithmetic * expression
| Negative of expression
| Negation of expression
| Logic of expression * logic * expression
| Variable of identifier
type statement =
| Assignment of identifier * expression
| Print of expression
| Read of identifier
let private ws = spaces
let private str s = pstring s .>> ws
let private pnumeric =
pfloat
.>> ws
|>> fun n -> Literal (Numeric n)
let private pboolean =
choice [
(stringReturn "true" (Literal (Boolean true)))
(stringReturn "false" (Literal (Boolean false)))
]
.>> ws
let private pstringliteral =
choice [
between (pstring "\"") (pstring "\"") (manyChars (satisfy (fun c -> c <> '"')))
between (pstring "'") (pstring "'") (manyChars (satisfy (fun c -> c <> ''')))
]
|>> fun s -> Literal (String s)
let private pidentifier =
many1Satisfy2L isLetter (fun c -> isLetter c || isDigit c) "identifier"
|>> fun s -> Identifier s
let private betweenParentheses p =
between (str "(") (str ")") p
let private pvalue =
choice [
pnumeric
pboolean
]
let private prefixOperator (p: OperatorPrecedenceParser<_,_,_>) op prec map =
p.AddOperator(PrefixOperator (op, ws, prec, true, map))
let private infixOperator (p: OperatorPrecedenceParser<_,_,_>) op prec map =
p.AddOperator(InfixOperator (op, ws, prec, Associativity.Left, map))
let private oppNegation = new OperatorPrecedenceParser<_,_,_>()
let private oppLogic = new OperatorPrecedenceParser<_,_,_>()
let private oppArithmetic = new OperatorPrecedenceParser<_,_,_>()
let private oppNegative = new OperatorPrecedenceParser<_,_,_>()
prefixOperator oppNegation "not" 1 (fun x -> Negation x)
infixOperator oppLogic "is" 1 (fun x y -> Logic (x, Equal, y))
infixOperator oppLogic "isnt" 1 (fun x y -> Logic (x, NotEqual, y))
infixOperator oppLogic "and" 2 (fun x y -> Logic (x, And, y))
infixOperator oppLogic "or" 3 (fun x y -> Logic (x, Or, y))
prefixOperator oppNegative "-" 1 (fun x -> Negative x)
infixOperator oppArithmetic ">" 1 (fun x y -> Logic (x, Greater, y))
infixOperator oppArithmetic "<" 1 (fun x y -> Logic (x, Smaller, y))
infixOperator oppArithmetic "is" 2 (fun x y -> Logic (x, Equal, y))
infixOperator oppArithmetic "isnt" 2 (fun x y -> Logic (x, NotEqual, y))
infixOperator oppArithmetic "plus" 3 (fun x y -> Arithmetic (x, Sum, y))
infixOperator oppArithmetic "minus" 3 (fun x y -> Arithmetic (x, Sub, y))
infixOperator oppArithmetic "times" 4 (fun x y -> Arithmetic (x, Mul, y))
infixOperator oppArithmetic "divided by" 4 (fun x y -> Arithmetic (x, Div, y))
infixOperator oppArithmetic "power" 5 (fun x y -> Arithmetic (x, Pow, y))
let private negationExprParser = oppNegation.ExpressionParser
let private logicExprParser = oppLogic.ExpressionParser
let private arithmeticExprParser = oppArithmetic.ExpressionParser
let private negativeExprParser = oppNegative.ExpressionParser
oppNegation.TermParser <- choice [
betweenParentheses negationExprParser
pboolean
]
oppLogic.TermParser <- choice [
betweenParentheses logicExprParser
pboolean
]
oppNegative.TermParser <- choice [
betweenParentheses negativeExprParser
pnumeric
]
oppArithmetic.TermParser <- choice [
betweenParentheses arithmeticExprParser
pnumeric
]
let private pexpression =
choice [
attempt <| pstringliteral
attempt <| negationExprParser
attempt <| logicExprParser
attempt <| negativeExprParser
attempt <| arithmeticExprParser
attempt <| (pidentifier |>> fun id -> Variable id)
]
let private passignment =
pipe2 (str "let" .>> ws >>. pidentifier) (ws >>. str "be" >>. ws >>. pexpression) (fun id exp -> Assignment (id, exp))
let private pprint =
str "print"
>>. pexpression
|>> fun exp -> Print exp
let private pread =
str "read"
>>. pidentifier
|>> fun id -> Read id
let private pstatement =
choice [
passignment
pprint
pread
]
let private pline =
skipMany (satisfy (fun c -> c = '\n' || c = ' '))
>>. pstatement
.>> ws
let private pcode =
many pline
let generateAST code =
match run pcode code with
| Success (ast, _, _) -> sprintf "%A" ast
| Failure (msg, _, _) -> msg
Usage:
[<EntryPoint>]
let main argv =
printfn "%s\n" (generateAST "let b be 5 plus 7")
// [Assignment (Identifier "b",Literal (Numeric 5.0))]
printfn "%s\n" (generateAST "let b be (5 plus 7)")
// [Assignment
// (Identifier "b",Arithmetic (Literal (Numeric 5.0),Sum,Literal (Numeric 7.0)))]
0
Take a look at FParsec - Tracing a parser
If you add the recommended FParsec tracing function to the top of your code
let (<!>) (p: Parser<_,_>) label : Parser<_,_> =
fun stream ->
printfn "%A: Entering %s" stream.Position label
let reply = p stream
printfn "%A: Leaving %s (%A)" stream.Position label reply.Status
reply
then modify the parsers to use the trace function
let private pnumeric =
(pfloat
.>> ws
|>> fun n -> Literal (Numeric n)) <!> "pnumeric"
let private pboolean =
(choice [
(stringReturn "true" (Literal (Boolean true)))
(stringReturn "false" (Literal (Boolean false)))
]
.>> ws) <!> "pboolean"
let private pstringliteral =
(choice [
between (pstring "\"") (pstring "\"") (manyChars (satisfy (fun c -> c <> '"')))
between (pstring "'") (pstring "'") (manyChars (satisfy (fun c -> c <> ''')))
]
|>> fun s -> Literal (String s)) <!> "pstringliteral"
let private pidentifier =
(many1Satisfy2L isLetter (fun c -> isLetter c || isDigit c) "identifier"
|>> fun s -> Identifier s) <!> "pidentifier"
let private betweenParentheses p =
(between (str "(") (str ")") p) <!> "betweenParentheses"
let private pvalue =
(choice [
pnumeric
pboolean
]) <!> "pvalue"
let private negationExprParser = oppNegation.ExpressionParser <!> "negationExprParser"
let private logicExprParser = oppLogic.ExpressionParser <!> "logicExprParser"
let private arithmeticExprParser = oppArithmetic.ExpressionParser <!> "arithmeticExprParser"
let private negativeExprParser = oppNegative.ExpressionParser <!> "negativeExprParser "
let private pexpression =
choice [
attempt <| pstringliteral
attempt <| negationExprParser
attempt <| logicExprParser
attempt <| negativeExprParser
attempt <| arithmeticExprParser
attempt <| (pidentifier |>> fun id -> Variable id)
] <!> "pexpression"
let private passignment =
pipe2 (str "let" .>> ws >>. pidentifier) (ws >>. str "be" >>. ws >>. pexpression) (fun id exp -> Assignment (id, exp)) <!> "passignment"
let private pprint =
(str "print"
>>. pexpression
|>> fun exp -> Print exp) <!> "pprint"
let private pread =
(str "read"
>>. pidentifier
|>> fun id -> Read id) <!> "pread"
let private pstatement =
(choice [
passignment
pprint
pread
]) <!> "pstatement"
let private pline =
(skipMany (satisfy (fun c -> c = '\n' || c = ' '))
>>. pstatement
.>> ws) <!> "pline"
let private pcode =
many pline <!> "pcode"
and run the code you will get
(Ln: 1, Col: 1): Entering pcode
(Ln: 1, Col: 1): Entering pline
(Ln: 1, Col: 1): Entering pstatement
(Ln: 1, Col: 1): Entering passignment
(Ln: 1, Col: 5): Entering pidentifier
(Ln: 1, Col: 6): Leaving pidentifier (Ok)
(Ln: 1, Col: 10): Entering pexpression
(Ln: 1, Col: 10): Entering pstringliteral
(Ln: 1, Col: 10): Leaving pstringliteral (Error)
(Ln: 1, Col: 10): Entering negationExprParser
(Ln: 1, Col: 10): Entering betweenParentheses
(Ln: 1, Col: 10): Leaving betweenParentheses (Error)
(Ln: 1, Col: 10): Entering pboolean
(Ln: 1, Col: 10): Leaving pboolean (Error)
(Ln: 1, Col: 10): Leaving negationExprParser (Error)
(Ln: 1, Col: 10): Entering logicExprParser
(Ln: 1, Col: 10): Entering betweenParentheses
(Ln: 1, Col: 10): Leaving betweenParentheses (Error)
(Ln: 1, Col: 10): Entering pboolean
(Ln: 1, Col: 10): Leaving pboolean (Error)
(Ln: 1, Col: 10): Leaving logicExprParser (Error)
(Ln: 1, Col: 10): Entering negativeExprParser
(Ln: 1, Col: 10): Entering betweenParentheses
(Ln: 1, Col: 10): Leaving betweenParentheses (Error)
(Ln: 1, Col: 10): Entering pnumeric
(Ln: 1, Col: 12): Leaving pnumeric (Ok)
(Ln: 1, Col: 12): Leaving negativeExprParser (Ok)
(Ln: 1, Col: 12): Leaving pexpression (Ok)
(Ln: 1, Col: 12): Leaving passignment (Ok)
(Ln: 1, Col: 12): Leaving pstatement (Ok)
(Ln: 1, Col: 12): Leaving pline (Ok)
(Ln: 1, Col: 12): Entering pline
(Ln: 1, Col: 12): Entering pstatement
(Ln: 1, Col: 12): Entering passignment
(Ln: 1, Col: 12): Leaving passignment (Error)
(Ln: 1, Col: 12): Entering pprint
(Ln: 1, Col: 12): Leaving pprint (Error)
(Ln: 1, Col: 12): Entering pread
(Ln: 1, Col: 12): Leaving pread (Error)
(Ln: 1, Col: 12): Leaving pstatement (Error)
(Ln: 1, Col: 12): Leaving pline (Error)
(Ln: 1, Col: 12): Leaving pcode (Ok)
[Assignment (Identifier "b",Literal (Numeric 5.0))]
(Ln: 1, Col: 1): Entering pcode
(Ln: 1, Col: 1): Entering pline
(Ln: 1, Col: 1): Entering pstatement
(Ln: 1, Col: 1): Entering passignment
(Ln: 1, Col: 5): Entering pidentifier
(Ln: 1, Col: 6): Leaving pidentifier (Ok)
(Ln: 1, Col: 10): Entering pexpression
(Ln: 1, Col: 10): Entering pstringliteral
(Ln: 1, Col: 10): Leaving pstringliteral (Error)
(Ln: 1, Col: 10): Entering negationExprParser
(Ln: 1, Col: 10): Entering betweenParentheses
(Ln: 1, Col: 11): Entering negationExprParser
(Ln: 1, Col: 11): Entering betweenParentheses
(Ln: 1, Col: 11): Leaving betweenParentheses (Error)
(Ln: 1, Col: 11): Entering pboolean
(Ln: 1, Col: 11): Leaving pboolean (Error)
(Ln: 1, Col: 11): Leaving negationExprParser (Error)
(Ln: 1, Col: 11): Leaving betweenParentheses (Error)
(Ln: 1, Col: 11): Leaving negationExprParser (Error)
(Ln: 1, Col: 10): Entering logicExprParser
(Ln: 1, Col: 10): Entering betweenParentheses
(Ln: 1, Col: 11): Entering logicExprParser
(Ln: 1, Col: 11): Entering betweenParentheses
(Ln: 1, Col: 11): Leaving betweenParentheses (Error)
(Ln: 1, Col: 11): Entering pboolean
(Ln: 1, Col: 11): Leaving pboolean (Error)
(Ln: 1, Col: 11): Leaving logicExprParser (Error)
(Ln: 1, Col: 11): Leaving betweenParentheses (Error)
(Ln: 1, Col: 11): Leaving logicExprParser (Error)
(Ln: 1, Col: 10): Entering negativeExprParser
(Ln: 1, Col: 10): Entering betweenParentheses
(Ln: 1, Col: 11): Entering negativeExprParser
(Ln: 1, Col: 11): Entering betweenParentheses
(Ln: 1, Col: 11): Leaving betweenParentheses (Error)
(Ln: 1, Col: 11): Entering pnumeric
(Ln: 1, Col: 13): Leaving pnumeric (Ok)
(Ln: 1, Col: 13): Leaving negativeExprParser (Ok)
(Ln: 1, Col: 13): Leaving betweenParentheses (Error)
(Ln: 1, Col: 13): Leaving negativeExprParser (Error)
(Ln: 1, Col: 10): Entering arithmeticExprParser
(Ln: 1, Col: 10): Entering betweenParentheses
(Ln: 1, Col: 11): Entering arithmeticExprParser
(Ln: 1, Col: 11): Entering betweenParentheses
(Ln: 1, Col: 11): Leaving betweenParentheses (Error)
(Ln: 1, Col: 11): Entering pnumeric
(Ln: 1, Col: 13): Leaving pnumeric (Ok)
(Ln: 1, Col: 18): Entering betweenParentheses
(Ln: 1, Col: 18): Leaving betweenParentheses (Error)
(Ln: 1, Col: 18): Entering pnumeric
(Ln: 1, Col: 19): Leaving pnumeric (Ok)
(Ln: 1, Col: 19): Leaving arithmeticExprParser (Ok)
(Ln: 1, Col: 20): Leaving betweenParentheses (Ok)
(Ln: 1, Col: 20): Leaving arithmeticExprParser (Ok)
(Ln: 1, Col: 20): Leaving pexpression (Ok)
(Ln: 1, Col: 20): Leaving passignment (Ok)
(Ln: 1, Col: 20): Leaving pstatement (Ok)
(Ln: 1, Col: 20): Leaving pline (Ok)
(Ln: 1, Col: 20): Entering pline
(Ln: 1, Col: 20): Entering pstatement
(Ln: 1, Col: 20): Entering passignment
(Ln: 1, Col: 20): Leaving passignment (Error)
(Ln: 1, Col: 20): Entering pprint
(Ln: 1, Col: 20): Leaving pprint (Error)
(Ln: 1, Col: 20): Entering pread
(Ln: 1, Col: 20): Leaving pread (Error)
(Ln: 1, Col: 20): Leaving pstatement (Error)
(Ln: 1, Col: 20): Leaving pline (Error)
(Ln: 1, Col: 20): Leaving pcode (Ok)
[Assignment
(Identifier "b",Arithmetic (Literal (Numeric 5.0),Sum,Literal (Numeric 7.0)))]
This should help you figure out your problem, but more importantly how to solve future problems with FParsec.

Resources