Skip to content

Commit c031321

Browse files
committed
Added support for single quoted strings. Tried to get multi-line if statements to work, still some problems.
1 parent ea2f671 commit c031321

File tree

9 files changed

+204
-62
lines changed

9 files changed

+204
-62
lines changed

README.textile

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
1-
Please note that this application is a development stage.
1+
Please note that this application is in a development stage.
22
I'm just adding this README, so github will stop complaining to me.
33

44

55
h1. Tcsh2Bash
66

77
This application will read in a tcsh script and try to output the bash equivalent.
88

9+
h2. Motivation
10+
11+
Tcsh, an improvement on the C shell, is generally chosen as a default shell for many environments
12+
because of how it mimics the C language. However, there are many ambiguities and limitations
13+
with the language. Additionally, documentation on the language is sparse compared to bash.
14+
15+
This application is developed for people trying to migrate from tcsh to bash such as converting
16+
a cshrc to bashrc or for people who want to support bash on a tcsh driven system.
17+
918
h2. Requirements
1019

11-
Ruby "1.9.2":http://www.ruby-lang.org/en/downloads/ (an older version may work, not sure)
20+
Ruby "1.9.2":http://www.ruby-lang.org/en/downloads/ (older versions probably work, this is just the one I use)
1221
"RubyGems":http://rubygems.org/pages/download
1322

1423
I recommend installing both with "rvm":http://rvm.beginrescueend.com/rvm/install/
@@ -25,3 +34,28 @@ Run it as follows
2534

2635
* Output to standard out: @./tcsh2bash --infile cshrc@
2736
* Output to a file: @./tcsh2bash --infile cshrc --outfile bashrc@
37+
38+
h3. Sample
39+
40+
Input
41+
42+
pre. alias hello goodbye
43+
setenv editor vim
44+
set p=d
45+
q243aca 0w3
46+
47+
Output
48+
49+
pre. alias hello=goodbye
50+
export editor=vim
51+
p=d
52+
#######################
53+
# Unable to parse: q243aca 0w3
54+
#######################
55+
56+
h2. Additional Notes
57+
58+
There are no guarantees that the bash output produces the same logic as the tcsh script so please
59+
review the changes especially if using this in a production environment.
60+
Also, this application is not a mind reader. If you feed it a malformed tcsh script,
61+
it doesn't make any "logical" guess at what you meant.

lib/tcsh2bash/nodes.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
require 'treetop'
22

33
require File.dirname(__FILE__) + '/nodes/tcsh'
4+
require File.dirname(__FILE__) + '/nodes/conditional'
45
require File.dirname(__FILE__) + '/nodes/assignment'
56
require File.dirname(__FILE__) + '/nodes/boolean'
67
require File.dirname(__FILE__) + '/nodes/operators'

lib/tcsh2bash/nodes/conditional.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
module Tcsh2Bash
2+
class IfOneLine < Treetop::Runtime::SyntaxNode
3+
def to_bash
4+
if_opening.to_bash + " ; then " + command.to_bash + " ; fi"
5+
end
6+
end
7+
8+
class IfMultiLine < Treetop::Runtime::SyntaxNode
9+
def to_bash
10+
if_opening.to_bash + "\nthen\n" + commands.to_bash + "\nfi"
11+
end
12+
end
13+
14+
class IfOpening < Treetop::Runtime::SyntaxNode
15+
def to_bash
16+
"if " + paren_bool_expr.to_bash
17+
end
18+
end
19+
20+
end

lib/tcsh2bash/parsers.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
require 'treetop'
22

3+
require File.dirname(__FILE__) + '/parsers/tokens'
34
require File.dirname(__FILE__) + '/parsers/symbols'
45
require File.dirname(__FILE__) + '/parsers/operators'
56
require File.dirname(__FILE__) + '/parsers/boolean'

lib/tcsh2bash/parsers/conditional.treetop

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,34 @@ module Tcsh2Bash
1212
# if_one_line
1313
#end
1414

15+
rule if_statement
16+
if_multi_line / if_one_line
17+
end
18+
19+
rule if_multi_line
20+
if_opening 'then' newline commands newline 'endif' <IfMultiLine>
21+
end
22+
1523
rule if_one_line
16-
'if' space* open_paren paren_bool_expr close_paren space* stmt:(assignment / anything) {
24+
if_opening command <IfOneLine>
25+
end
26+
27+
rule if_opening
28+
'if' space* paren_bool_expr space* <IfOpening>
29+
end
30+
31+
rule commands
32+
command (newline command)*
33+
end
34+
35+
rule command
36+
assignment / any_command
37+
end
38+
39+
rule any_command
40+
(!(newline / eof) .)* {
1741
def to_bash
18-
"if " + paren_bool_expr.to_bash + "\nthen\n " + stmt.to_bash + "\nfi"
42+
text_value
1943
end
2044
}
2145
end

lib/tcsh2bash/parsers/symbols.treetop

Lines changed: 14 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,38 @@
11
module Tcsh2Bash
22
grammar Symbols
3+
include Tokens
34

4-
# @todo - this works for double quoted strings,
5-
# should be able to use this with single quoted strings
65
rule string
7-
'"' (!'"' . / '\"')* '"'
6+
single_quoted_string / double_quoted_string
87
end
98

10-
rule variable_ref
11-
dollar variable
9+
rule double_quoted_string
10+
'"' [^"]* '"'
1211
end
1312

14-
rule variable
15-
[a-zA-Z_] value*
13+
rule single_quoted_string
14+
"'" [^']* "'"
1615
end
1716

18-
rule value
19-
[\w]+
17+
rule backtick_string
18+
backtick string backtick
2019
end
2120

22-
rule open_paren
23-
'('
24-
end
25-
26-
rule close_paren
27-
')'
28-
end
29-
30-
rule quote
31-
"'" / '"' / '`'
32-
end
33-
34-
rule dollar
35-
'$'
36-
end
37-
38-
rule number
39-
[0-9] [0-9]*
21+
rule variable_ref
22+
dollar variable
4023
end
4124

42-
43-
rule newline
44-
[\n]
25+
rule variable
26+
[a-zA-Z_] value*
4527
end
4628

47-
rule space
48-
[ \t]
29+
rule value
30+
[\w]+
4931
end
5032

5133
rule white
5234
[ \t\n\r\f]
5335
end
5436

55-
rule eof
56-
!.
57-
end
58-
59-
rule anything
60-
.* {
61-
def to_bash
62-
text_value
63-
end
64-
}
65-
end
66-
6737
end
6838
end

lib/tcsh2bash/parsers/tokens.treetop

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
module Tcsh2Bash
2+
grammar Tokens
3+
4+
rule single_quote
5+
"'"
6+
end
7+
8+
rule double_quote
9+
"\""
10+
end
11+
12+
rule backtick
13+
"`"
14+
end
15+
16+
rule open_paren
17+
"("
18+
end
19+
20+
rule close_paren
21+
")"
22+
end
23+
24+
rule dollar
25+
"$"
26+
end
27+
28+
rule number
29+
[0-9] [0-9]*
30+
end
31+
32+
rule newline
33+
"\n"
34+
end
35+
36+
rule space
37+
[ \t]
38+
end
39+
40+
rule eof
41+
!.
42+
end
43+
end
44+
end

spec/parsers/conditional_parser_spec.rb

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,29 +9,40 @@ module Tcsh2Bash
99
describe "one line if statement" do
1010
it "should convert it a one line if statement to bash" do
1111

12-
output = <<EOF
13-
if [ $foo == "foo" ]
14-
then
15-
echo "Hello world!"
16-
fi
17-
EOF
18-
output.strip!
12+
output = <<IF_ONE_LINE.strip
13+
if [ $foo == "foo" ] ; then echo "Hello world!" ; fi
14+
IF_ONE_LINE
1915

2016
convert_to_bash('if ($foo == "foo") echo "Hello world!"').should == output
2117
end
2218

2319
it "should convert assignments when possible" do
24-
output = <<EOF
25-
if [ $foo -gt 2 ]
26-
then
27-
alias foo=bar
28-
fi
29-
EOF
30-
output.strip!
20+
21+
output = <<IF_ONE_LINE.strip
22+
if [ $foo -gt 2 ] ; then alias foo=bar ; fi
23+
IF_ONE_LINE
3124

3225
convert_to_bash('if ($foo > 2) alias foo bar').should == output
3326
end
3427
end
3528

29+
describe "multi line if statement" do
30+
it "should convert a multiline statement to bash" do
31+
32+
input = <<INPUT.strip
33+
if ($foo == 'foo') then
34+
echo 'Hello world!'
35+
endif
36+
INPUT
37+
38+
output = <<OUTPUT.strip
39+
if [ $foo == 'foo' ]
40+
then
41+
echo 'Hello world!'
42+
fi
43+
OUTPUT
44+
convert_to_bash(input).should == output
45+
end
46+
end
3647
end
3748
end

spec/parsers/symbols_parser_spec.rb

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
require 'spec_helper'
2+
3+
module Tcsh2Bash
4+
describe SymbolsParser do
5+
6+
before :each do
7+
@parser = SymbolsParser.new
8+
end
9+
10+
describe 'strings' do
11+
it 'should parse double quoted string' do
12+
parse('"hello world"').should_not be_nil
13+
end
14+
15+
it 'should parse single quoted strings' do
16+
parse("'hello'").should_not be_nil
17+
end
18+
19+
describe 'mixed quoted string' do
20+
it 'should parse single quotes on the outside' do
21+
22+
output = <<MIXED
23+
'Hello "World"'
24+
MIXED
25+
parse(output).should_not be_nil
26+
end
27+
28+
it 'should parse double quotes on the outside' do
29+
output = <<MIXED
30+
"Hello 'World'"
31+
MIXED
32+
parse(output).should_not be_nil
33+
end
34+
end
35+
end
36+
end
37+
end

0 commit comments

Comments
 (0)