So-net無料ブログ作成

ColdFire V1 - ラインエディタらしきもの [ColdFire (ColdeFire) V1]このエントリーを含むはてなブックマーク#

シリアル・インターフェースを拡張してライン・エディタを作りました。

ソースコード

/*
 * $Source: /mnt/cvs/rep/CW/CFQE20/Sources/main.c,v $
 * $Id: main.c,v 1.3 2008/02/03 02:10:58 noritan Exp $
 */
#include <hidef.h> /* for EnableInterrupts macro */
#include "derivative.h" /* include peripheral declarations */

// 定数の宣言
#define   BUF_LENGTH  (72)
#define   TEXT_LENGTH (4096)

// 大域変数の宣言
char lineBuf[BUF_LENGTH];   // ラインバッファ
char *linePoint;            // ラインポインタ
char textBuf[TEXT_LENGTH];  // テキスト領域
char *textEnd;              // テキスト終端ポインタ


// お便利関数の宣言
int     getc(void);
void    putc(int ch);
void    puts(const char *s);
char    *getLine(void);
int     getNumber(void);
void    insertLine(int lineno, char *line);
void    removeLineByNo(int lineno);
char    *findLine(int lineno);
void    listLines(void);
void    putNumber(int lineno);


// メイン関数
void main(void) {
  int       nLine;        // 入力した数値
  
  // SOPT1を設定する
  // COPは停止させる
  SOPT1 = 0
    | SOPT1_WAITE_MASK    // WAIT命令を許可
    | SOPT1_RSTOPE_MASK   // RSTO*出力を使う
    | SOPT1_BKGDPE_MASK   // BKGDポートを使う
    | SOPT1_RSTPE_MASK ;  // RESET*入力を使う

  // ICSを設定する
  //   REFCLK = 31,250Hz
  //   DCO    = 48,000,000Hz
  //   BUSCLK = DCO / 2 = 24,000,000Hz
  ICSTRM          = NVICSTRM;
  ICSSC_FTRIM     = NVFTRIM_FTRIM;
  ICSC2_BDIV      = 0;  // BDIV 1/1
  ICSSC_DRST_DRS  = 2;  // FLL x1536
  
  // SCI1を設定する
  //   BAUD   = 115200
  //   BR     = BUSCLK / BAUD / 16 = 13
  SCI1BD_SBR = 13;      // クロック分周比
  SCI1C2_TE  = 1;       // 送信機能を有効にする
  SCI1C2_RE  = 1;       // 受信機能を有効にする
  
  // テキストエリアの初期化
  textBuf[0] = -1;
  textEnd = &textBuf[0];

  EnableInterrupts; /* enable interrupts */
  /* include your code here */

  for(;;) {
    puts("\n*READY");         // プロンプトを表示する
    linePoint = getLine();    // 一行受信する
    nLine = getNumber();      // 数値を取り出す
    if (nLine < 0) {          // 数値がない時には
      puts("*ERROR*");        // エラー表示
    } else if (nLine == 0) {  // 数値が0の時には、
      listLines();            // リストを表示する
    } else if (!*linePoint) { // 数値だけの時には、
      removeLineByNo(nLine);  // 削除
    } else {                  // それ以外は、
      insertLine(nLine, linePoint); // 挿入処理
    } 
  } /* loop forever */
  /* please make sure that you never leave main */
}


// char *getLine(void) : 
//   一行受信ルーチン
//   ラインバッファの先頭を返す
char *getLine(void) {
  char  *p;             // バッファポインタ
  char  c;              // 一文字バッファ
  
  for (;;) {
    putc(':');          // プロンプト出力
    p = lineBuf;        // バッファの先頭を指示
    for (;;) {
      c = (char)getc(); // 一文字受け取り
      if (c == 8) {
        // Back Spaceの処理
        putc(c);        // カーソルをもどす
        p--;            // 一文字戻す
        // ポインタがバッファの先頭に達したら、
        // プロンプト出力からやりなおす。
        if (p < lineBuf) break;
      } else if (c == '\n') {
        // Enterの処理
        putc(c);        // 改行出力
        *p = 0;         // 文字列末文字を書き込む
        return lineBuf; // バッファへのポインタを返す
      } else if (c < ' ') {
        // その他のコントロール文字
        continue;       // 単に無視する
      } else if (c == 127) {
        // DELETE文字の処理
        putc('\n');     // 改行出力
        break;          // プロンプト出力からやりなおす
      } else {
        // 通常の文字の処理
        putc(c);        // エコーバック
        *p++ = c;       // バッファに書き込む
        // バッファを使い切ったら、
        if (p >= &lineBuf[BUF_LENGTH-1]) {
          putc('\n');   // 改行出力
          break;        // プロンプト出力からやりなおす
        }
      }
    }
  }
}

// int getc(void) : 
//   一文字受信ルーチン
int getc(void) {
  int ch;               // 文字バッファ
  
  // 受信バッファがいっぱいになるのを待つ
  while (!SCI1S1_RDRF) {
    // Do nothing
  }
  ch = SCI1D;           // 一文字受け取る
  if (ch == '\r') {     // Enterキーは、
    ch = '\n';          // 行末文字に変換する
  }
  return ch;            // 受け取った文字を返す
}


// void putc(int ch) : 
//   一文字送信ルーチン
void putc(int ch) {
  if (ch == '\n') {     // 行末文字の前にCRを付ける
    // 送信バッファが空くのを待つ
    while (!SCI1S1_TDRE) {
      // Do nothing
    }
    SCI1D = '\r';       // SCIにCR文字を送信する
  }
  // 送信バッファが空くのを待つ
  while (!SCI1S1_TDRE) {
    // Do nothing
  }
  SCI1D = (byte)ch;     // SCIに一文字送信する
}


// void puts(const char *s) : 
//   文字列送信ルーチン
void puts(const char *s) {
  while (*s) {          // 文字列末でなければ、
    putc(*s++);         // 一文字送信する
  }
}


// int getNumber(void) : 
//   ラインポインタの位置から数値を取り出す
int getNumber(void) {
  int n = 0;                    // 数値
  
  if (!isdigit(*linePoint)) {   // 数字がなければ、 
    return -1;                  // -1 を返す
  }
  while (isdigit(*linePoint)) { // 数値の十進変換
    n = n * 10 + ((*linePoint) - '0');
    linePoint++;
  }
  return n;                     // 数値を返す
}


// void putNumber(int n) : 
//   数値の表示 - ZERO SUPPRESS は省略。
void putNumber(int n) {
  int m = 10000;          // 着目する桁
  
  while (m > 0) {           // 一の位まで表示する
    putc((n / m) + '0');    // 着目桁の表示
    n %= m;                 // 残りの桁の部分
    m /= 10;                // 着目桁の移動
  }
}

// int getLineNo(line)
//   行番号を取り出す
int getLineNo(char *line) {
   return *((word *)line);
}


// char *nextLine(line)
//   次の行にスキップする
char *nextLine(char *line) {
  char *s;
  for (s = line + 2; *s++; ) {
  }
  return s;
}


// void removeLine(line)
//   ポインタで指示する行を削除する。
void removeLine(char *line) {
  const char *s;
  char *p;
  
  // 削除
  p = (char *)line;
  s = nextLine(line);
  while (s < textEnd) {
    *p++ = *s++;
  }
  *p = *s;
  textEnd = p;
}


// char *findLine(lineno)
//   行をさがす
char *findLine(int lineno) {
  char *s;

  // 行を探す
  s = textBuf;
  for (;;) {
    // テキスト末端に到達    
    if (s >= textEnd) {
      break;
    }
    // 行番号を検証。
    if (getLineNo(s) >= lineno) {
      // 行位置発見
      break;
    }
    // 次の行にスキップ
    s = nextLine(s);
  }
  return s;
}


// void insertLine(lineno, line) : 
//   行挿入
void insertLine(int lineno, char *line) {
  char *s;
  char *p;
  char *pInsert;
  int length;
  
  // 挿入候補位置を探す
  pInsert = findLine(lineno);
  // 行番号を検証。
  if (getLineNo(pInsert) == lineno) {
    // 置換
    // 置換後の文字数差を計算する。
    length = strlen(line) - strlen(&pInsert[2]);
    if (length > 0) {
      // 場所を拡張して挿入する
      if (textEnd - textBuf + length > TEXT_LENGTH) {
        // バッファ・オーバフロー
        pInsert = 0;
      } else {
        // 拡張
        p = textEnd + length;
        s = textEnd;
        while (s >= pInsert) {
          *p-- = *s--;
        }
        textEnd += length;
      }
    } else if (length < 0) {
      // 場所を縮小して挿入する
      s = nextLine(pInsert);
      p = s + length;
      while (s <= textEnd) {
        *p++ = *s++;
      }
      textEnd += length;
    } else {
      // 上書き
    }
  } else {
    // バッファ・チェック
    length = strlen(line) + 3;
    if (textEnd - textBuf + length > TEXT_LENGTH) {
      // バッファ・オーバフロー
      pInsert = 0;
    } else {      
      // 丸ごと拡張して挿入する
      p = textEnd + length;
      s = textEnd;
      while (s >= pInsert) {
        *p-- = *s--;
      }
      textEnd += length;
    }
  }
  
  // 挿入位置が見つからなければ、何もしない。
  if (!pInsert) {
    return;
  }

  // 挿入開始
  p = pInsert;
  // 行番号を書き込む
  *((word *)p) = (word)lineno;
  p += 2;
  // 本体を書き込む
  for (s = line; *s; ) {
    *p++ = *s++;
  }
  // 行末を書き込む
  *p++ = 0;
}


// void removeLineByNo(lineno)
//   与えられた行番号の行を削除する
void removeLineByNo(int lineno) {
  char *s;
  
  // 削除位置を探す
  s = findLine(lineno);
  // 行番号部分を比較する
  if (getLineNo(s) == lineno) {
    removeLine(s);
  }
}


// void listLines(void)
//   リスト出力
void listLines(void) {
  char *p;
  
  // テキスト終端まで表示する。
  for (p = textBuf; p < textEnd; ) {
    // 行番号表示
    putNumber(getLineNo(p));
    p += 2;
    // 本文表示
    while (*p) {
      putc(*p++);
    }
    putc('\n');
    // 行末をスキップする
    p++;
  }
}

使ってみよう

このラインエディタは、昔懐かしいインターフェースで構成されています。

*READY:10 i=1,100

*READY:0
00010 i=1,100

*READY:20   ?=i

*READY:30 @=i+1

*READY:40 #=-1

*READY:0
00010 i=1,100
00020   ?=i
00030 @=i+1
00040 #=-1

*READY:20

*READY:0
00010 i=1,100
00030 @=i+1
00040 #=-1

*READY:20   ??=i

*READY:0
00010 i=1,100
00020   ??=i
00030 @=i+1
00040 #=-1

*READY:20   ?$=i

*READY:0
00010 i=1,100
00020   ?$=i
00030 @=i+1
00040 #=-1

*READY:20   ?=i

*READY:0
00010 i=1,100
00020   ?=i
00030 @=i+1
00040 #=-1

*READY:???=i

*READY:0
00010 i=1,100
00020   ???=i
00030 @=i+1
00040 #=-1

*READY:

putc/getcの実装時には、DEMOQE128を使いましたが、 それ以降のプログラムを作るのに、実機は使用していません。 すべて、CodeWarriorのシミュレータだけを使っています。

次は、インタプリタだな。


nice!(0)  コメント(0)  トラックバック(0)  このエントリーを含むはてなブックマーク#

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

トラックバックの受付は締め切りました

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。