LoginSignup
10
8

More than 5 years have passed since last update.

SCSSでBrainf*ckインタプリタ

Posted at

SASS、SCSSの勉強に作ってみました。実行環境によって動作が違って大変でした……。

制作過程

まず、文字列のn文字目の文字を返す関数を作ります。環境によっては動かなかったりするので、色々調整します。

@function str-nth($str, $num) {
  @return str-slice($str, $num, $num);
  // 動かない場合1
  @return str-slice($str, $num, $num - str-length($str));
  // 動かない場合2
  @return str-slice(str-slice($str, $num - 1, $num), 2, 3);
}

次に、10進数を16進数に変換する関数を作ります。

@function dec2hex($num) {
  @if ($num == 0) {
    @return "0";
  }
  $digit: "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f";
  $out: "";
  @while $num > 0 {
    $hex: $num % 16;
    $out: nth($digit, $hex + 1) + $out;
    $num: ($num - $hex) / 16;
  }
  @return $out;
}

これを何に使うかというと、Unicodeのコードポイントで表した文字列を返す関数を作るためです。

@function char($codepoint) {
  @return unquote("\\") + dec2hex($codepoint);
}

そして、関数本体を作ります。


@function bf($src) {
  // 変数宣言
  $array: (0, 0);  // 配列。(0)だけだとリスト扱いされない場合がある
  $p: 1; // ポインタ
  $i: 1; // ソースコードの何文字目か
  $out: unquote(""); // 出力結果。「"」が付かない文字列にする

  // 1文字ずつループ
  @while $i <= str-length($src) {
    $c: str-nth($src, $i);
    @if $c == ">" {
      $p: $p + 1;
      @if $p > length($array) {
        $array: append($array, 0); // ポインタが端を超えたら配列を増やす
      }
    }
    @else if $c == "<" {
      $p: $p - 1;
      @if $p < 1 {
        @return "Error!"; // ポインタが負になったらエラー
      }
    }
    @else if $c == "+" {
      $array: set-nth($array, $p, (nth($array, $p) + 1) % 256);
    }
    @else if $c == "-" {
      $array: set-nth($array, $p, (nth($array, $p) + 255) % 256);
    }
    @else if $c == "." {
      $out: $out + char(nth($array, $p));
    }
    @else if $c == "," {
      // 入力の実装はなし
    }
    @else if $c == "[" {
      @if nth($array, $p) == 0 {
        $b: 1; // カッコの対応を数える
        @while $b != 0 {
          $i: $i + 1;
          @if $i > str-length($src) {
            @return "Error!"; // 正しく対応していなかったらエラー
          }
          @else if str-nth($src, $i) == "[" {
            $b: $b + 1;
          }
          @else if str-nth($src, $i) == "]" {
            $b: $b - 1;
          }
        }
      }
    } @else if $c == "]" {
      @if nth($array, $p) != 0 {
        $b: -1; // 対応するカッコを数える
        @while $b != 0 {
          $i: $i - 1;
          @if $i < 1 {
            @return "Error!"; // 正しく対応していなかったらエラー
          }
          @else if str-nth($src, $i) == "[" {
            $b: $b + 1;
          }
          @else if str-nth($src, $i) == "]" {
            $b: $b - 1;
          }
        }
      }
    }
    $i: $i + 1;
  }
  // クオートで囲んで返す
  @return unquote("\"") + $out + unquote("\"");
}

表示してみます。

$helloworld: "+++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.+++++++..+++.>-.------------.<++++++++.--------.+++.------.--------.>+.";

#log::before {
  content: bf($helloworld);
}
コンパイル結果
#output::before {
  content: "\48\65\6c\6c\6f\2c\20\77\6f\72\6c\64\21";
}
HTML
<div id="output"></div>
表示結果
Hello, world!

SASS、SCSSはチューリング完全なんですね。

実行結果

10
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
8