α置換
Posted feedbacks - C#
Cのソースを変換します。
1文字ずつ結構まじめに解析してます。
お題のソースの変換ができてることを確認しました。
一番外側の変数しか変換しないという仕様を満たすのがしんどかったです。
よーく見ると実はバグで動いてたりするのは内緒。(正規表現のあたり)
1文字ずつ結構まじめに解析してます。
お題のソースの変換ができてることを確認しました。
一番外側の変数しか変換しないという仕様を満たすのがしんどかったです。
よーく見ると実はバグで動いてたりするのは内緒。(正規表現のあたり)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
class AlphaReader {
public bool IsDebug = false;
void DBG(String s, params Object[] args) {
if (!IsDebug) return;
Console.WriteLine(s, args);
}
TextReader input;
String before; //変換前文字列
String after; //変換後文字列
enum State { //状態
Global, Func, Struct, //グローバル, 関数定義, 構造体(共用体・列挙体)
Block, Name, Comment, InStr //ブロック, 識別子, コメント, 文字列
}
String IdDelimiter = "\t (){};,=+-*/%&|^!?"; //識別子分離文字
Stack<State> state; //現在のReaderの状態
int targetDepth; //変換対象のスコープ(stateの深さ)
int targetHideDepth; //変換対照が再定義された深さ
//コンストラクタ
public AlphaReader(TextReader input,
String before, String after) {
this.input = input;
this.before = before;
this.after = after;
this.state = new Stack<State>();
this.state.Push(State.Global);
this.targetDepth = int.MaxValue;
this.targetHideDepth = int.MaxValue;
}
//行を読み込んで変換処理するメソッド
public String ReadLine() {
String strIn = this.input.ReadLine();
if (strIn == null) {
return null;
}
DBG("## [{0}]", strIn);
StringBuilder buf = new StringBuilder(); //バッファ
StringBuilder name = new StringBuilder(); //識別子バッファ
/* 変数宣言の判定 */
/* この判定は、変数宣言と演算が別の行にわかれていること、
および、変数宣言が比較的シンプルなことを前提としています。 */
String decVar = @".*(\w+|(struct|union)\s+\w+)(\s+[^;,]+,)*\s+"
+ before + @"\s*[=,;\)].*"; //型+(変数, ...)+変換前文字列
bool hasDecVar = false;
if ((new Regex(decVar)).IsMatch(strIn)) {
DBG("## 変数宣言発見");
hasDecVar = true;
}
/* 行を1文字ずつ解析 */
for (int pos = 0; pos < strIn.Length; pos++) {
State st = this.state.Peek();
char c = strIn[pos];
String cs = strIn.Substring(pos);
DBG("## pos={0} c={1} state={2} depth={3}", pos, c, st.ToString(), state.Count);
switch (st) {
case State.InStr: //文字列リテラルの中
if (c == '\\') {
buf.Append(c);
if (++pos < strIn.Length) {
buf.Append(strIn[pos]);
}
} else if (c == '"') {
buf.Append(c);
this.state.Pop();
}
break;
case State.Comment: //コメントの中
buf.Append(c);
if (cs.StartsWith("*/")) {
buf.Append(strIn[++pos]);
this.state.Pop();
}
break;
case State.Name: //識別子の中
if (IdDelimiter.IndexOf(c) < 0) {
name.Append(c); //識別子続行
} else if (cs.StartsWith("->")) {
name.Append("->"); //識別子続行
pos++;
} else {
//識別子を抽出
String id = name.ToString();
this.state.Pop();
st = this.state.Peek();
switch (st) {
case State.Struct: //構造体の中は変換対象外
buf.Append(id);
break;
default: //変換対象
if (hasDecVar && id == this.before) { //変数宣言
if (this.state.Count < this.targetDepth) { //新たに宣言の場合
this.targetDepth = this.state.Count; //targetDepthをセット
} else if (this.state.Count < this.targetHideDepth
&& this.targetDepth < this.state.Count) { //再宣言した場合
this.targetHideDepth = this.state.Count; //targetHideDepthをセット
}
DBG("## set targetDepth:{0} hideDepth:{1}", targetDepth, targetHideDepth);
}
if (this.targetDepth <= this.state.Count
&& this.state.Count < this.targetHideDepth) {
//変換対象スコープの場合
if (id == this.before) {
buf.Append(this.after);
} else if ((new Regex(this.before + @"[\.\-]")).IsMatch(id)) {
//変換対象変数のメンバを参照してる場合
buf.Append(this.after);
buf.Append(id.Substring(this.before.Length));
} else {
buf.Append(id); //変換なし
}
} else {
buf.Append(id); //変換なし
}
break;
}
buf.Append(c);
if (st == State.Global && c == '(') { //関数宣言の場合
this.state.Push(State.Func);
}
name = new StringBuilder();
}
break;
default: //その他の状態
if (cs.StartsWith("/*")) { //コメント開始
buf.Append("/*");
pos++;
this.state.Push(State.Comment);
} else if (c == '"') { //文字列開始
buf.Append(c);
this.state.Push(State.InStr);
} else if (IdDelimiter.IndexOf(c) >= 0) { //識別子外文字
buf.Append(c);
if (c == '{') {
if (st != State.Struct) {
this.state.Push(State.Block);
}
} else if (c == '(') {
if (st == State.Global) {
this.state.Push(State.Func);
}
} else if (c == '}') {
if (st == State.Block) {
this.state.Pop();
if (this.state.Peek() == State.Func) {
this.state.Pop();
}
} else if (st == State.Struct) {
this.state.Pop();
}
if (this.state.Count < this.targetDepth)
this.targetDepth = int.MaxValue;
if (this.state.Count < this.targetHideDepth)
this.targetHideDepth = int.MaxValue;
DBG("## unset targetDepth:{0} hideDepth:{1}", targetDepth, targetHideDepth);
} else if (c == ';') {
if (st == State.Func) {
this.state.Pop();
}
}
} else if (cs.StartsWith("struct ") //構造体・共用体・列挙体のブロック内は
|| cs.StartsWith("union ") //変換を行わない
|| cs.StartsWith("enum ")) {
int index = cs.IndexOf(" ");
pos += index;
name.Append(cs.Substring(0, index + 1));
this.state.Push(State.Struct);
} else { //識別子開始
name.Append(c);
this.state.Push(State.Name);
}
break;
}
}
if (name.Length > 0) {
buf.Append(name.ToString());
if (this.state.Peek() == State.Name) {
this.state.Pop();
}
}
return buf.ToString();
}
}
class Driver {
public static int Main(String[] args) {
if (args.Length < 2) {
Console.WriteLine("alpha.exe before after [debug]");
return -1;
}
AlphaReader ar = new AlphaReader(
Console.In, args[0], args[1]);
if (args.Length >= 3 && args[2] == "debug") {
ar.IsDebug = true;
}
String line;
while ((line = ar.ReadLine()) != null) {
Console.WriteLine(line);
}
return 0;
}
}
|

gandalf #6153() Rating-2/6=-0.33
標準入力から与えられたソースコードの変数名 を置換するプログラムを作ってください。 最近はリファクタリングツールなどの普及でこ のような需要は少ないかと思われますが、viな ど貧弱なエディタを使っているときに困る のが変数名の置換です。さすがに以下の例のよ うなプログラムは例としてしか書きませんが、 置換しようとしている変数名と同じ綴りの他の ものがプログラム中に出てくることはまれにあ ります。そこで、与えられたソースコードに現 れる変数だけを指定された名前に置換してくだ さい。 置換対象となるソースコードと使用言語は同じ ものを使ってください。与えられるソースコー ドは、完全なコンパイル単位、もしくはパース して意味が通る範囲のものどちらであってもか まいません。後者の場合、一番外側の変数だけ 置換できるようにしてください。 C言語での解答例をつけたかったのですが、と ても難しかったためまだ作成できていません。 ご容赦ください。 例 $ cat a.c /* a */ int foo() { struct a {int a;} a; #if FOO a.a = 1; #endif { int a; } return 0; } $ alpha -DFOO=1 b a < a.c /* a */ int foo() { struct a {int a;} b; #if FOO b.a = 1; #endif { int a; } return 0; }[ reply ]