linmeric 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +51 -0
- data/Rakefile +10 -0
- data/bin/help/Help.rb +184 -0
- data/bin/help/Help_inst.rb +244 -0
- data/bin/linguide +23 -0
- data/bin/linmeric +36 -70
- data/doc/Archive.html +352 -0
- data/doc/Calculator/Evaluator.html +477 -0
- data/doc/Calculator/Lexer.html +186 -0
- data/doc/Calculator/Token.html +257 -0
- data/doc/Calculator.html +181 -0
- data/doc/Dim.html +257 -0
- data/doc/Filename.html +246 -0
- data/doc/Fixnum.html +253 -0
- data/doc/Float.html +253 -0
- data/doc/Function.html +784 -0
- data/doc/InputError.html +102 -0
- data/doc/Instructions_en.txt +6 -7
- data/doc/Instructions_it.txt +6 -9
- data/doc/Integrators.html +436 -0
- data/doc/LU.html +435 -0
- data/doc/Lexer.html +261 -0
- data/doc/Linmeric.html +109 -0
- data/doc/Listener.html +605 -0
- data/doc/Matrix.html +1719 -0
- data/doc/MyArgError.html +102 -0
- data/doc/NilClass.html +202 -0
- data/doc/Numeric.html +251 -0
- data/doc/Parser.html +389 -0
- data/doc/PrintError.html +622 -0
- data/doc/README_md.html +142 -0
- data/doc/Scp.html +530 -0
- data/doc/Sizer.html +652 -0
- data/doc/String.html +540 -0
- data/doc/Token.html +341 -0
- data/doc/Tool.html +394 -0
- data/doc/created.rid +18 -0
- data/doc/css/fonts.css +167 -0
- data/doc/css/rdoc.css +590 -0
- data/doc/fonts/Lato-Light.ttf +0 -0
- data/doc/fonts/Lato-LightItalic.ttf +0 -0
- data/doc/fonts/Lato-Regular.ttf +0 -0
- data/doc/fonts/Lato-RegularItalic.ttf +0 -0
- data/doc/fonts/SourceCodePro-Bold.ttf +0 -0
- data/doc/fonts/SourceCodePro-Regular.ttf +0 -0
- data/doc/images/add.png +0 -0
- data/doc/images/arrow_up.png +0 -0
- data/doc/images/brick.png +0 -0
- data/doc/images/brick_link.png +0 -0
- data/doc/images/bug.png +0 -0
- data/doc/images/bullet_black.png +0 -0
- data/doc/images/bullet_toggle_minus.png +0 -0
- data/doc/images/bullet_toggle_plus.png +0 -0
- data/doc/images/date.png +0 -0
- data/doc/images/delete.png +0 -0
- data/doc/images/find.png +0 -0
- data/doc/images/loadingAnimation.gif +0 -0
- data/doc/images/macFFBgHack.png +0 -0
- data/doc/images/package.png +0 -0
- data/doc/images/page_green.png +0 -0
- data/doc/images/page_white_text.png +0 -0
- data/doc/images/page_white_width.png +0 -0
- data/doc/images/plugin.png +0 -0
- data/doc/images/ruby.png +0 -0
- data/doc/images/tag_blue.png +0 -0
- data/doc/images/tag_green.png +0 -0
- data/doc/images/transparent.png +0 -0
- data/doc/images/wrench.png +0 -0
- data/doc/images/wrench_orange.png +0 -0
- data/doc/images/zoom.png +0 -0
- data/doc/index.html +190 -0
- data/doc/js/darkfish.js +161 -0
- data/doc/js/jquery.js +9404 -0
- data/doc/js/navigation.js +142 -0
- data/doc/js/navigation.js.gz +0 -0
- data/doc/js/search.js +109 -0
- data/doc/js/search_index.js +1 -0
- data/doc/js/search_index.js.gz +0 -0
- data/doc/js/searcher.js +228 -0
- data/doc/js/searcher.js.gz +0 -0
- data/doc/table_of_contents.html +834 -0
- data/lib/linmeric/Archive.rb +22 -1
- data/lib/linmeric/Calculator.rb +252 -0
- data/lib/linmeric/CnGal_Matrix_class.rb +130 -49
- data/lib/linmeric/CnGal_new_classes.rb +139 -37
- data/lib/linmeric/CnGal_tools.rb +23 -40
- data/lib/linmeric/Error_print.rb +35 -1
- data/lib/linmeric/Function_class.rb +70 -11
- data/lib/linmeric/Integrators.rb +81 -35
- data/lib/linmeric/LU.rb +26 -5
- data/lib/linmeric/Lexer.rb +19 -1
- data/lib/linmeric/Listener.rb +25 -5
- data/lib/linmeric/Parser.rb +23 -1
- data/lib/linmeric/Scopify.rb +52 -31
- data/lib/linmeric/Sizer.rb +43 -10
- data/lib/linmeric/Token.rb +23 -4
- data/lib/linmeric/version.rb +3 -0
- data/lib/linmeric.rb +10 -8
- data/lib/linmeric_bin.rb +12 -0
- metadata +126 -22
- data/doc/Instructions_en.html +0 -231
- data/doc/Instructions_it.html +0 -231
- data/doc/README_en.html +0 -177
- data/doc/README_en.txt +0 -30
- data/doc/README_it.html +0 -187
- data/doc/README_it.txt +0 -32
data/lib/linmeric/Integrators.rb
CHANGED
|
@@ -1,76 +1,122 @@
|
|
|
1
1
|
#! /usr/bin/env ruby
|
|
2
2
|
|
|
3
|
+
##
|
|
4
|
+
# This module provides some method to integrate a function
|
|
5
|
+
#
|
|
6
|
+
#
|
|
7
|
+
# Author:: Massimiliano Dal Mas (mailto:max.codeware@gmail.com)
|
|
8
|
+
# License:: Distributed under MIT license
|
|
3
9
|
module Integrators
|
|
10
|
+
|
|
11
|
+
# Implementation of trapezes method
|
|
12
|
+
#
|
|
13
|
+
# * **argument**: left range value
|
|
14
|
+
# * **argument**: right range value
|
|
15
|
+
# * **argument**: number of integration points
|
|
16
|
+
# * **returns**: result of the operation (Numeric)
|
|
4
17
|
def self.trapezi(a,b,n)
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
int_parz=0
|
|
18
|
+
h = (b - a) / n.to_f
|
|
19
|
+
int_parz = 0
|
|
8
20
|
for i in 0...n
|
|
9
|
-
#
|
|
10
|
-
f1=yield(a+i*h)
|
|
11
|
-
#
|
|
12
|
-
f2=yield(a+(i+1)*h)
|
|
13
|
-
#
|
|
14
|
-
trap=0.5*h*(f1+f2)
|
|
15
|
-
int_parz+=trap
|
|
21
|
+
# Calculating first addend = f(x_i)
|
|
22
|
+
f1 = yield(a + i * h)
|
|
23
|
+
# calculating second addend = f(X_{i+1})
|
|
24
|
+
f2 = yield(a + (i + 1) * h)
|
|
25
|
+
# Calculating trapeze area
|
|
26
|
+
trap = 0.5 * h * (f1 + f2)
|
|
27
|
+
int_parz += trap
|
|
16
28
|
end
|
|
17
29
|
return int_parz
|
|
18
30
|
end
|
|
19
31
|
|
|
32
|
+
# Implementation of midpoint method
|
|
33
|
+
#
|
|
34
|
+
# * **argument**: left range value
|
|
35
|
+
# * **argument**: right range value
|
|
36
|
+
# * **argument**: number of integration points
|
|
37
|
+
# * **returns**: result of the operation (Numeric)
|
|
20
38
|
def self.midpoint(a,b,n)
|
|
21
|
-
parz=0
|
|
22
|
-
h=(b-a)/n.to_f
|
|
39
|
+
parz = 0
|
|
40
|
+
h = (b - a) / n.to_f
|
|
23
41
|
for i in 0...n
|
|
24
|
-
f1 = yield(a+(i+0.5)*h)
|
|
25
|
-
parz+=f1
|
|
42
|
+
f1 = yield(a + (i + 0.5) * h)
|
|
43
|
+
parz += f1
|
|
26
44
|
end
|
|
27
|
-
return h*parz
|
|
45
|
+
return h * parz
|
|
28
46
|
end
|
|
29
47
|
|
|
48
|
+
# Implementation of Simpson's method
|
|
49
|
+
#
|
|
50
|
+
# * **argument**: left range value
|
|
51
|
+
# * **argument**: right range value
|
|
52
|
+
# * **argument**: number of integration points
|
|
53
|
+
# * **returns**: result of the operation (Numeric)
|
|
30
54
|
def self.simpson(a,b,n)
|
|
31
|
-
hs=(b-a)/(n*2.0)
|
|
32
|
-
intSA =0
|
|
33
|
-
intSB =0
|
|
55
|
+
hs = (b - a) / (n * 2.0)
|
|
56
|
+
intSA = 0
|
|
57
|
+
intSB = 0
|
|
34
58
|
for i in 1..n-1
|
|
35
|
-
xa = a+ (2*i)*hs
|
|
36
|
-
intSA+=yield(xa)
|
|
59
|
+
xa = a + (2 * i) * hs
|
|
60
|
+
intSA += yield(xa)
|
|
37
61
|
end
|
|
38
62
|
|
|
39
63
|
for i in 0..n-1
|
|
40
|
-
xb=a+ (2*i+1)*hs
|
|
41
|
-
intSB+=yield(xb)
|
|
64
|
+
xb = a + (2 * i + 1) * hs
|
|
65
|
+
intSB += yield(xb)
|
|
42
66
|
end
|
|
43
|
-
fa=yield(a)
|
|
44
|
-
fb=yield(b)
|
|
45
|
-
intS=hs/3.0*(fa+fb+2*intSA+4*intSB)
|
|
67
|
+
fa = yield(a)
|
|
68
|
+
fb = yield(b)
|
|
69
|
+
intS = hs / 3.0 * (fa + fb + 2 * intSA + 4 * intSB)
|
|
46
70
|
return intS
|
|
47
71
|
end
|
|
48
72
|
|
|
73
|
+
# Implementation of left rectangles method
|
|
74
|
+
#
|
|
75
|
+
# * **argument**: left range value
|
|
76
|
+
# * **argument**: right range value
|
|
77
|
+
# * **argument**: number of integration points
|
|
78
|
+
# * **returns**: result of the operation (Numeric)
|
|
49
79
|
def self.rettsx(a,b,n)
|
|
50
|
-
h=(b-a)/n.to_f
|
|
51
|
-
area=0
|
|
80
|
+
h = (b - a) / n.to_f
|
|
81
|
+
area = 0
|
|
52
82
|
for i in 0..n-1
|
|
53
|
-
area+=yield(a+(h*i))*h
|
|
83
|
+
area += yield(a + (h * i)) * h
|
|
54
84
|
end
|
|
55
85
|
return area
|
|
56
86
|
end
|
|
57
87
|
|
|
88
|
+
# Implementation of right rectangles method
|
|
89
|
+
#
|
|
90
|
+
# * **argument**: left range value
|
|
91
|
+
# * **argument**: right range value
|
|
92
|
+
# * **argument**: number of integration points
|
|
93
|
+
# * **returns**: result of the operation (Numeric)
|
|
58
94
|
def self.rettdx(a,b,n)
|
|
59
|
-
h=(b-a)/n.to_f
|
|
60
|
-
area=0
|
|
95
|
+
h = (b - a) / n.to_f
|
|
96
|
+
area = 0
|
|
61
97
|
for i in 1..n
|
|
62
|
-
area+=yield(a+(h*i))*h
|
|
98
|
+
area += yield(a + (h * i)) * h
|
|
63
99
|
end
|
|
64
100
|
return area
|
|
65
101
|
end
|
|
66
102
|
|
|
103
|
+
# Implementation of Boole's method
|
|
104
|
+
#
|
|
105
|
+
# * **argument**: left range value
|
|
106
|
+
# * **argument**: right range value
|
|
107
|
+
# * **argument**: number of integration points
|
|
108
|
+
# * **returns**: result of the operation (Numeric)
|
|
67
109
|
def self.boole(a,b,n)
|
|
68
|
-
h=(b-a)/(4*n.to_f)
|
|
69
|
-
|
|
110
|
+
h = (b - a) / (4 * n.to_f)
|
|
111
|
+
part = 0
|
|
70
112
|
for i in 0..n-1
|
|
71
|
-
|
|
113
|
+
part += 7 * yield(a + (h * 4 * i)) +
|
|
114
|
+
32 * yield(a + (h * (4 * i + 1))) +
|
|
115
|
+
12 * yield(a + (h * (4 * i + 2))) +
|
|
116
|
+
32 * yield(a + (h * (4 * i + 3))) +
|
|
117
|
+
7 * yield(a + (h * (4 * i + 4)))
|
|
72
118
|
end
|
|
73
|
-
return (2*h)/45.0*
|
|
119
|
+
return (2 * h) / 45.0 * part
|
|
74
120
|
end
|
|
75
121
|
|
|
76
122
|
end
|
data/lib/linmeric/LU.rb
CHANGED
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
#! /usr/bin/env ruby
|
|
2
2
|
require_relative 'CnGal_Matrix_class'
|
|
3
3
|
|
|
4
|
+
##
|
|
5
|
+
# This module provides some method to perform LU factorization
|
|
6
|
+
# on squared matrices.
|
|
7
|
+
#
|
|
8
|
+
#
|
|
9
|
+
# Author:: Massimiliano Dal Mas (mailto:max.codeware@gmail.com)
|
|
10
|
+
# License:: Distributed under MIT license
|
|
4
11
|
module LU
|
|
5
12
|
|
|
6
|
-
#
|
|
13
|
+
# Swaps two rows of a matrix (pivoting)
|
|
14
|
+
#
|
|
15
|
+
# * **argument**: matrix the rows must be swapped on
|
|
16
|
+
# * **argument**: first row
|
|
17
|
+
# * **argument**: second row
|
|
18
|
+
# * **returns**: new matrix with swapped rows
|
|
7
19
|
def self.swap(mx,r1,r2)
|
|
8
20
|
for i in 0...mx.getCls do
|
|
9
21
|
mx[r1,i],mx[r2,i] = mx[r2,i],mx[r1,i]
|
|
@@ -11,19 +23,27 @@ module LU
|
|
|
11
23
|
return mx
|
|
12
24
|
end
|
|
13
25
|
|
|
26
|
+
# Returns the `L` matrix
|
|
14
27
|
def self.L()
|
|
15
28
|
return @L
|
|
16
29
|
end
|
|
17
30
|
|
|
31
|
+
# Returns the `U` matrix
|
|
18
32
|
def self.U()
|
|
19
33
|
return @U
|
|
20
34
|
end
|
|
21
35
|
|
|
36
|
+
# Sets to nil @L and @U variables
|
|
22
37
|
def self.reset
|
|
23
38
|
@L = nil
|
|
24
39
|
@U = nil
|
|
25
40
|
end
|
|
26
41
|
|
|
42
|
+
# Performs LU factorization calculating L and U matrices
|
|
43
|
+
#
|
|
44
|
+
# * **argument**: squared matrix to factorize
|
|
45
|
+
# * **argument**: n x 1 matrix of known values of the linear system
|
|
46
|
+
# * **returns**: same as LU.solve
|
|
27
47
|
def self.factorize(mx,sol)
|
|
28
48
|
[mx,sol].each do |vec|
|
|
29
49
|
return nil unless vec.is_a? Matrix
|
|
@@ -33,13 +53,11 @@ module LU
|
|
|
33
53
|
return nil unless mx.is_squared?
|
|
34
54
|
return nil unless mx.getRws == sol.getRws
|
|
35
55
|
rows = mx.getRws
|
|
36
|
-
#sol.show;gets
|
|
37
56
|
for k in 0...rows do
|
|
38
57
|
column = mx[k...mx.getRws,k].export.map! { |val| val.abs}
|
|
39
58
|
max_index = column.index(column.max)
|
|
40
59
|
mx = self.swap(mx,k,k + max_index) unless k == max_index + k
|
|
41
60
|
sol = self.swap(sol,0,k + max_index) unless k == max_index + k
|
|
42
|
-
#mx.show;gets
|
|
43
61
|
for i in (k+1)...mx.getRws do
|
|
44
62
|
alpha = (mx[k,k] != 0) ? (mx[i,k] / mx[k,k].to_f) : 0
|
|
45
63
|
mx[i,k] = alpha
|
|
@@ -48,12 +66,15 @@ module LU
|
|
|
48
66
|
end
|
|
49
67
|
end
|
|
50
68
|
end
|
|
51
|
-
|
|
52
|
-
@L = Matrix.identity(mx.getRws) + Matrix.new(mx.getRws,mx.getCls){ |i,j| (i > j) ? mx[i,j] : 0} #
|
|
69
|
+
@L = Matrix.identity(mx.getRws) + Matrix.new(mx.getRws,mx.getCls){ |i,j| (i > j) ? mx[i,j] : 0}
|
|
53
70
|
@U = Matrix.new(mx.getRws,mx.getCls){ |i,j| (i <= j) ? mx[i,j] : 0}
|
|
54
71
|
return solve(sol)
|
|
55
72
|
end
|
|
56
73
|
|
|
74
|
+
# Finds the solutions of the linear system
|
|
75
|
+
#
|
|
76
|
+
# * **argument**: n x 1 matrix of known values of the linear system
|
|
77
|
+
# * **returns**: n x 1 matrix with the solutions of the system
|
|
57
78
|
def self.solve(sol)
|
|
58
79
|
z = Matrix.new(sol.getRws,1) {0}
|
|
59
80
|
x = Matrix.new(sol.getRws,1) {0}
|
data/lib/linmeric/Lexer.rb
CHANGED
|
@@ -4,8 +4,20 @@ require_relative 'CnGal_tools.rb'
|
|
|
4
4
|
require_relative 'CnGal_new_classes.rb'
|
|
5
5
|
require_relative 'Token.rb'
|
|
6
6
|
|
|
7
|
+
##
|
|
8
|
+
# This simple Lexer tokenizes the input stream of commands for the sintax analyzer
|
|
9
|
+
#
|
|
10
|
+
#
|
|
11
|
+
# Author:: Massimiliano Dal Mas (mailto:max.codeware@gmail.com)
|
|
12
|
+
# License:: Distributed under MIT license
|
|
7
13
|
class Lexer
|
|
8
14
|
|
|
15
|
+
# Tokenizes the input stream according to particular tokenizer symbols
|
|
16
|
+
# which determine the end of an element.Eg: a+3 => `+` determines the end of variable `a`
|
|
17
|
+
# and the beginning of another element (`3`)
|
|
18
|
+
#
|
|
19
|
+
# * **argument**: string to tokenize
|
|
20
|
+
# * **returns**: array of tokens (see: Token )
|
|
9
21
|
def tokenize(expr)
|
|
10
22
|
token = []
|
|
11
23
|
temp = ""
|
|
@@ -15,7 +27,6 @@ class Lexer
|
|
|
15
27
|
gen_exp = []
|
|
16
28
|
tokenizers = Tool.operators + [" ","(",")",":",'"',"~"]
|
|
17
29
|
while i < expr.size
|
|
18
|
-
# puts expr[i];gets
|
|
19
30
|
if (tokenizers.include? expr[i]) then
|
|
20
31
|
temp += ':' if expr[i] == ':'
|
|
21
32
|
token << Token.new(temp, pos) unless temp == ""
|
|
@@ -38,6 +49,13 @@ class Lexer
|
|
|
38
49
|
|
|
39
50
|
private
|
|
40
51
|
|
|
52
|
+
# Reads all the content between quotes so that it can be classified as string
|
|
53
|
+
#
|
|
54
|
+
# * **argument**: string to extract the 'string' element
|
|
55
|
+
# * **returns**: array with three elements:
|
|
56
|
+
# * 'string' element
|
|
57
|
+
# * counter `i`
|
|
58
|
+
# * boleean value to tell whether final quotes have been found (+true+ = found, +false+ = not found)
|
|
41
59
|
def extract_gen_exp(string)
|
|
42
60
|
i = 0
|
|
43
61
|
gen_exp = ""
|
data/lib/linmeric/Listener.rb
CHANGED
|
@@ -5,6 +5,13 @@ require_relative 'CnGal_new_classes.rb'
|
|
|
5
5
|
require_relative 'Archive.rb'
|
|
6
6
|
require_relative 'CnGal_tools.rb'
|
|
7
7
|
|
|
8
|
+
##
|
|
9
|
+
# This class works on the command line interface to allow the user to move
|
|
10
|
+
# the cursor, modify the input string in each point and retrieve commands from the history
|
|
11
|
+
#
|
|
12
|
+
#
|
|
13
|
+
# Author:: Massimiliano Dal Mas (mailto:max.codeware@gmail.com)
|
|
14
|
+
# License:: Distributed under MIT license
|
|
8
15
|
class Listener
|
|
9
16
|
CSI = "\e["
|
|
10
17
|
LETTERS = Tool.letters
|
|
@@ -12,6 +19,7 @@ class Listener
|
|
|
12
19
|
SPECIAL_CHARS = "|!$%&/()=?'^~+-*<>-_,:;. " + '"'
|
|
13
20
|
CHARS = LETTERS + LETTERS.upcase + SPECIAL_CHARS + NUMBERS
|
|
14
21
|
|
|
22
|
+
# Creates the main variables
|
|
15
23
|
def initialize
|
|
16
24
|
@final_string = ""
|
|
17
25
|
@i = 0
|
|
@@ -20,12 +28,14 @@ class Listener
|
|
|
20
28
|
@list = Archive.new
|
|
21
29
|
end
|
|
22
30
|
|
|
31
|
+
# reinitializates three main variables
|
|
23
32
|
def reset
|
|
24
33
|
@final_string = ""
|
|
25
34
|
@i = 0
|
|
26
35
|
@exit = false
|
|
27
36
|
end
|
|
28
37
|
|
|
38
|
+
# Reads a single char from the command line
|
|
29
39
|
def read_char
|
|
30
40
|
STDIN.echo = false
|
|
31
41
|
STDIN.raw!
|
|
@@ -42,12 +52,14 @@ class Listener
|
|
|
42
52
|
return input
|
|
43
53
|
end
|
|
44
54
|
|
|
45
|
-
|
|
55
|
+
# according to the collected key decides what to do: moving the cursor,
|
|
56
|
+
# surfing the history, or simply store chars in a variable
|
|
57
|
+
def collect_single_key()
|
|
46
58
|
c = read_char
|
|
47
59
|
case c
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
60
|
+
|
|
61
|
+
# "TAB"
|
|
62
|
+
when "\t"
|
|
51
63
|
|
|
52
64
|
# "RETURN"
|
|
53
65
|
when "\r"
|
|
@@ -139,14 +151,19 @@ class Listener
|
|
|
139
151
|
end
|
|
140
152
|
end
|
|
141
153
|
|
|
154
|
+
# main function that can be used. It returns the stream the user wrote on the command
|
|
155
|
+
# line after they pressed return.
|
|
142
156
|
def gets()
|
|
143
|
-
|
|
157
|
+
collect_single_key while(!@exit)
|
|
144
158
|
@list.store(@final_string)
|
|
145
159
|
return @final_string.clone
|
|
160
|
+
ensure
|
|
161
|
+
reset
|
|
146
162
|
end
|
|
147
163
|
|
|
148
164
|
private
|
|
149
165
|
|
|
166
|
+
# Clears the current line (deletes the typed input)
|
|
150
167
|
def clear_line
|
|
151
168
|
if @i < @final_string.size
|
|
152
169
|
for i in @i...@final_string.size do
|
|
@@ -162,6 +179,9 @@ class Listener
|
|
|
162
179
|
@i = 0
|
|
163
180
|
end
|
|
164
181
|
|
|
182
|
+
# Moves the cursor backward of the number of specified position
|
|
183
|
+
#
|
|
184
|
+
# * **argument**: number of position the cursor must be moved backward
|
|
165
185
|
def cursor_to(pos)
|
|
166
186
|
return nil if pos < 0
|
|
167
187
|
for i in pos..@final_string.size
|
data/lib/linmeric/Parser.rb
CHANGED
|
@@ -2,17 +2,35 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative 'CnGal_new_classes.rb'
|
|
4
4
|
|
|
5
|
+
##
|
|
6
|
+
# This is a stack-based parser that returns a tree in array format.
|
|
7
|
+
# Sub arrays are operations with higher priority. Operators are converted
|
|
8
|
+
# to symbol. It must be associated to Scp.
|
|
9
|
+
# Eg: 3 + 4 * 9 => `[3, :+, [4, :*, 9]]`
|
|
10
|
+
#
|
|
11
|
+
#
|
|
12
|
+
# Author:: Massimiliano Dal Mas (mailto:max.codeware@gmail.com)
|
|
13
|
+
# License:: Distributed under MIT license
|
|
5
14
|
class Parser
|
|
15
|
+
|
|
16
|
+
# Initialize two new variables: a counter and a boolean one
|
|
17
|
+
# to report errors and stop the parser
|
|
6
18
|
def initialize()
|
|
7
19
|
@d = 0
|
|
8
20
|
@error = false
|
|
9
21
|
end
|
|
10
22
|
|
|
23
|
+
# Re initializes the counter and the boolean variable
|
|
11
24
|
def reset()
|
|
12
25
|
@d = 0
|
|
13
26
|
@error = false
|
|
14
27
|
end
|
|
15
|
-
|
|
28
|
+
|
|
29
|
+
# Main function that parses the string
|
|
30
|
+
#
|
|
31
|
+
# * **argument**: string to be parsed; the string must be the
|
|
32
|
+
# output of scopify (see: Scp )
|
|
33
|
+
# * **returns**: abstract tree array
|
|
16
34
|
def parse(expr)
|
|
17
35
|
array = Array.new
|
|
18
36
|
until @d == expr.length
|
|
@@ -105,6 +123,10 @@ class Parser
|
|
|
105
123
|
return array
|
|
106
124
|
end
|
|
107
125
|
|
|
126
|
+
# Extracts the content between quotes (it must not be parsed)
|
|
127
|
+
#
|
|
128
|
+
# * **argument**: string to extract the sub-string from
|
|
129
|
+
# * **returns**: sub-string
|
|
108
130
|
def extract(expr)
|
|
109
131
|
ext = '"'
|
|
110
132
|
while expr[@d] != '"' do
|
data/lib/linmeric/Scopify.rb
CHANGED
|
@@ -1,25 +1,31 @@
|
|
|
1
1
|
#! /usr/bin/env ruby
|
|
2
2
|
require_relative 'CnGal_new_classes.rb'
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
# suo argomento vengono messi tra parentesi; es t: a => (t: a)
|
|
3
|
+
|
|
4
|
+
##
|
|
5
|
+
# This class manipulates a string representing an algebric expression
|
|
6
|
+
# underlining the higher priority operations putting them between brackets.
|
|
7
|
+
# Scp prepares strings to be parsed. It must work associated with Sizer.
|
|
8
|
+
# These rules are followed:
|
|
9
|
+
# * ... = ... => (...) = (...) (same with `>`)
|
|
10
|
+
# * a + b * c => a + (b * c) (same with `/`)
|
|
11
|
+
# * a ^ b => (a ^ (b))
|
|
12
|
+
# * <keyword>: <argument> => (<keyword>: <argument>)
|
|
13
|
+
#
|
|
14
|
+
#
|
|
15
|
+
# Author:: Massimiliano Dal Mas (mailto:max.codeware@gmail.com)
|
|
16
|
+
# License:: Distributed under MIT license
|
|
18
17
|
class Scp
|
|
18
|
+
|
|
19
|
+
# Initializes a new counter
|
|
19
20
|
def initialize
|
|
20
21
|
@i = 0
|
|
21
22
|
end
|
|
22
23
|
|
|
24
|
+
# Main function that analyzes the string and puts the brackets where it
|
|
25
|
+
# is necessary.
|
|
26
|
+
#
|
|
27
|
+
# * **argument**: string to be manipulated
|
|
28
|
+
# * **returns**: manipulated string
|
|
23
29
|
def scopify(expr)
|
|
24
30
|
expr = insert_b(expr)
|
|
25
31
|
@i = 0
|
|
@@ -34,15 +40,15 @@ class Scp
|
|
|
34
40
|
state = 0
|
|
35
41
|
while @i < expr.size
|
|
36
42
|
case expr[@i]
|
|
37
|
-
#
|
|
38
|
-
#
|
|
43
|
+
# Each part between brackets is seen as a subexpression
|
|
44
|
+
# and it is analyzed recoursively.
|
|
39
45
|
when '('
|
|
40
46
|
scp = Scp.new
|
|
41
47
|
n_expr += expr[@i] + scp.scopify(extract(expr[(@i + 1)...expr.length]))
|
|
42
48
|
@i += scp.count
|
|
43
49
|
when /[\*\/]/
|
|
44
|
-
#
|
|
45
|
-
#
|
|
50
|
+
# If there are open brackets of higher opertions
|
|
51
|
+
# it closes them
|
|
46
52
|
if open_m_b > 0
|
|
47
53
|
n_expr += ')' * open_m_b
|
|
48
54
|
last_empty = last_e.pop
|
|
@@ -54,8 +60,8 @@ class Scp
|
|
|
54
60
|
open_p_b = 0
|
|
55
61
|
state = (stack.size > 0 ? stack.pop : 0)
|
|
56
62
|
end
|
|
57
|
-
#
|
|
58
|
-
#
|
|
63
|
+
# If it is not still analyzing a multiplication, it adds the brackets
|
|
64
|
+
# following the rules
|
|
59
65
|
unless state == 1
|
|
60
66
|
n_expr.insert last_empty, '('
|
|
61
67
|
state = 1
|
|
@@ -64,8 +70,8 @@ class Scp
|
|
|
64
70
|
n_expr += expr[@i]
|
|
65
71
|
last_empty = n_expr.size # + 1
|
|
66
72
|
when /[\+\-]/
|
|
67
|
-
#
|
|
68
|
-
#
|
|
73
|
+
# higher priority operation brackets are closed
|
|
74
|
+
# last_empty is shifted
|
|
69
75
|
n_expr += ')' * open_p_b if open_p_b > 0
|
|
70
76
|
n_expr += ')' * open_b if open_b > 0
|
|
71
77
|
state = 0
|
|
@@ -74,8 +80,7 @@ class Scp
|
|
|
74
80
|
n_expr += expr[@i]
|
|
75
81
|
last_empty = n_expr.size
|
|
76
82
|
when /\^/
|
|
77
|
-
#
|
|
78
|
-
|
|
83
|
+
# It begins to put between brackets the operation and its exponent
|
|
79
84
|
if open_m_b > 0 then
|
|
80
85
|
n_expr += ")" * open_m_b
|
|
81
86
|
last_empty = last_e.pop
|
|
@@ -89,13 +94,15 @@ class Scp
|
|
|
89
94
|
stack.push state unless state == 2
|
|
90
95
|
state = 2
|
|
91
96
|
when /\=/
|
|
92
|
-
#
|
|
93
|
-
#
|
|
94
|
-
#
|
|
97
|
+
# The expression at the left of `=` is put between brackets
|
|
98
|
+
# and a bracket at the right is opened
|
|
99
|
+
# It closes previously opened brackets
|
|
95
100
|
n_expr += ')' * open_p_b if open_p_b > 0
|
|
96
|
-
n_expr += ')' * open_b
|
|
97
|
-
|
|
101
|
+
n_expr += ')' * open_b if open_b > 0
|
|
102
|
+
n_expr += ')' * open_m_b if open_m_b >0
|
|
103
|
+
open_b = 0
|
|
98
104
|
open_p_b = 0
|
|
105
|
+
open_m_b = 0
|
|
99
106
|
n_expr = '(' + n_expr + ')' + expr[@i]
|
|
100
107
|
n_expr += '('
|
|
101
108
|
last_empty = n_expr.size
|
|
@@ -135,7 +142,7 @@ class Scp
|
|
|
135
142
|
end
|
|
136
143
|
@i += 1
|
|
137
144
|
end
|
|
138
|
-
#
|
|
145
|
+
# it closes all the opened brackets
|
|
139
146
|
n_expr += ')' * open_m_b if open_m_b > 0
|
|
140
147
|
n_expr += ')' * open_p_b if open_p_b > 0
|
|
141
148
|
n_expr += ')' * open_b if open_b > 0
|
|
@@ -143,10 +150,16 @@ class Scp
|
|
|
143
150
|
return n_expr
|
|
144
151
|
end
|
|
145
152
|
|
|
153
|
+
# Returns the current value of the counter
|
|
146
154
|
def count()
|
|
147
155
|
return @i
|
|
148
156
|
end
|
|
149
157
|
|
|
158
|
+
# Inserts a couple of brackets `()` before non-binary sum and diff.
|
|
159
|
+
# operators
|
|
160
|
+
#
|
|
161
|
+
# * **argument**: string to be checked and manipulated
|
|
162
|
+
# * **returns**: manipulated string
|
|
150
163
|
def insert_b(expr)
|
|
151
164
|
@i = 0
|
|
152
165
|
string = false
|
|
@@ -162,6 +175,10 @@ class Scp
|
|
|
162
175
|
|
|
163
176
|
private
|
|
164
177
|
|
|
178
|
+
# Extracts the subexpression between brackets
|
|
179
|
+
#
|
|
180
|
+
# * **argument**: string to extract the sub expression from
|
|
181
|
+
# * **returns**: subexpression (string)
|
|
165
182
|
def extract(expr)
|
|
166
183
|
n_expr = ""
|
|
167
184
|
i = 0
|
|
@@ -175,6 +192,10 @@ class Scp
|
|
|
175
192
|
return n_expr + ')'
|
|
176
193
|
end
|
|
177
194
|
|
|
195
|
+
# Extracts the content between quotes
|
|
196
|
+
#
|
|
197
|
+
# * **argument**: string to extract the content from
|
|
198
|
+
# * **returns**: content (substring)
|
|
178
199
|
def discard(expr)
|
|
179
200
|
extract = ""
|
|
180
201
|
while expr[@i] != '"' do
|