trac_lang 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +58 -0
- data/Rakefile +12 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/examples/README.trl +633 -0
- data/examples/golf.trl +113 -0
- data/examples/list.trl +125 -0
- data/examples/math.trl +351 -0
- data/examples/meta.trl +254 -0
- data/examples/ratio.trl +107 -0
- data/examples/struct.trl +176 -0
- data/examples/term.trl +129 -0
- data/examples/util.trl +366 -0
- data/exe/trac_lang +74 -0
- data/lib/trac_lang.rb +16 -0
- data/lib/trac_lang/bindings.rb +53 -0
- data/lib/trac_lang/block.rb +46 -0
- data/lib/trac_lang/decimal.rb +79 -0
- data/lib/trac_lang/dispatch.rb +421 -0
- data/lib/trac_lang/executor.rb +97 -0
- data/lib/trac_lang/expression.rb +58 -0
- data/lib/trac_lang/form.rb +253 -0
- data/lib/trac_lang/immediate_read.rb +52 -0
- data/lib/trac_lang/octal.rb +88 -0
- data/lib/trac_lang/parser.rb +114 -0
- data/lib/trac_lang/version.rb +4 -0
- data/trac_lang.gemspec +42 -0
- metadata +177 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1d150f5cbc3fc4e763b191e4e0fa57c08e3fd318
|
4
|
+
data.tar.gz: f655796f68d27b84f26a4e1071255f1a17da15d1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2384ee6d4f74559e7632b0a3fce3baa89edbb7a1607adb742514596652c52db7563f500a845f9c90899d25c2e7e23c42d327bef23a8507e7b543a2a12f1194e8
|
7
|
+
data.tar.gz: 7b77743318ed2925a9bbb1254d9ee2faa02211c81a9ca584ad6c121a4bfc00828dd212be028e88e461cd3706b3858d5cbc296180d817a5b76b0a2cb315dfc0bf
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
2
|
+
|
3
|
+
## Our Pledge
|
4
|
+
|
5
|
+
In the interest of fostering an open and welcoming environment, we as
|
6
|
+
contributors and maintainers pledge to making participation in our project and
|
7
|
+
our community a harassment-free experience for everyone, regardless of age, body
|
8
|
+
size, disability, ethnicity, gender identity and expression, level of experience,
|
9
|
+
nationality, personal appearance, race, religion, or sexual identity and
|
10
|
+
orientation.
|
11
|
+
|
12
|
+
## Our Standards
|
13
|
+
|
14
|
+
Examples of behavior that contributes to creating a positive environment
|
15
|
+
include:
|
16
|
+
|
17
|
+
* Using welcoming and inclusive language
|
18
|
+
* Being respectful of differing viewpoints and experiences
|
19
|
+
* Gracefully accepting constructive criticism
|
20
|
+
* Focusing on what is best for the community
|
21
|
+
* Showing empathy towards other community members
|
22
|
+
|
23
|
+
Examples of unacceptable behavior by participants include:
|
24
|
+
|
25
|
+
* The use of sexualized language or imagery and unwelcome sexual attention or
|
26
|
+
advances
|
27
|
+
* Trolling, insulting/derogatory comments, and personal or political attacks
|
28
|
+
* Public or private harassment
|
29
|
+
* Publishing others' private information, such as a physical or electronic
|
30
|
+
address, without explicit permission
|
31
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
32
|
+
professional setting
|
33
|
+
|
34
|
+
## Our Responsibilities
|
35
|
+
|
36
|
+
Project maintainers are responsible for clarifying the standards of acceptable
|
37
|
+
behavior and are expected to take appropriate and fair corrective action in
|
38
|
+
response to any instances of unacceptable behavior.
|
39
|
+
|
40
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
41
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
42
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
43
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
44
|
+
threatening, offensive, or harmful.
|
45
|
+
|
46
|
+
## Scope
|
47
|
+
|
48
|
+
This Code of Conduct applies both within project spaces and in public spaces
|
49
|
+
when an individual is representing the project or its community. Examples of
|
50
|
+
representing a project or community include using an official project e-mail
|
51
|
+
address, posting via an official social media account, or acting as an appointed
|
52
|
+
representative at an online or offline event. Representation of a project may be
|
53
|
+
further defined and clarified by project maintainers.
|
54
|
+
|
55
|
+
## Enforcement
|
56
|
+
|
57
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
58
|
+
reported by contacting the project team at TODO: Write your email address. All
|
59
|
+
complaints will be reviewed and investigated and will result in a response that
|
60
|
+
is deemed necessary and appropriate to the circumstances. The project team is
|
61
|
+
obligated to maintain confidentiality with regard to the reporter of an incident.
|
62
|
+
Further details of specific enforcement policies may be posted separately.
|
63
|
+
|
64
|
+
Project maintainers who do not follow or enforce the Code of Conduct in good
|
65
|
+
faith may face temporary or permanent repercussions as determined by other
|
66
|
+
members of the project's leadership.
|
67
|
+
|
68
|
+
## Attribution
|
69
|
+
|
70
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
71
|
+
available at [http://contributor-covenant.org/version/1/4][version]
|
72
|
+
|
73
|
+
[homepage]: http://contributor-covenant.org
|
74
|
+
[version]: http://contributor-covenant.org/version/1/4/
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2017 TODO: Write your name
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# TracLang
|
2
|
+
|
3
|
+
An implementation of TRAC Language, written in Ruby.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'trac_lang'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install trac_lang
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
Once it's installed, you can run:
|
24
|
+
|
25
|
+
$ trac_lang
|
26
|
+
|
27
|
+
from the command line to start the TRAC interpreter. You can also give it a file name of a file with TRAC commands in it to load those commands before you start the interpreter. Try the examples/util.trl file to get a number of useful utilities loaded.
|
28
|
+
|
29
|
+
TRAC is a macro language, meaning it consists solely of replacing strings of text with other strings. In spite of this simplicity, it is surprisingly powerful, to the point where you can create a version of the Y combinator, as follows:
|
30
|
+
|
31
|
+
#(DS,Y,(
|
32
|
+
#(#(lambda,x,(
|
33
|
+
#(f,(#(x,x)))
|
34
|
+
)),#(lambda,x,(
|
35
|
+
#(f,(#(x,x)))
|
36
|
+
)))
|
37
|
+
))
|
38
|
+
#(SS,Y,f)
|
39
|
+
|
40
|
+
You can read about the different TRAC commands available in the examples/README.trl file, or read the original manual by the creator of TRAC, Calvin Mooers:
|
41
|
+
|
42
|
+
https://web.archive.org/web/20050205173449/http://tracfoundation.org:80/t64tech.htm
|
43
|
+
|
44
|
+
## Development
|
45
|
+
|
46
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
47
|
+
|
48
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
49
|
+
|
50
|
+
## Contributing
|
51
|
+
|
52
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/trac_lang. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
53
|
+
|
54
|
+
|
55
|
+
## License
|
56
|
+
|
57
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
58
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "trac_lang"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/examples/README.trl
ADDED
@@ -0,0 +1,633 @@
|
|
1
|
+
|
2
|
+
TRAC Example Code README
|
3
|
+
|
4
|
+
#(PS,Loading examples/README.trl...)'
|
5
|
+
|
6
|
+
|
7
|
+
Introduction
|
8
|
+
-------------------------------------------------------------------------------
|
9
|
+
|
10
|
+
TRAC is a macro language, meaning it consists solely of replacing strings of
|
11
|
+
text with other strings of text. Despite this seeming simplicity, it's
|
12
|
+
capable of very sophisticated programming constructs. TRAC was originally
|
13
|
+
created in the sixties by Calvin Mooers and implemented by Peter Deutsch.
|
14
|
+
The best introduction to TRAC is to read Mooers original user manual, which
|
15
|
+
you can find online on the following page:
|
16
|
+
|
17
|
+
TRAC T64 Version
|
18
|
+
https://web.archive.org/web/20050205173449/http://tracfoundation.org:80/t64tech.htm
|
19
|
+
|
20
|
+
TRAC was featured in Computer Lib/Dream Machines by Ted Nelson.
|
21
|
+
|
22
|
+
There's a version of TRAC called MINT which was used to write a version of
|
23
|
+
EMACS called FreeMACS. You can find a version of it here:
|
24
|
+
|
25
|
+
C++ Windows/Linux/MacOS X port of Russell Nelson's FreeMACS:
|
26
|
+
https://github.com/msandiford/Freemacs
|
27
|
+
|
28
|
+
Another macro language that's similar to TRAC is TTM. In the following PDF
|
29
|
+
file, a number of applications for a macro language are demonstrated,
|
30
|
+
including expression parsing. It's a great introduction to what TRAC can do.
|
31
|
+
|
32
|
+
TTM: An Experimental Interpretive Language
|
33
|
+
https://github.com/Unidata/ttm/raw/master/ttm_interpretive_language_pr_07.pdf
|
34
|
+
|
35
|
+
There are some other implementations of TRAC.
|
36
|
+
|
37
|
+
In Python:
|
38
|
+
|
39
|
+
http://code.activestate.com/recipes/577366-trac-interpreter-sixties-programming-language/
|
40
|
+
|
41
|
+
https://github.com/natkuhn/Trac-in-Python
|
42
|
+
|
43
|
+
In Perl:
|
44
|
+
|
45
|
+
At the RetroComputing Museum, search for "TRAC" on the page:
|
46
|
+
http://www.catb.org/retro/
|
47
|
+
|
48
|
+
In Tcl/Tk:
|
49
|
+
|
50
|
+
Here someone creates a TRAC-like interpreter in Tcl/Tk:
|
51
|
+
http://wiki.tcl.tk/11314
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
Using TRAC
|
56
|
+
-------------------------------------------------------------------------------
|
57
|
+
|
58
|
+
Each TRAC command starts with one or two hash characters, and are surrounded
|
59
|
+
by parentheses, like so:
|
60
|
+
|
61
|
+
(
|
62
|
+
#(PS,Hello World!)
|
63
|
+
#(DS,test,##(RS))
|
64
|
+
)
|
65
|
+
|
66
|
+
The first word after the open parenthesis is the command, while the other
|
67
|
+
words after are the arguments. The commands above will print "Hello World!"
|
68
|
+
and then set the variable "test" to whatever you type in. A complete list of
|
69
|
+
TRAC commands appears later in this file.
|
70
|
+
|
71
|
+
You can either enter TRAC commands in a file and have the file executed, or
|
72
|
+
type them in at the command prompt while in the TRAC interpreter. Either
|
73
|
+
way, to let the parser know that you're ready for it to execute the command,
|
74
|
+
you must end the command with a single quote, known as the meta character.
|
75
|
+
You can see an example of this at the beginning of this file and at the end.
|
76
|
+
The meta character should not appear within comments such as this, nor within
|
77
|
+
protecting parentheses.
|
78
|
+
|
79
|
+
TRAC was originally written for a teletype - a computer attached to a
|
80
|
+
typewriter. Whatever you typed would be printed on a piece of paper, not a
|
81
|
+
screen, so there was no such thing as backspacing over your mistakes. So
|
82
|
+
working at the prompt is going to be different from what you're used to. The
|
83
|
+
"\" character will tell TRAC to ignore the last character you typed and the
|
84
|
+
"@" character will tell TRAC to ignore everything you've typed. So if you
|
85
|
+
type the following:
|
86
|
+
(
|
87
|
+
#,\(,@#(O\Ps\S,Hello)
|
88
|
+
)
|
89
|
+
the TRAC interpreter will see this:
|
90
|
+
(
|
91
|
+
#(PS,Hello)
|
92
|
+
)
|
93
|
+
Also, the enter key will not make a command be executed. Instead the meta
|
94
|
+
character will, as explained above. So the following is valid TRAC, and
|
95
|
+
will print two new lines:
|
96
|
+
(
|
97
|
+
#(PS,(
|
98
|
+
|
99
|
+
))
|
100
|
+
)
|
101
|
+
|
102
|
+
As you can see from this file, text can be mixed freely in TRAC code files,
|
103
|
+
and will be ignored. If you want some code to be ignored, just protect it
|
104
|
+
with parentheses, like so:
|
105
|
+
(
|
106
|
+
#(PS,This will not be printed)
|
107
|
+
)
|
108
|
+
|
109
|
+
TRAC does not do a lot of error checking. If you give it a command it
|
110
|
+
doesn't recognize, it will ignore it. You can take advantage of this by
|
111
|
+
using the empty command to create comments in scripts:
|
112
|
+
|
113
|
+
#(, This will also not be executed)'
|
114
|
+
|
115
|
+
Although the command above is executed, since it doesn't exist as a valid
|
116
|
+
command it will be replaced by the empty string when it's processed.
|
117
|
+
|
118
|
+
There are three syntactic groupings in TRAC:
|
119
|
+
|
120
|
+
* Active Command
|
121
|
+
. Starts with single hash character, delimited by matching parentheses
|
122
|
+
. Result is result of TRAC or user defined command
|
123
|
+
. Result is rescanned for more commands
|
124
|
+
* Neutral Command
|
125
|
+
. Starts with two hash characters, delimited by matching parentheses
|
126
|
+
. Result is result of TRAC command
|
127
|
+
. Result is not scanned again
|
128
|
+
* Protected Parentheses
|
129
|
+
. Delimited by matching parentheses
|
130
|
+
. Result is text between parentheses
|
131
|
+
. Result is not scanned again
|
132
|
+
|
133
|
+
There's one last concept about TRAC that needs to be reviewed. When the TRAC
|
134
|
+
command DS gives a name to a string, that defined string is called a form.
|
135
|
+
Each form has a form pointer, that points to a character in the string.
|
136
|
+
Different commands will return what the form pointer is pointing to and then
|
137
|
+
increment the form pointer. What is returned and how the form pointer is
|
138
|
+
incremented depends on which command is called.
|
139
|
+
|
140
|
+
Coding Conventions
|
141
|
+
-------------------------------------------------------------------------------
|
142
|
+
|
143
|
+
Carriage returns and line feeds are ignored in TRAC commands unless they're
|
144
|
+
protected by parentheses, so commands can have any number of newlines to make
|
145
|
+
them more readable. However, spaces and tabs are not ignored, and commands
|
146
|
+
are harder to understand if there's no indentation. So, I've written a
|
147
|
+
"scrub" script that removes spaces and tabs from forms as well, in the
|
148
|
+
examples/util.trl file.
|
149
|
+
|
150
|
+
In the example code, I've used two spaces for indentation, and started a new
|
151
|
+
line for the following:
|
152
|
+
|
153
|
+
* definitions
|
154
|
+
* sequential commands
|
155
|
+
* results of tests
|
156
|
+
|
157
|
+
You can see all of this in the following defintions, which create a script to
|
158
|
+
reverse a string.
|
159
|
+
|
160
|
+
(
|
161
|
+
|
162
|
+
#(DS,[reverse],( #(, <== define helper script )
|
163
|
+
#(EQ,##(CC,<a>,--),--,( #(, <== at end of string? )
|
164
|
+
##(CL,str) #(, <== if so, return answer )
|
165
|
+
),( #(, <== otherwise )
|
166
|
+
#(,##(CN,<a>,-1)) #(, <== read prev char, discard )
|
167
|
+
#(DS,str,##(CC,<a>)##(CL,str)) #(, <== add last char read )
|
168
|
+
#([reverse],<a>) #(, <== call recursively )
|
169
|
+
))
|
170
|
+
))
|
171
|
+
#(sss,[reverse],<a>)
|
172
|
+
|
173
|
+
#(DS,reverse,(#(DS,str,)#([reverse],<a>)))
|
174
|
+
#(SS,reverse,<a>)'
|
175
|
+
|
176
|
+
)
|
177
|
+
|
178
|
+
In most of my definitions, I've delimited arguments to forms with angle
|
179
|
+
brackets. This is not a requirement - TRAC allows you to enter any string
|
180
|
+
whatsoever. I used the angle brackets because they stand out and they also
|
181
|
+
make the parameter names unique. Look at the following example.
|
182
|
+
|
183
|
+
(
|
184
|
+
#(DS,diff,(#(abs,#(SU,a,b))))
|
185
|
+
#(SS,diff,a,b)
|
186
|
+
)
|
187
|
+
|
188
|
+
Because there aren't angle brackets around a and b, the a and b of abs have
|
189
|
+
also been made into segment gaps, and we have:
|
190
|
+
|
191
|
+
(
|
192
|
+
#(diff,2,3) => #(23s,#(SU,2,3))
|
193
|
+
)
|
194
|
+
|
195
|
+
TRAC, being error averse, simply returns the empty string from the
|
196
|
+
non-existent form 23s.
|
197
|
+
|
198
|
+
Although TRAC allows you to use any character for anything, I've avoided
|
199
|
+
using symbols for operations I've defined. Letters are much easier to type
|
200
|
+
than symbols, so for instance, I have:
|
201
|
+
|
202
|
+
mod for modulo instead of %
|
203
|
+
abs for absolute value instead of |.|
|
204
|
+
times for repeated action instead of *
|
205
|
+
|
206
|
+
However, if you prefer symbols instead of names, it would be easy enough for
|
207
|
+
you to make a file of synonyms for operations if you want.
|
208
|
+
|
209
|
+
|
210
|
+
TRAC Commands
|
211
|
+
-------------------------------------------------------------------------------
|
212
|
+
|
213
|
+
Each command takes some action and then returns a string as a result.
|
214
|
+
|
215
|
+
Basic Commands
|
216
|
+
--------------
|
217
|
+
|
218
|
+
DS Define String ( #(DS,name,value) )
|
219
|
+
Result: Empty string
|
220
|
+
|
221
|
+
Defines a string, giving it a name and storing it in form storage.
|
222
|
+
Strings that have been given names are called "forms". Strings that have
|
223
|
+
TRAC commands in them are called "scripts".
|
224
|
+
|
225
|
+
When you define a script, remember to protect its definition with
|
226
|
+
parentheses or you will end up running the script before it's named.
|
227
|
+
(
|
228
|
+
#(DS,value,#(AD,a,5))
|
229
|
+
#(DS,value2,(#(AD,a,5)))
|
230
|
+
)
|
231
|
+
Above "value" has been set to 5, since strings without numeric characters
|
232
|
+
in them are considered equal to zero. The "value2" on the other hand, has
|
233
|
+
been set to( #(AD,a,5) )so later, if we put in a value for "a", it will be
|
234
|
+
able to calculate something.
|
235
|
+
|
236
|
+
SS Segment String ( #(SS,name,arg1,arg2,...) ) Result: empty string
|
237
|
+
Result: Empty string
|
238
|
+
|
239
|
+
Break a defined string into segments, using the given arguments. Each
|
240
|
+
argument is searched for in turn, and if found in the named string, a
|
241
|
+
numbered hole is punched in the string where the argument was found. The
|
242
|
+
parts of the string between the holes are called segments, and the holes
|
243
|
+
themselves are called segment gaps. Using the defintions from above:
|
244
|
+
(
|
245
|
+
#(DS,value2,(#(AD,a,5)))
|
246
|
+
#(SS,value2,a)
|
247
|
+
)
|
248
|
+
Now the form value2 has a hole where the "a" was, which can be filled with
|
249
|
+
whatever we want when we call it using the next command.
|
250
|
+
|
251
|
+
CL Call ( #(CL,name,arg1,arg2,...) )
|
252
|
+
Result: Value of form with gaps replaced by given arguments
|
253
|
+
|
254
|
+
Retrieve a form, replacing any segments gaps in it with the arguments
|
255
|
+
provided. Taking the commands from above as before:
|
256
|
+
(
|
257
|
+
#(DS,value2,(#(AD,a,5)))
|
258
|
+
#(SS,value2,a)
|
259
|
+
#(CL,value2,5) ==> result 10
|
260
|
+
#(CL,value2,121) ==> result 126
|
261
|
+
#(CL,value2,#(ML,2,7)) ==> result 70
|
262
|
+
#(CL,value2) ==> result 5 (gap replaced by empty string
|
263
|
+
which has a value of zero)
|
264
|
+
)
|
265
|
+
Also, we can call this command neutrally to see what the value of a form
|
266
|
+
is.
|
267
|
+
(
|
268
|
+
##(CL,value2,--arg1--) ==> result( #(AD,--arg1--,5) )
|
269
|
+
)
|
270
|
+
|
271
|
+
HL Halt ( #(HL) )
|
272
|
+
Result: Empty string
|
273
|
+
|
274
|
+
Stop the TRAC processor.
|
275
|
+
|
276
|
+
|
277
|
+
Console I/O
|
278
|
+
-----------
|
279
|
+
|
280
|
+
PS Print String ( #(PS,value) )
|
281
|
+
Result: Empty string
|
282
|
+
|
283
|
+
Prints the given value to the console. Unless the value is protected by
|
284
|
+
parentheses, any carriage return or linefeed character in it will be
|
285
|
+
stripped. All other control characters can appear in the value however,
|
286
|
+
including ANSI escape codes for controlling the terminal.
|
287
|
+
|
288
|
+
RC Read Character ( #(RC) )
|
289
|
+
Result: Character read
|
290
|
+
|
291
|
+
Read a single character from the keyboard. Any character can be entered
|
292
|
+
this way, include parentheses, the meta character and the two editing
|
293
|
+
characters.
|
294
|
+
|
295
|
+
RS Read String ( #(RS) )
|
296
|
+
Result: Value read
|
297
|
+
|
298
|
+
Read a string from the keyboard, up until the meta character is pressed.
|
299
|
+
The string may have any character you can type at the keyboard, with the
|
300
|
+
following exceptions:
|
301
|
+
|
302
|
+
Edit character \ erases previous character from string
|
303
|
+
Edit character @ erases entire entered string
|
304
|
+
Meta character ends input
|
305
|
+
|
306
|
+
The meta character is normally set to single quote but you can change it
|
307
|
+
to another character using the following command.
|
308
|
+
|
309
|
+
CM Change Meta ( #(CM) )
|
310
|
+
Result: Empty string
|
311
|
+
|
312
|
+
Change the meta character to a different character. Once it's changed all
|
313
|
+
input will use the new meta character until you call this command with a
|
314
|
+
different value. You can even change the meta character to the enter key
|
315
|
+
if you wish.
|
316
|
+
|
317
|
+
Form Reading
|
318
|
+
------------
|
319
|
+
|
320
|
+
CC Call Character ( #(CC,name,eos) )
|
321
|
+
Result: Next character of form or eos value if at end of string
|
322
|
+
|
323
|
+
Returns the next character of the form and increments the form pointer by
|
324
|
+
one. If the form pointer is at the end of the string, the eos value is
|
325
|
+
returned. This is used to read a form character by character.
|
326
|
+
|
327
|
+
CN Call N Characters ( #(CN,name,n,eos) )
|
328
|
+
Result: Next n characters of form or eos value if at end of string
|
329
|
+
|
330
|
+
Returns "n" characters from the string and increments the form pointer by
|
331
|
+
the same amount. The "n" can be positive or negative. When "n" is
|
332
|
+
negative the characters read are still returned in the orginal order they
|
333
|
+
are in the string. If "n" is positive and the form pointer is at the end
|
334
|
+
of the string, or "n" is negative and the form pointer is at the beginning
|
335
|
+
of the string, the eos parameter is returned.
|
336
|
+
|
337
|
+
This can be called to check if the form pointer is at the beginning or end
|
338
|
+
of the string without moving the pointer by using -0 or 0 as the number of
|
339
|
+
characters respectively. For example:
|
340
|
+
(
|
341
|
+
#(CN,string,-0,begin) <= returns "begin" if you're at the beginning of
|
342
|
+
the form, and an empty string otherwise
|
343
|
+
#(CN,string,0,end) <= returns "end" if you're at the end of the form
|
344
|
+
and an empty string otherwise
|
345
|
+
)
|
346
|
+
|
347
|
+
CS Call Segment ( #(CS,name,eos) )
|
348
|
+
Result: Next segment of form or eos value if at end of string
|
349
|
+
|
350
|
+
When you punch holes in a form with the SS command, text between the holes
|
351
|
+
is called a segment. This command calls up each segment in turn, and then
|
352
|
+
returns the eos argument when the form pointer is at the end of the form.
|
353
|
+
For example:
|
354
|
+
(
|
355
|
+
#(DS,list,2;5;13;7;12)
|
356
|
+
#(SS,list,;) <= each number is now in an individual segment
|
357
|
+
#(CS,list) <= "2"
|
358
|
+
#(CS,list) <= "5"
|
359
|
+
#(CL,list,/) <= "13/7/12"
|
360
|
+
)
|
361
|
+
A gotcha to watch out for - if a segment gap starts the form, an empty
|
362
|
+
string will be returned for the first call. For example:
|
363
|
+
(
|
364
|
+
#(DS,name,<first> <middle-init>. <last>)
|
365
|
+
#(SS,name,<first>,<middle-init>,<last>)
|
366
|
+
#(CS,name) <= empty string
|
367
|
+
#(CS,name) <= single space
|
368
|
+
#(CS,name) <= ". "
|
369
|
+
#(CL,name,Smith) <= last segment gap is numbered three and
|
370
|
+
no third argument was given, so empty
|
371
|
+
string is returned
|
372
|
+
)
|
373
|
+
|
374
|
+
IN In String ( #(IN,name,value,eos) )
|
375
|
+
Result: String preceeding found value or eos value if at end of string
|
376
|
+
|
377
|
+
The IN command searches for a string in the given form starting at the
|
378
|
+
form pointer. If the value is found, this command returns everything
|
379
|
+
between the form pointer and the found string, and then the form pointer
|
380
|
+
is moved beyond the found string. If the value is not found, the eos
|
381
|
+
value is returned and the form pointer is unchanged.
|
382
|
+
|
383
|
+
This command can also be used to test if a form with a given name exists.
|
384
|
+
Let value be the empty string, something that will never be found in an
|
385
|
+
existing form.
|
386
|
+
(
|
387
|
+
#(IN,x123,,exists)
|
388
|
+
If a form with the name x123 exists, "exists" will be returned.
|
389
|
+
Otherwise the empty string will be returned since the form doesn't
|
390
|
+
exist.
|
391
|
+
)
|
392
|
+
|
393
|
+
CR Call Return ( #(CR,name) )
|
394
|
+
Result: Empty string
|
395
|
+
|
396
|
+
This command moves the form pointer back to the start of the form. There
|
397
|
+
is no corresponding command that moves the pointer to the end of the form.
|
398
|
+
|
399
|
+
|
400
|
+
Form Storage
|
401
|
+
------------
|
402
|
+
|
403
|
+
LN List Names ( #(LN,delimiter) )
|
404
|
+
Result: List of form names delimited by given delimiter
|
405
|
+
|
406
|
+
This command lists the names of all defined forms using the given
|
407
|
+
delimiter. Two examples, using space and newline as delimiters:
|
408
|
+
(
|
409
|
+
#(LN, )scrub count times backslash space return tab escape ...
|
410
|
+
#(LN,(
|
411
|
+
))
|
412
|
+
scrub
|
413
|
+
count
|
414
|
+
times
|
415
|
+
...
|
416
|
+
)
|
417
|
+
|
418
|
+
DD Delete Definition ( #(DD,name1,name2,...) )
|
419
|
+
Result: Empty string
|
420
|
+
|
421
|
+
Deletes the named definitions. If one of the names doesn't correspond to
|
422
|
+
an existing definition, it's ignored.
|
423
|
+
|
424
|
+
DA Delete All ( #(DA) )
|
425
|
+
Result: Empty string
|
426
|
+
|
427
|
+
Delete all defined forms.
|
428
|
+
|
429
|
+
SB Store Block ( #(SB,block-name,form-name1,form-name2,...) )
|
430
|
+
Result: Empty string
|
431
|
+
|
432
|
+
Saves the given forms in a file with the given name and an extension of
|
433
|
+
.trl in the default save directory. The file format will be a text file
|
434
|
+
with TRAC commands in it for defining, segmenting and possibly moving the
|
435
|
+
form pointer of the given forms. The listed forms will be removed from
|
436
|
+
the list of definitions, and a new form will be created, with the same
|
437
|
+
name as the block name. This form will be used in the following command.
|
438
|
+
|
439
|
+
FB Fetch Block ( #(FB,block-name) )
|
440
|
+
Result: Empty string
|
441
|
+
|
442
|
+
Reads the file defined by the given form and loads all TRAC commands in
|
443
|
+
that file. The file can either have been created by the SB command above
|
444
|
+
or created by hand using an editor.
|
445
|
+
|
446
|
+
|
447
|
+
Integer Mathematics
|
448
|
+
-------------------
|
449
|
+
|
450
|
+
Numbers in TRAC are just strings; they are just read in a special way. Any
|
451
|
+
leading non-numeric characters are ignored, so numbers can have descriptive
|
452
|
+
prefixes, like "apples5" or "salary-john:150000". Numbers have an optional
|
453
|
+
sign, and then a string of digits. A string without any digits in it is
|
454
|
+
intepreted as a zero.
|
455
|
+
|
456
|
+
AD Add ( #(AD,n1,n2) )
|
457
|
+
Result: Sum of n1 and n2
|
458
|
+
|
459
|
+
Add two numbers. The prefix for n1 will be copied to the result.
|
460
|
+
|
461
|
+
SU Subtract ( #(SU,n1,n2) )
|
462
|
+
Result: Difference of n1 and n2
|
463
|
+
|
464
|
+
Subtract two numbers. The prefix for n1 will be copied to the result.
|
465
|
+
|
466
|
+
ML Multiply ( #(ML,n1,n2) )
|
467
|
+
Result: Product of n1 and n2
|
468
|
+
|
469
|
+
Multiply two numbers. The prefix for n1 will be copied to the result.
|
470
|
+
|
471
|
+
DV Divide ( #(DV,n1,n2,z) )
|
472
|
+
Result: Quotient of n1 and n2, or z if n2 is zero
|
473
|
+
|
474
|
+
Divide n2 into n1. TRAC truncates down, so for instance, -7 / 3 is -3.
|
475
|
+
If n2 is zero, the z parameter is returned.
|
476
|
+
|
477
|
+
|
478
|
+
Octal Mathematics
|
479
|
+
-----------------
|
480
|
+
|
481
|
+
Bit operations are done on octal numbers in TRAC. Unlike integers, octal
|
482
|
+
numbers do not carry a non-numeric prefix. TRAC also does not have a word
|
483
|
+
size defined, so octal numbers can be of arbitrary length. This means the
|
484
|
+
shift and rotate commands will work with the bits you have given them,
|
485
|
+
instead of working within a fixed word size.
|
486
|
+
|
487
|
+
BU Bit Union ( #(BU,o1,o2) )
|
488
|
+
Result: Bitwise OR of two octal numbers.
|
489
|
+
|
490
|
+
BI Bit Intersection ( #(BI,o1,o2) )
|
491
|
+
Result: Bitwise AND of two octal numbers.
|
492
|
+
|
493
|
+
BC Bit Complement ( #(BC,o1) )
|
494
|
+
Result: Bitwise complement of octal number.
|
495
|
+
|
496
|
+
BS Bit Shift ( #(BS,o1,n1) )
|
497
|
+
Result: Bit shift of octal number by the decimal number given.
|
498
|
+
|
499
|
+
BR Bit Rotate ( #(BR,o1,n1) )
|
500
|
+
Result: Bit rotation of octal number by the decimal number given.
|
501
|
+
|
502
|
+
|
503
|
+
Debugging
|
504
|
+
---------
|
505
|
+
|
506
|
+
PF Print Form ( #(PF,name) )
|
507
|
+
Result: Empty string
|
508
|
+
|
509
|
+
Print the value of a form, with indicators to show where the form pointer
|
510
|
+
is and where the segment gaps are. For example:
|
511
|
+
(
|
512
|
+
#(DS,form,abcdefghijklmnop)
|
513
|
+
#(SS,form,c,f,j)
|
514
|
+
#(CS,form) ==> ab
|
515
|
+
#(CS,form) ==> de
|
516
|
+
#(CC,form) ==> g
|
517
|
+
#(PF,form) ==> ab<1>de<2>g<^>hi<3>klmnop
|
518
|
+
)
|
519
|
+
|
520
|
+
TN Trace On ( #(TN) )
|
521
|
+
Result: Empty string
|
522
|
+
|
523
|
+
Turns trace on. When trace is on, every time TRAC is ready to execute a
|
524
|
+
string, it will display it first, and wait for your response. The string
|
525
|
+
will be displayed in a special form, delimited by slashes instead of
|
526
|
+
parentheses and with asterisks separating arguments instead of commas. If
|
527
|
+
you want to execute the command, press enter, and the next command will be
|
528
|
+
displayed to you. If you want to quit, press any other key and the TRAC
|
529
|
+
processor will be cleared and the idle string will be reloaded. The idle
|
530
|
+
string is the following TRAC command:
|
531
|
+
(
|
532
|
+
#(PS,#(RS))
|
533
|
+
)
|
534
|
+
This reads a string, executes it, and prints the result. This is loaded
|
535
|
+
on startup, whenever a serious error occurs, and when you exit from trace.
|
536
|
+
|
537
|
+
TF Trace Off ( #(TF) )
|
538
|
+
Result: Empty string
|
539
|
+
|
540
|
+
Turn tracing off. You can debug certain sections of code by surrounding
|
541
|
+
it with a trace on and trace off command.
|
542
|
+
|
543
|
+
|
544
|
+
Example Files
|
545
|
+
-------------------------------------------------------------------------------
|
546
|
+
|
547
|
+
README.trl This file
|
548
|
+
util.trl Basic utilities for TRAC, including scrub which is needed for
|
549
|
+
the rest of the files
|
550
|
+
term.trl Terminal control with ANSI escape codes
|
551
|
+
math.trl Definition of some basic mathematical functions
|
552
|
+
ratio.trl Rational numbers defined in TRAC
|
553
|
+
meta.trl Meta-programming including combinators
|
554
|
+
list.trl List commands written in TRAC
|
555
|
+
golf.trl A few code golf attempts
|
556
|
+
|
557
|
+
|
558
|
+
Things To Watch Out For
|
559
|
+
-------------------------------------------------------------------------------
|
560
|
+
|
561
|
+
Active Call .vs. Neutral Call
|
562
|
+
|
563
|
+
The result of an active call is rescanned for TRAC commands while the result
|
564
|
+
of a neutral call is not. But you need to remember, you can only call a TRAC
|
565
|
+
mnemonic command neutrally. User defined commands are always active. So in
|
566
|
+
the following:
|
567
|
+
|
568
|
+
(
|
569
|
+
##(mycmd,1,2,3)
|
570
|
+
##(CL,mycmd,1,2,3)
|
571
|
+
)
|
572
|
+
|
573
|
+
only the second call is a neutral call. The result of the first one is
|
574
|
+
rescanned, despite the double hash marks in front of it.
|
575
|
+
|
576
|
+
|
577
|
+
Unprotected Whitespace
|
578
|
+
|
579
|
+
Newlines and linefeeds are ignored if they are unprotected. This is great
|
580
|
+
for the average script, but when you're trying to create a form with newlines
|
581
|
+
in it, it can be frustrating. Just remember to protect any newlines you want
|
582
|
+
to keep with parentheses. Also, if you use any of my scrub scripts defined
|
583
|
+
in examples/util.trl, remember to use (##(CL,space)) instead of a literal
|
584
|
+
space when you actually want to use a space character.
|
585
|
+
|
586
|
+
|
587
|
+
CL And The Form Pointer
|
588
|
+
|
589
|
+
The CL command only returns the part of the form that is past the form
|
590
|
+
pointer. So if you ever use one of the form call commands (CC,CN,CS,IN) on a
|
591
|
+
script, CL is not going to return what you expect.
|
592
|
+
(
|
593
|
+
#(DS,diff,(#(GR,a,b,(#(SU,a,b)),(#(SU,b,a)))))
|
594
|
+
#(SS,diff,a,b)
|
595
|
+
|
596
|
+
Find out if script uses "GR"
|
597
|
+
|
598
|
+
#(EQ,#(IN,diff,GR,-END-),-END-,not-used,used)
|
599
|
+
|
600
|
+
If we call it now, we get:
|
601
|
+
|
602
|
+
#(diff,5,2) ==> ,5,2,(#(SU,5,2)),(#(SU,2,5)) (plus another paren)
|
603
|
+
|
604
|
+
which is more than likely going to cause an error.
|
605
|
+
)
|
606
|
+
|
607
|
+
EQ .vs. GR
|
608
|
+
|
609
|
+
EQ is for comparing strings, while GR is for comparing numbers. This can
|
610
|
+
lead to some confusing results:
|
611
|
+
|
612
|
+
(
|
613
|
+
#(EQ,0,,true,false) => false
|
614
|
+
|
615
|
+
Even though the empty string is zero numerically, here it's being
|
616
|
+
compared as a string, and so it not equal to 0. To find if two numbers
|
617
|
+
are equal, you must verify that neither is greater than the other. In
|
618
|
+
the examples/math.trl file I define a script called eqn which tests
|
619
|
+
numeric equality this way. This will usually not cause problems if you
|
620
|
+
don't use prefixes on numbers, but the above can catch you if you're not
|
621
|
+
careful.
|
622
|
+
|
623
|
+
#(GR,b,a,true,false) => false
|
624
|
+
|
625
|
+
Both "a" and "b" are considered zero numerically, so neither is greater
|
626
|
+
than the other, so this will return false no matter which character is
|
627
|
+
first. TRAC actually doesn't have any provision for comparing strings
|
628
|
+
lexically.
|
629
|
+
)
|
630
|
+
|
631
|
+
|
632
|
+
#(PS,(success!
|
633
|
+
))'
|