アセンブリのソートについての質問

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ビルド

アセンブリのソートについての質問

#1

投稿記事 by ビルド » 6年前

今までのやつは沢山あり、ややこしいので、新しい質問項目にしました。
そこで、今回はアセンブリの問題に取り組んでいて、仕様は
キーボードから入力したデータを昇順にソートして小さい順に表示する sml2のアセンブラプログラム ex01.txtを作成せよ。ただし,配列に入力後,配列をソートする部分は関数とし,prec, call, dclv, rtrn, stof, lodf を用いること。

今わかる範囲でコードを書いてみました。
ソートするプログラム

コード:

0, nop, -1
1, read, -1
2, store, 0
3, read, -1
4, store, 1
5, read, -1
6, store, 2
7, read, -1
8, store, 3
9, read, -1
10, store, 4
11, read, -1
12, store, 5
13, read, -1
14, store, 6
15, ldi, 7
16, store, 15
17, load, 6
18, load, 5
19, opr2, gtr
20, cjump, 27
21, load, 6
22, store, 16
23, load, 5
24, store, 6
25, load, 16
26, store, 5
27, load, 5
28, load, 4
29, opr2, gtr
30, cjump, 37
31, load, 5
32, store, 16
33, load, 4
34, store, 5
35, load, 16
36, store, 4
37, load, 4
38, load, 3
39, opr2, gtr
40, cjump, 47
41, load, 4
42, store, 16
43, load, 3
44, store, 4
45, load, 16
46, store, 3
47, load, 3
48, load, 2
49, opr2, gtr
59, cjump, 57
51, load, 3
52, store, 16
53, load, 2
54, store, 3
55, load, 16
56, store, 2
57, load, 2
58, load, 1
59, opr2, gtr
60, cjump, 67
61, load, 2
62, store, 16
63, load, 1
64, store, 2
65, load, 16
66, store, 1
67, load, 1
68, load, 0
69, opr2, gtr
70, cjump, 77
71, load, 1
72, store, 16
73, load, 0
74, store, 1
75, load, 16
76, store, 0
77, load, 15
78, ldi, 1
79, opr2, sub
80, store, 15
81, load, 15
82, ldi, 0
83, opr2, gtr
84, cjump, 86
85, jump, 17
86, load, 0
87, print, -1
88, load, 1
89, print, -1
90, load, 2
91, print, -1
92, load, 3
93, print, -1
94, load, 4
95, print, -1
96, load, 5
97, print, -1
98, load, 6
99, print, -1
100, halt, -1
prec, call, dclv, rtrn, stof, lodf についてよくわかりません。多分わたしとしてはどこかの番地に付け加えいいと思う。

コード:

0	nop	なし	-1	"(no operation)operand無し(形式的に -1).no operation; なにもせずに pcを1増やす(次の命令に進む).
"
1	ldi	なし	即値	(load immediate data)operandの即値をstackにpushし,pcを1増やす.
2	opr1	なし	"単項演算
識別子
(即値)"	"operandの即値が示す単項演算をstackに対して実施し,pcを1増やす.
単項演算の種類と意味については sml2_conf.h を参照せよ.
"
3	opr2	なし	"二項演算
識別子
(即値)"	"operandの即値が示す2項演算をstackに対して実施し,pcを1増やす.
2項演算の種類と意味については sml2_conf.hを参照せよ.
"
4	print	"なし
動作の変更有り"	"0以外→改行
0→改行しない"	"operandが0以外の時(とくに -1の時など),stack topの値を表示して改行する.pcを1増やす.
operandが0の時,stack topの値を表示するが改行しない.pcを1増やす.
いずれの場合でも popしない.従って,stack_ptrは変化しない.この変更に伴い,del命令(11)を導入した."
5	read	なし	-1	"operand無し(形式的に -1).キーボード入力をstackにpushし,pcを1増やす.
"
6	jump	なし	"insts 内
絶対番地
(即値)"	"pcの値をoperandの値(即値)とする.つまり,operandが示す番地(絶対番地)にジャンプする.
"
7	cjump	なし	"insts 内
絶対番地
(即値)"	"stack topの値が0(偽)の時,popしてjumpする.そうでない場合単にpopし,pcを1増やす. 
※1(真)でjumpではないので注意.
"
8	store	なし	"mem 内
絶対番地
(即値)"	"stack topの値をpopして,operand(即値)が示すmem領域の番地に格納し,pcを1増やす.
"
9	load	なし	"mem 内
絶対番地
(即値)"	"operand(即値)が示すmem領域の番地の値を stack にpushし,pcを1増やす.
"
10	halt	なし	-1	"operand無し(形式的に -1).実行を終了する.
"
11	"del
"	新規	-1	operand無し(形式的に -1).stack topをpopし,その値をstoreせず単に捨てる.pcを1増やす.
12	prec	新規	関数の引数の個数(arity)	"関数の呼び出しの準備をするために用いる.この命令は call命令とペアとなり,call命令の直前に実行されなければならない.①prec命令実行前の b_regの値を fstackにpush. ②関数処理終了後(rtrn命令実行後)のprogram counter (pc)の値(戻り番地という)をfstackにpush.③operand(即値)が示す arity個の実引数を stack からpopして fstack にコピーする※.④pcを1増やす.
※③のコピーの順序は stackに先に積まれたものが fstackにも先に積まれるようにする.このため,少なくともpopあるいはpushの一方はsml0で用意したものとは別に(block_pop()やblock_push()など)用意する必要がある.または,このデータ移動のための専用の関数(block_mv())を用意する."
13	call	新規	insts内の関数の開始番地	関数呼び出しに用いる.この命令は prec命令とペアとなり,prec命令の直後に実行されなければならない.pcをoperand(即値)の値に変更する.つまり次に実行する命令番地は関数の開始番地となる.現状では jump命令と全く同じ.
14	dclv	新規	局所変数の個数	operandで指定された個数分の局所変数の領域を fstack に確保し,pcを1増やす.確保した領域は 0クリアする.
15	rtrn	新規	-1	operand無し.形式的に -1.関数の呼び出しから復帰する.base registerの値や pcの値を fstackから復元する.fstack_ptrは関数呼び出し前の関数frameの最後のデータの場所を指すようになる.具体的にはつぎの3処理を順に行う.①fstack_ptr = b_reg-1 とする.②pc = fstack[b_reg+1] とする.③b_reg = fstack[b_reg] とする.
16	stof	新規	fstack内局所変位	stackを popして,popされた値を fstack に格納し,pcを1増やす.値の操作は具体的にはつぎのようになる.dをoperandの即値とするとき, stackをpopし,popされた値を fstack[b_reg+2+d]に格納する.dのことを局所変位(local displacement)という.
17	lodf	新規	fstack内局所変位	operand(即値)が示す番地の fstack の値を stack にpushし,pcを1増やす.値の操作は具体的にはつぎのようになる.dをoperandの即値とするとき, fstack[b_reg+2+d]にある値を stackに積む.dのことを局所変位(local displacement)という.
18	putch	printc	ascii文字コード(即値)	operand(asciiコードで1文字分,即値)を表示し,pcを1増やす.stackは参照しないので,popはしない.
19	val	新規	配列の先頭となる mem[]の番地	operandの値(array_base)にstack topの値(disp)を加えた値(mem_addr=array_base+disp)で示されるmem[]の番地に格納されている値(mem[mem_adr])をstack topに移動し,pcを1増やす.(stack topの値は上書きされて, mem[mem_adr]に等しくなる)stack_ptrは変化しない.
20	ass	新規	配列の先頭となる mem[]の番地	operandの値(array_base)にstack topの1つ下の値(disp = stack[stack_ptr - 1])を加えた値(mem_addr = array_base + disp)で示されるmem[]の番地(mem[mem_adr])に,stack topの値(v)を格納し,stack_ptrを2減らす.pcを1増やす.
21	assv	新規	配列の先頭となる mem[]の番地	operandの値(array_base)にstack topの1つ下の値(disp = stack[stack_ptr - 1])を加えた値(mem_addr = array_base + disp)で示されるmem[]の番地(mem[mem_adr])に,stack topの値(v)を格納し,さらに値(v)をstack topの一つ下(stack[stack_ptr - 1])に格納する.stack_ptrは 1減らす.※注:pcの増加数の違いを除けば,assvは ass命令を実行後,元stack topに在った値 vを再度pushすることに相当する.ただし,ass命令実行後には vは mem上にあり stack上には無くなっているので,assv命令を使用しない場合には,v自体を知っている,もしくは memの何処に格納したかを知っていることが必要である.
これが命令表記です。
実行は私がやります。だから、precなどについて詳しく解説をお願いします。(解説つき)

ビルド

Re: アセンブリのソートについての質問

#2

投稿記事 by ビルド » 6年前

補足で、
今わかる範囲の実行結果です。

コード:

$ ./sml2 ex.txt
   0:       0,       -1
   1:       5,       -1
   2:       8,        0
   3:       5,       -1
   4:       8,        1
   5:       5,       -1
   6:       8,        2
   7:       5,       -1
   8:       8,        3
   9:       5,       -1
  10:       8,        4
  11:       5,       -1
  12:       8,        5
  13:       5,       -1
  14:       8,        6
  15:       1,        7
  16:       8,       15
  17:       9,        6
  18:       9,        5
  19:    opr2,       23
  20:       7,       27
  21:       9,        6
  22:       8,       16
  23:       9,        5
  24:       8,        6
  25:       9,       16
  26:       8,        5
  27:       9,        5
  28:       9,        4
  29:    opr2,       23
  30:       7,       37
  31:       9,        5
  32:       8,       16
  33:       9,        4
  34:       8,        5
  35:       9,       16
  36:       8,        4
  37:       9,        4
  38:       9,        3
  39:    opr2,       23
  40:       7,       47
  41:       9,        4
  42:       8,       16
  43:       9,        3
  44:       8,        4
  45:       9,       16
  46:       8,        3
  47:       9,        3
  48:       9,        2
  49:    opr2,       23
  50:       0,        0
  51:       9,        3
  52:       8,       16
  53:       9,        2
  54:       8,        3
  55:       9,       16
  56:       8,        2
  57:       9,        2
  58:       9,        1
  59:    opr2,       23
  60:       7,       67
  61:       9,        2
  62:       8,       16
  63:       9,        1
  64:       8,        2
  65:       9,       16
  66:       8,        1
  67:       9,        1
  68:       9,        0
  69:    opr2,       23
  70:       7,       77
  71:       9,        1
  72:       8,       16
  73:       9,        0
  74:       8,        1
  75:       9,       16
  76:       8,        0
  77:       9,       15
  78:       1,        1
  79:    opr2,       11
  80:       8,       15
  81:       9,       15
  82:       1,        0
  83:    opr2,       23
  84:       7,       86
  85:       6,       17
  86:       9,        0
  87:       4,       -1
  88:       9,        1
  89:       4,       -1
  90:       9,        2
  91:       4,       -1
  92:       9,        3
  93:       4,       -1
  94:       9,        4
  95:       4,       -1
  96:       9,        5
  97:       4,       -1
  98:       9,        6
  99:       4,       -1
 100:      10,       -1
Executing program...
? 111
? 555
? 999
? 777
? 333
? 666
? 444
999
777
666
555
444
333
111
(debug): stack_ptr = 7; If non 0, something is WRONG!
Execution terminated.

かずま

Re: アセンブリのソートについての質問

#3

投稿記事 by かずま » 6年前

ビルド さんが書きました: 今までのやつは沢山あり、ややこしいので、新しい質問項目にしました。
何度も言っていますが、前の質問にリンクを張らないと、
初めてこの質問を読む人には何もわかりません。

リンクを張るのが嫌なら、sml2 とは何かとか、
命令セットとか、プロセッサのアーキテクチャを
すべて説明しないといけません。

アーキテクチャとは、内部構成がどうなっているかです。
コード用のメモリがあり、データ用のメモリがあり、
演算用のスタックがあり、関数呼び出しの引数や
ローカル変数を格納するフレームスタックがあるなどです。

前の質問は、
アセンブリ言語の配列のプログラムがわからないですが、
ここにある sml2 の処理系は、バグがあって val命令が正しく動きません。
prec, call dclv, rtrn, stof, lodf の実装もありません。

また、prec の説明も間違っていて、このままでは実装できません。

そこで、sml2 の処理系を私が勝手に作ってみました。

sml2.c

コード:

#include <stdio.h>
#include <stdlib.h> // exit
#include <string.h> // strtok, memcpy, memset

enum OP { nop, ldi, opr1, opr2, print, read, jump, cjump,
    store, load, halt, del, prec, call, dclv, rtrn,
    stof, lodf, putch, val, ass, assv };
const char *str_op[] = {
    "nop", "ldi", "opr1", "opr2", "print", "read", "jump", "cjump",
    "store", "load", "halt", "del", "prec", "call", "dclv", "rtrn",
    "stof", "lodf", "putch", "val", "ass", "assv"
};
const int n_op = sizeof(str_op) / sizeof(*str_op);

enum OPR { neg, not, add, sub, mul, dvd, mod, and, or, xor,
    less, lseq, gteq, gtr, equ, nteq };
const char *str_opr[] = {
    "neg", "not", "add", "sub", "mul", "dvd", "mod", "and", "or", "xor",
    "less", "lseq", "gteq", "gtr", "equ", "nteq"
};
const int n_opr = sizeof(str_opr) / sizeof(*str_opr);

typedef struct { int op; int operand; } Code;

Code code[512];
int mem[1024], stack[128], fstack[256], pc, sp, fsp, b_reg;

void error(const char *msg)
{
    printf("[pc:%d, sp:%d, fsp:%d] %s\n", pc, sp, fsp, msg);
    exit(1);
}

void push(int x)
{
    if (sp >= 128) error("stack overflow");
    stack[sp++] = x;
}

int pop(void)
{
    if (sp <= 0) error("stack empty");
    return stack[--sp];
}

void do_opr1(int x)
{
    int a = pop();
    switch (x) {
    case neg: push(-a); break;
    case not: push(~a); break;
    }
}

void do_opr2(int x)
{
    int b = pop(), a = pop();
    switch (x) {
    case add: push(a + b); break;
    case sub: push(a - b); break;
    case mul: push(a * b); break;
    case dvd: if (b == 0) error("zero divide");
              push(a / b); break;
    case mod: if (b == 0) error("zero divide");
              push(a % b); break;
    case and: push(a & b); break;
    case or:  push(a | b); break;
    case xor: push(a ^ b); break;
    case less: push(a <  b); break;
    case lseq: push(a <= b); break;
    case gteq: push(a >= b); break;
    case gtr:  push(a >  b); break;
    case equ:  push(a == b); break;
    case nteq: push(a != b); break;
    }
}

void do_read(void)
{
    int x;
    printf("? ");
    if (scanf("%d", &x) != 1) error("read failed");
    push(x);
}

void do_prec(int x)
{
    fstack[fsp+1] = b_reg;
    fstack[fsp+2] = pc + 1;
    b_reg = fsp + 1;
    memcpy(fstack+ (fsp + 3), stack + (sp - x), sizeof(int) * x);
    sp -= x;
    fsp += x;
}

void do_dclv(int x)
{
    memset(fstack + fsp, 0, sizeof(int) * x);
    fsp += x;
}

void do_rtrn(void)
{
    fsp = b_reg - 1;
    pc = fstack[b_reg + 1];
    b_reg = fstack[b_reg];
}

void execute(int a)
{
    pc = a;
    while (1){
        int operand = code[pc].operand;
        switch (code[pc++].op) {
        case nop   : break;
        case ldi   : push(operand); break;
        case opr1  : do_opr1(operand); break;
        case opr2  : do_opr2(operand); break; 
        case print : printf(operand & 1 ? " %d\n" : " %d", pop()); break;
        case read  : do_read(); break;
        case jump  : pc = operand; break;
        case cjump : if (pop() == 0) pc = operand; break;
        case store : mem[operand] = pop(); break;
        case load  : push(mem[operand]); break;
        case del   : pop(); break;
        case call  : pc = operand; break;
        case prec  : do_prec(operand); break;
        case dclv  : do_dclv(operand); break;
        case rtrn  : do_rtrn(); break;
        case stof  : fstack[b_reg + 2 + operand] = pop(); break;
        case lodf  : push(fstack[b_reg + 2 + operand]); break;
        case putch : putchar(operand); break;
        case val   : push(mem[operand + pop()]); break;
        case ass   : a = pop(); mem[operand + pop()] = a; break;
        case assv  : a = pop(); push(mem[operand + pop()] = a); break;
        case halt  : return;
        default: error("invalid op code");
        };
    }
}


int loader(const char *fname)
{
    FILE *fp = fopen(fname, "r");
    if (!fp) return printf("can't open %s\n", fname), -1;
    int ret = 0;
    char buf[256], *p;
    while (fgets(buf, sizeof buf, fp)) {
        char *addr = strtok(buf, " ,:\t\r\n");
        char *op  = strtok(NULL, " ,;\t\r\n");
        char *opr = strtok(NULL, " ,;\t\r\n");
        if (!addr || *addr == ';') continue;
        if (!op || !opr) { ret = 1; break; }
        int i, j, k = strtol(addr, &p, 10);
        if (p == addr) { ret = 2; break; }
        for (i = 0; i < n_op && strcmp(op, str_op[i]); i++) ;
        if (i == n_op) { ret = 3; break; }
        j = strtol(opr, &p, 10);
        if (p == opr) {
            for (j = 0; j < n_opr && strcmp(opr, str_opr[j]); j++) ;
            if (j == n_opr) { ret = 4; break; }
            printf("%4d:%8s %6s\n", k, str_op[i], str_opr[j]);
        }
        else
            printf("%4d:%8s %6d\n", k, str_op[i], j);
        code[k].op = i, code[k].operand = j;
    }
    fclose(fp);
    return ret;
}

int main(int argc, char *argv[])
{
    if (argc != 2) return printf("usage: %s file\n", argv[0]), 1;
    if (loader(argv[1])) return puts("load error"), 2;
    puts("Executing program...");
    execute(0);
    printf("[pc:%d, sp:%d, fsp:%d] Execution terminated\n", pc, sp, fsp);
}
test_call.txt

コード:

;    r = func(23, 48);
;    print(r);
;    halt();
;
;int func(int a, int b) {
;    int c;
;    c = a + b;
;    return c;
;}

0: ldi 23    ; 第1引数 23
1: ldi 48    ; 第2引数 48
2: prec 2    ; 引数の個数 2
3: call 8    ; アドレス 8 の関数を呼び出す
4: store 0   ; r = 返却値
5: load 0    ; 
6: print -1  ; print(r)
7: halt -1   ;
8: dclv 1    ; ローカル変数 1個 (c)
9: lodf 0    ; 第1引数 a
10: lodf 1   ; 第2引数 b
11; opr2 sub ; 引き算
12: stof 2   ; c = 演算結果
13: lodf 2   ; 返却値
14: rtrn -1  : 戻る
実行例

コード:

   0:  ldi    23
   1:  ldi    48
   2:  prec   2
   3:  call   8
   4:  store  0
   5:  load   0
   6:  print  -1
   7:  halt   -1
   8:  dclv   1
   9:  lodf   0
  10:  lodf   1
  11:  opr2   sub
  12:  stof   2
  13:  lodf   2
  14:  rtrn   -1
Executing program...
 -25
[pc:8, sp:0, fsp:0] Execution terminated
ビルド さんが書きました: 実行は私がやります。だから、precなどについて詳しく解説をお願いします。(解説つき)
上記の prec などを使ったプログラムを実行して、
それが正しいのかを、どうか教えてください。
解説はそれからします。

かずま

Re: アセンブリのソートについての質問

#4

投稿記事 by かずま » 6年前

すみません。sml2.c にバグありました。
98行目の
memset(fstack + fsp, 0, sizeof(int) * x); を
memset(fstack + fsp + 1, 0, sizeof(int) * x);
に訂正します。

かずま

Re: アセンブリのソートについての質問

#5

投稿記事 by かずま » 6年前

すみません。93行目も間違っていました。
今、動いている sml2.c は、次のものです。

コード:

#include <stdio.h>
#include <stdlib.h> // exit
#include <string.h> // strtok, memcpy, memset

enum OP { nop, ldi, opr1, opr2, print, read, jump, cjump,
    store, load, halt, del, prec, call, dclv, rtrn,
    stof, lodf, putch, val, ass, assv };
const char *str_op[] = {
    "nop", "ldi", "opr1", "opr2", "print", "read", "jump", "cjump",
    "store", "load", "halt", "del", "prec", "call", "dclv", "rtrn",
    "stof", "lodf", "putch", "val", "ass", "assv"
};
const int n_op = sizeof(str_op) / sizeof(*str_op);

enum OPR { neg, not, add, sub, mul, dvd, mod, and, or, xor,
    less, lseq, gteq, gtr, equ, nteq };
const char *str_opr[] = {
    "neg", "not", "add", "sub", "mul", "dvd", "mod", "and", "or", "xor",
    "less", "lseq", "gteq", "gtr", "equ", "nteq"
};
const int n_opr = sizeof(str_opr) / sizeof(*str_opr);

typedef struct { int op; int operand; } Code;

Code code[512];
int mem[1024], stack[128], fstack[256], pc, sp, fsp, b_reg;

void error(const char *msg)
{
    printf("[pc:%d, sp:%d, fsp:%d] %s\n", pc, sp, fsp, msg);
    exit(1);
}

void push(int x)
{
    if (sp >= 128) error("stack overflow");
    stack[sp++] = x;
}

int pop(void)
{
    if (sp <= 0) error("stack empty");
    return stack[--sp];
}

void do_opr1(int x)
{
    int a = pop();
    switch (x) {
    case neg: push(-a); break;
    case not: push(~a); break;
    }
}

void do_opr2(int x)
{
    int b = pop(), a = pop();
    switch (x) {
    case add: push(a + b); break;
    case sub: push(a - b); break;
    case mul: push(a * b); break;
    case dvd: if (b == 0) error("zero divide");
              push(a / b); break;
    case mod: if (b == 0) error("zero divide");
              push(a % b); break;
    case and: push(a & b); break;
    case or:  push(a | b); break;
    case xor: push(a ^ b); break;
    case less: push(a <  b); break;
    case lseq: push(a <= b); break;
    case gteq: push(a >= b); break;
    case gtr:  push(a >  b); break;
    case equ:  push(a == b); break;
    case nteq: push(a != b); break;
    }
}

void do_read(void)
{
    int x;
    printf("? ");
    if (scanf("%d", &x) != 1) error("read failed");
    push(x);
}

void do_prec(int x)
{
    fstack[fsp+1] = b_reg;
    fstack[fsp+2] = pc + 1;
    b_reg = fsp + 1;
    memcpy(fstack + (fsp + 3), stack + (sp - x), sizeof(int) * x);
    sp -= x;
    fsp += 2 + x;
}

void do_dclv(int x)
{
    memset(fstack + fsp + 1, 0, sizeof(int) * x);
    fsp += x;
}

void do_rtrn(void)
{
    fsp = b_reg - 1;
    pc = fstack[b_reg + 1];
    b_reg = fstack[b_reg];
}

void execute(int a)
{
    pc = a;
    while (1){
        int opr = code[pc].operand;
        switch (code[pc++].op) {
        case nop   : break;
        case ldi   : push(opr); break;
        case opr1  : do_opr1(opr); break;
        case opr2  : do_opr2(opr); break; 
        case print : printf(opr & 1 ? " %d\n" : " %d", pop()); break;
        case read  : do_read(); break;
        case jump  : pc = opr; break;
        case cjump : if (pop() == 0) pc = opr; break;
        case store : mem[opr] = pop(); break;
        case load  : push(mem[opr]); break;
        case del   : pop(); break;
        case call  : pc = opr; break;
        case prec  : do_prec(opr); break;
        case dclv  : do_dclv(opr); break;
        case rtrn  : do_rtrn(); break;
        case stof  : fstack[b_reg + 2 + opr] = pop(); break;
        case lodf  : push(fstack[b_reg + 2 + opr]); break;
        case putch : putchar(opr); break;
        case val   : push(mem[opr + pop()]); break;
        case ass   : a = pop(); mem[opr + pop()] = a; break;
        case assv  : a = pop(); push(mem[opr + pop()] = a); break;
        case halt  : return;
        default: error("invalid op code");
        };
    }
}

int loader(const char *fname)
{
    FILE *fp = fopen(fname, "r");
    if (!fp) return printf("can't open %s\n", fname), -1;
    int ret = 0;
    char buf[256], *p;
    while (fgets(buf, sizeof buf, fp)) {
        char *addr = strtok(buf, " ,:\t\r\n");
        char *op  = strtok(NULL, " ,;\t\r\n");
        char *opr = strtok(NULL, " ,;\t\r\n");
        if (!addr || *addr == ';') continue;
        if (!op || !opr) { ret = 1; break; }
        int i, j, k = strtol(addr, &p, 10);
        if (p == addr) { ret = 2; break; }
        for (i = 0; i < n_op && strcmp(op, str_op[i]); i++) ;
        if (i == n_op) { ret = 3; break; }
        j = strtol(opr, &p, 10);
        if (p == opr) {
            for (j = 0; j < n_opr && strcmp(opr, str_opr[j]); j++) ;
            if (j == n_opr) { ret = 4; break; }
            printf("%4d:  %-6s %s\n", k, str_op[i], str_opr[j]);
        }
        else
            printf("%4d:  %-6s %d\n", k, str_op[i], j);
        code[k].op = i, code[k].operand = j;
    }
    fclose(fp);
    return ret;
}

int main(int argc, char *argv[])
{
    if (argc != 2) return printf("usage: %s file\n", argv[0]), 1;
    if (loader(argv[1])) return puts("load error"), 2;
    puts("Executing program...");
    execute(0);
    printf("[pc:%d, sp:%d, fsp:%d] Execution terminated\n", pc, sp, fsp);
}

かずま

Re: アセンブリのソートについての質問

#6

投稿記事 by かずま » 6年前

ビルド さんが書きました: ソートするプログラム

コード:

0, nop, -1
1, read, -1
2, store, 0
3, read, -1
4, store, 1
5, read, -1
6, store, 2
7, read, -1
8, store, 3
9, read, -1
10, store, 4
11, read, -1
12, store, 5
13, read, -1
14, store, 6
15, ldi, 7
16, store, 15
17, load, 6
18, load, 5
19, opr2, gtr
20, cjump, 27
21, load, 6
22, store, 16
23, load, 5
24, store, 6
25, load, 16
26, store, 5
27, load, 5
28, load, 4
29, opr2, gtr
30, cjump, 37
31, load, 5
32, store, 16
33, load, 4
34, store, 5
35, load, 16
36, store, 4
37, load, 4
38, load, 3
39, opr2, gtr
40, cjump, 47
41, load, 4
42, store, 16
43, load, 3
44, store, 4
45, load, 16
46, store, 3
47, load, 3
48, load, 2
49, opr2, gtr
59, cjump, 57
51, load, 3
52, store, 16
53, load, 2
54, store, 3
55, load, 16
56, store, 2
57, load, 2
58, load, 1
59, opr2, gtr
60, cjump, 67
61, load, 2
62, store, 16
63, load, 1
64, store, 2
65, load, 16
66, store, 1
67, load, 1
68, load, 0
69, opr2, gtr
70, cjump, 77
71, load, 1
72, store, 16
73, load, 0
74, store, 1
75, load, 16
76, store, 0
77, load, 15
78, ldi, 1
79, opr2, sub
80, store, 15
81, load, 15
82, ldi, 0
83, opr2, gtr
84, cjump, 86
85, jump, 17
86, load, 0
87, print, -1
88, load, 1
89, print, -1
90, load, 2
91, print, -1
92, load, 3
93, print, -1
94, load, 4
95, print, -1
96, load, 5
97, print, -1
98, load, 6
99, print, -1
100, halt, -1
そのプログラムは、次のものと等価です。

コード:

    nop();
	a = read();
	b = read();
	c = read();
	d = read();
	e = read();
	f = read();
	g = read();
	i = 7;
	do {
	    if (g > f) {
		    t = g; g = f; f = t;
		}
	    if (f > e) {
		    t = f; f = e; e = t;
		}
	    if (e > d) {
		    t = e; e = d; d = t;
		}
	    if (d > c) {
		    t = d; d = c; c = t;
		}
	    if (c > b) {
		    t = c; c = b; b = t;
		}
	    if (b > a) {
		    t = b; b = a; a = t;
		}
        i--;
	} while (i > 0);
	print(a);
	print(b);
	print(c);
	print(d);
	print(e);
	print(f);
	print(g);
	halt();
確かに 7個のデータをソートできます。
バブルソートですね。
でも、なぜ配列を使わないのですか?
なぜ、val と ass を使わないのですか?
データが 50個になったらどうしますか?

アセンブリ言語の配列のプログラムがわからない
の No.4 で、配列を使った挿入ソートを示したら、
ビルド さんが書きました:参考になりました。ありがとうございます。
と答えていましたよね。
全然参考になっていないのではありませんか?

ビルド

Re: アセンブリのソートについての質問

#7

投稿記事 by ビルド » 6年前

prec, call, dclv, rtrn, stof, lodf やval,assを用いてソートするコードを教えてください。
実行は時間がかかるので遅くなるかもしれません。

ビルド

Re: アセンブリのソートについての質問

#8

投稿記事 by ビルド » 6年前

コード:

C:\workC>sml3.exe text.txt
   0:  ldi    23
   1:  ldi    48
   2:  prec   2
   3:  call   8
   4:  store  0
   5:  load   0
   6:  print  -1
   7:  halt   -1
   8:  dclv   1
   9:  lodf   0
  10:  lodf   1
  11:  opr2   sub
  12:  stof   2
  13:  lodf   2
  14:  rtrn   -1
Executing program...
 -25
[pc:8, sp:0, fsp:0] Execution terminated
実行画面です。

かずま

Re: アセンブリのソートについての質問

#9

投稿記事 by かずま » 6年前

ビルド さんが書きました:prec, call, dclv, rtrn, stof, lodf やval,assを用いてソートするコードを教えてください。
実行は時間がかかるので遅くなるかもしれません。
回答者の質問には答えずに、答えだけを要求することばかりですね。

次の質問にすべて答えてくれたら、コードを示します。

(1) sml は Stack Machine Language の略ですか?
(2) fstack, stof, lodf の f とは何のことですか?
(3) val、ass、assv は、何の略ですか?
(4) 私の書いた sml2.c は実行してみましたか?
(5) sml2 をグループで作っているのなら、なぜそのメンバーに聞かないのですか?
(6) 配列を使うソートを提示したのに、No.1 はなぜ配列を使わないのですか?
(7) No.2 で、(debug): stack_ptr = 7; If non 0, something is WRONG!
  となっているのはなぜだか分かりますか?

ビルド

Re: アセンブリのソートについての質問

#10

投稿記事 by ビルド » 6年前

(1)Stack Machine Level
(2) fstack(frame stack)利用命令.関数呼び出しで利用する.
stof ・・新規 fstack内局所変位 stackを popして,popされた値を fstack に格納し,pcを1増やす.値の操作は具体的にはつぎのようになる.dをoperandの即値とするとき, stackをpopし,popされた値を fstack[b_reg+2+d]に格納する.dのことを局所変位(local displacement)という.
lodf・・ 新規 fstack内局所変位 operand(即値)が示す番地の fstack の値を stack にpushし,pcを1増やす.値の操作は具体的にはつぎのようになる.dをoperandの即値とするとき, fstack[b_reg+2+d]にある値を stackに積む.dのことを局所変位(local displacement)という.
(3)
val ・・ 配列の先頭となる mem[]の番地 operandの値(array_base)にstack topの値(disp)を加えた値(mem_addr=array_base+disp)で示されるmem[]の番地に格納されている値(mem[mem_adr])をstack topに移動し,pcを1増やす.(stack topの値は上書きされて, mem[mem_adr]に等しくなる)stack_ptrは変化しない.
ass ・・ 配列の先頭となる mem[]の番地 operandの値(array_base)にstack topの1つ下の値(disp = stack[stack_ptr - 1])を加えた値(mem_addr = array_base + disp)で示されるmem[]の番地(mem[mem_adr])に,stack topの値(v)を格納し,stack_ptrを2減らす.pcを1増やす.
assv ・・ 配列の先頭となる mem[]の番地 operandの値(array_base)にstack topの1つ下の値(disp = stack[stack_ptr - 1])を加えた値(mem_addr = array_base + disp)で示されるmem[]の番地(mem[mem_adr])に,stack topの値(v)を格納し,さらに値(v)をstack topの一つ下(stack[stack_ptr - 1])に格納する.stack_ptrは 1減らす.※注:pcの増加数の違いを除けば,assvは ass命令を実行後,元stack topに在った値 vを再度pushすることに相当する.ただし,ass命令実行後には vは mem上にあり stack上には無くなっているので,assv命令を使用しない場合には,v自体を知っている,もしくは memの何処に格納したかを知っていることが必要である.

(4)No.8にあります。sml3にしました。

(5) 班の人で、わかるひとがいないので、どうしても教えてほしいので

【6】配列なしでやったらできるので、配列があるとどうしてもできませんので

(7)(デバッグ): stack_ptr = 7;0以外の場合、何かが間違っている!
実行が終了しましたと思います。

かずま

Re: アセンブリのソートについての質問

#11

投稿記事 by かずま » 6年前

コード:

(1) sml の l は Level なんですね。

(2) f はやはり frame でしたか。
frame というのは、関数の呼び出しごとに確保されるメモリ領域で、
fstack内の b_reg(base register)の値の位置から、
fsp(frame stack pointer) の値の位置までの部分です。

     regiser         fstack
                    |           |
     +--------+     +-----------+
b_reg|    *-------->| old b_reg |  一つ前のフレームの先頭
     +--------+     +-----------+
 fsp |    *------+  |return addr|  関数からの戻り先のアドレス
     +--------+  |  +-----------+
  sp |        |  |  | argument 0|  func(int arg0, int arg1)
     +--------+  |  +-----------+  {
  pc |        |  |  | argument 1|      int var2, var3, var4;
     +--------+  |  +-----------+
                 |  |local var 2|      return 7;
                 |  +-----------+  }
                 |  |local var 3|
                 |  +-----------+
                 +->|local var 4|
                    +-----------+
                    |           | 
呼び出し側
    load arg0 ; 第1引数を stack に push
    load arg1 ; 第2引数を stack に push
    prec 2    ; 引数の個数 2 までの新たな frame を fstack に構築
    call func ; 関数を呼び出す。

呼び出し先
    dclv 3    ; ローカル変数の個数 3。fsp を 3進める
    :
    ldi  7    ; 返却値を stack に push
    rtrn -1   ; b_reg と fsp を元に戻し、pc に戻り番地を入れる

(3) val, ass, assv の意味ではなく、略語の元の単語を尋ねているのです。
    l は load、s の一つは store というのは分かります。
    a は array(配列) ですか?  v は何ですか?

(4) sml3 は、そちらで作ったものではないのですね。

(5) 先生に聞けばいいのでは?

(6) 配列を使う例は示したはずですが。そちらで作った sml2 と、
    私の作った sml2.c を両方とも理解してください。

(7) 実行は終了したけど、stack_ptr が 0 ではないので何かが間違っています。
    print命令の仕様変更で、pop しなくなったので、それが stack に溜まって
    いるんですね。命令の説明にあるように print のあとに del を実行しま
    しょう。私の sml2.c では pop を実行します。
    なぜ、pop を実行しないように仕様変更したのですか?
prec, call, dclv, rtrn と lodf, stof を使ったバブルソートのプログラムです。
まずは、高級言語でプログラムを書きます。

コード:

    int n, i;          ; // n:mem[0], i:mem[1]
    int a[7];          ; // a:(mem[2+0], ..., mem[2+6])

    n = 7;             ; ldi 7; store 0
    i = 0;             ; ldi 0; store 1
    do {               ; <do_read>:
        a[i] = read(); ; load 1; read; ass 2
        i++;           ; load 1; ldi 1; opr2 add; store 1
    } while (i != n);  ; load 1; load 0; opr2 equ; cjump <do_read>
    sort(n);           ; load 0; prec 1; call <sort>
    i = 0;             ; ldi 0; store 1
    do {               ; <do_print>:
        print(a[i]);   ; load 1; val 2; print
        i++;           ; load 1; ldi 1; opr2 add; store 1
    } while (i != n);  ; load 1; load 0; opr2 equ; cjump <do_print>
    halt();            ; halt

void sort(int n)       ; n:fstack[+0]
{
    int i, j;          ; dclv 2;  // i:fstack[+1], j:fstack[+2]
    n--;               ; lodf 0; ldi 1; opr2 sub; stof 0
    i = 0              ; ldi 0; stof 1
    do {               ; <do_i>:
        j = n;             ; lodf 0; stof 2
        do {               ; <do_j>:
            if (a[j-1] < a[j])  ; lodf 2; val 1; lodf 2; val 2;
                                ; opr2 less; cjump <end_if>
                swap(a[j-1], a[j];  ; lodf 2; lodf 2; val 1; lodf 2;
                                    ; lodf 2; val 2; ass 1; ass 2
                                ; <end_if>:
            j--;                ; lodf 2; ldi 1; opr2 sub; stof 2
        } while (j != i);  ; lodf 2; lodf 1; opr2 equ; cjump <do_j>
        i++;               ; lodf 1; ldi 1; opr2 add; stof 1
    } while (i != n);  ; lodf 1; lodf 0; opr2 equ; cjump <do_i>
}                      ; rtrn
アセンブリ言語に変換します。

コード:

0: ldi 7
1: store 0   ; n = 7;
2: ldi 0
3: store 1   ; i = 0;
4: load 1    ; do {
5: read -1
6: ass 2     ;     a[i] = read();
7: load 1
8: ldi 1
9: opr2 add
10: store 1  ;     i++;
11: load 1
12: load 0
13: opr2 equ
14: cjump 4  : } while (i != n);
15: load 0
16: prec 1
17: call 40  ; sort(n);
18: ldi 0
19: store 1  ; i = 0;
20: load 1   ; do {
21: val 2
22: print -1 ;     print(a[i]);
23: load 1
24: ldi 1
25: opr2 add
26: store 1  ;     i++;
27: load 1
28: load 0
29: opr2 equ
30: cjump 20 ; } while (i != n);
31: halt -1  ; halt();
           ; void sort(int n) {
40: dclv 2   ; int i, j;
41: lodf 0   
42: ldi 1
43: opr2 sub
44: stof 0   ; n--;
45: ldi 0
46: stof 1   ; i = 0;
47: lodf 0   ; do {
48: stof 2   ;     j = 0;
49: lodf 2   ;     do {
50: val 1
51: lodf 2
52: val 2
53: opr2 less
54: cjump 63 ;         if (a[j-1] < a[j])
55: lodf 2
56: lodf 2
57: val 1
58: lodf 2
59: lodf 2
60: val 2
61: ass 1
62: ass 2    ;             swap(a[j-1], a[j]);
63: lodf 2
64: ldi 1
65: opr2 sub
66: stof 2   ;          j--;
67: lodf 2
68: lodf 1
69: opr2 equ
70: cjump 49 ;       } while (j != i);
71: lodf 1
72: ldi 1
73: opr2 add
74: stof 1   ;       i++;
75: lodf 1
76: lodf 0
77: opr2 equ
78: cjump 47 ;  } while (i != n);
79: rtrn -1 ; }
a = x は、load i; load x; ass a になりますが、
私は、この ass命令の仕様が不満です。
a と i の結びつきが強いので、
load x; load i; ass a のように i と a が近いほうが
コードを書きやすい/読みやすいと思います。

ビルド

Re: アセンブリのソートについての質問

#12

投稿記事 by ビルド » 6年前

おかげさまで、実行結果うまくいきました。ありがとうございます。

コード:

C:\workC>sml3.exe ex01(1).txt
   0:  ldi    7
   1:  store  0
   2:  ldi    0
   3:  store  1
   4:  load   1
   5:  read   -1
   6:  ass    2
   7:  load   1
   8:  ldi    1
   9:  opr2   add
  10:  store  1
  11:  load   1
  12:  load   0
  13:  opr2   equ
  14:  cjump  4
  15:  load   0
  16:  prec   1
  17:  call   40
  18:  ldi    0
  19:  store  1
  20:  load   1
  21:  val    2
  22:  print  -1
  23:  load   1
  24:  ldi    1
  25:  opr2   add
  26:  store  1
  27:  load   1
  28:  load   0
  29:  opr2   equ
  30:  cjump  20
  31:  halt   -1
  40:  dclv   2
  41:  lodf   0
  42:  ldi    1
  43:  opr2   sub
  44:  stof   0
  45:  ldi    0
  46:  stof   1
  47:  lodf   0
  48:  stof   2
  49:  lodf   2
  50:  val    1
  51:  lodf   2
  52:  val    2
  53:  opr2   less
  54:  cjump  63
  55:  lodf   2
  56:  lodf   2
  57:  val    1
  58:  lodf   2
  59:  lodf   2
  60:  val    2
  61:  ass    1
  62:  ass    2
  63:  lodf   2
  64:  ldi    1
  65:  opr2   sub
  66:  stof   2
  67:  lodf   2
  68:  lodf   1
  69:  opr2   equ
  70:  cjump  49
  71:  lodf   1
  72:  ldi    1
  73:  opr2   add
  74:  stof   1
  75:  lodf   1
  76:  lodf   0
  77:  opr2   equ
  78:  cjump  47
  79:  rtrn   -1
Executing program...
? 1
? 2
? 3
? 4
? 5
? 6
? 7
 7
 6
 5
 4
 3
 2
 1
[pc:32, sp:0, fsp:0] Execution terminated

かずま

Re: アセンブリのソートについての質問

#13

投稿記事 by かずま » 6年前

ビルド さんが書きました:おかげさまで、実行結果うまくいきました。ありがとうございます。
うまくいくのは当たり前です。
私の作った sml2.c で、動かしたのですから。

私が知りたいのは、そちらの sml2 で、
そのソートプログラムが動くのかどうかです。

質問です。
(1) ソートプログラムは理解できましたか?
(2) 各命令の意味は理解できましたか?
(3) バブルソートを選択ソートまたは挿入
  ソートに書き換えることはできますか?
(4) 次の prec の説明の不十分な点をを指摘できますか?
12 prec  新規 関数の引数の個数(arity)
  "関数の呼び出しの準備をするために用いる.
  この命令は call命令とペアとなり,call命令の直前に
  実行されなければならない.
  ①prec命令実行前の b_regの値を fstackにpush.
  ②関数処理終了後(rtrn命令実行後)の program counter
   (pc)の値(戻り番地という)をfstackにpush.
  ③operand(即値)が示す arity個の実引数を
   stack からpopして fstack にコピーする※.
  ④pcを1増やす.
  ※③のコピーの順序は stackに先に積まれたものが
   fstackにも先に積まれるようにする.
   このため,少なくともpopあるいはpushの一方は
   sml0で用意したものとは別に(block_pop()や
   block_push()など)用意する必要がある.
   または,このデータ移動のための専用の関数
   (block_mv())を用意する.

(5) 2つの変数の値を交換するのに、
  通常は、t = a; a = b; b = t; とするので、
  load a; store t; load b; store a; load t; store b
  となりますが、スタックマシンの場合は、
  load a; load b; store a; store b
  とできることは理解できますか?
  ソートプログラムの swap(a[j-1], a[j]) では、配列の
  要素の交換ですが、そのテクニックを使っています。
(6) 配列は mem[2] から始まるので、a は load i; val a となり、
  a[i-1] は load i; ldi 1; opr2 sub; val a となりそうですが、
  load i; val (a-1) で参照しているのに気づきましたか?

アバター
あたっしゅ
記事: 664
登録日時: 13年前
住所: 東京23区
連絡を取る:

Re: アセンブリのソートについての質問

#14

投稿記事 by あたっしゅ » 6年前

 わしには、uni くんより、ビルドくんの方が、悪質に思えます、という個人の感想。
 なんか、「個人の感想」と付け加えるのが、はやっているから付けました。
わしは、いつも、個人の感想なので、あらためて付ける必要性を感じないのですが...
VTuber:
東上☆海美☆(とうじょう・うみみ)
http://atassyu.php.xdomain.jp/vtuber/index.html
レスがついていないものを優先して、レスするみみ。時々、見当外れなレスしみみ。

中の人:
手提鞄あたッしュ、[MrAtassyu] 手提鞄屋魚有店
http://ameblo.jp/mratassyu/
Pixiv: 666303
Windows, Mac, Linux, Haiku, Raspbery Pi, Jetson Nano, 電子ブロック 持ち。

ビルド

Re: アセンブリのソートについての質問

#15

投稿記事 by ビルド » 6年前

(1)(2)(3)(4)(5)(6)一応理解できました。C言語のプログラムをみてわかりやすかったです。これからC言語のプログラムをかいてそして、アセンブラのプログラムを書きたいと思います。
また、自分のsml2は今できないので、おそくなるかもしれないが、自分のsml2の実行結果を載せます。

ビルド

Re: アセンブリのソートについての質問

#16

投稿記事 by ビルド » 6年前

おそくなりました。ソートプログラムの実行画面です。

コード:

./sml2 ex01.txt
   0:     ldi       7
   1:   store       0
   2:     ldi       0
   3:   store       1
   4:    load       1
   5:    read      -1
   6:     ass       2
   7:    load       1
   8:     ldi       1
   9:    opr2     add
  10:   store       1
  11:    load       1
  12:    load       0
  13:    opr2     equ
  14:   cjump       4
  15:    load       0
  16:    prec       1
  17:    call      40
  18:     ldi       0
  19:   store       1
  20:    load       1
  21:     val       2
  22:   print      -1
  23:    load       1
  24:     ldi       1
  25:    opr2     add
  26:   store       1
  27:    load       1
  28:    load       0
  29:    opr2     equ
  30:   cjump      20
  31:    halt      -1
Executing program...
? 1
? 2
? 3
? 4
? 5
? 6
? 7
7
6
5
4
3
2
1
(debug): stack_ptr = 7, fstack_ptr = -1, b_reg = -1;
(debug): These must be 0, -1, and -1, respectively. 
Execution terminated.
おそらく31~のコードは省略です。
うまく実行結果ができたと思います。
ありがとうございます。

ビルド\\

Re: アセンブリのソートについての質問

#17

投稿記事 by ビルド\\ » 6年前

すみませんけど、問(2) 正整数 nを引数として呼び出されると 0から nまでの総和を関数値とする関数を再帰呼出しを使い実現せよ.その関数を用い,キーボードから入力された mと nに対して,0から m+nまでの総和を求め表示するプログラム ex02.txtを作成せよ(また,上記の課題(2)で与える mと nは学籍番号の上位から3桁目(c)と下位から3桁目(e)を用いよ.ただし、m+n = c+e <= 1 の場合には m=1, n=2とせよ。(この場合m+n=3となる)
)っていう問題ですが、c言語ではうまくいけたのですが、アセンブリコードでやってみたら、エラーになっていて、困っています。期限は1/11です。お願いします。
C言語

コード:

#include <stdio.h>

int souwa(int);

main() {

	int a,m;
	
	scanf("%d",&a); //1,read -1
	
	m = sum(a); //call
	
	printf("1~%dまでの総和は%dです。\n",a,m); //print
	
	return 0;
}
int sum(int n) // n; fstack[+0]
{
	if(n==0) { // cjump
	
		return 1;
	}
	else { // jump
		return n + sum(n-1); // rtrn
	}
}
(C言語)実行画面

コード:

C:\workC>a.exe
10
1~10までの総和は56です。
[code/]

アセンブリ言語
[code]
0, nop, -1 
1, read, -1
2, preac 1
3, call 8
4, store, 0
5, load, 0
6, print, -1
7, halt, -1
8, dclv, 1
9, lodf, 0
10, id , 7
11, opr2 add
12, stof, 2
13,lodf, 2
14, rtrn, -1
15, nop, -1

コード:

./sml2 ex02.txt
Segmentation fault (コアダンプ)

ビルド

Re: アセンブリのソートについての質問

#18

投稿記事 by ビルド » 6年前

訂正で提出期限が1/10の15時までです。

かずま

Re: アセンブリのソートについての質問

#19

投稿記事 by かずま » 6年前

ビルド さんが書きました:

コード:

./sml2 ex01.txt
  :
(debug): stack_ptr = 7, fstack_ptr = -1, b_reg = -1;
(debug): These must be 0, -1, and -1, respectively. 
Execution terminated.
おそらく31~のコードは省略です。
うまく実行結果ができたと思います。
stack_ptr が 0 になっていません。

かずま

Re: アセンブリのソートについての質問

#20

投稿記事 by かずま » 6年前

ビルド\ さんが書きました: その関数を用い,キーボードから入力された mと nに対して,
キーボードから m と n が入力されていません。
ビルド\ さんが書きました: c言語ではうまくいけたのですが、
1から 10までの総和は 56 ではありません。
ビルド\ さんが書きました: アセンブリコードでやってみたら、エラーになっていて、困っています。
sml3 で試してみましたか?

ビルド

Re: アセンブリのソートについての質問

#21

投稿記事 by ビルド » 6年前

訂正でこんな感じですか。(C言語)

コード:

#include<stdio.h>

 int main(void)
 {
 int m,n,i,sum;

 printf("mからnまでの総和を求めます。mとnの値を入力してください",n);
 scanf("%d %d",&m,&n);

 if(m>=n){
 printf("Error!!m<nで入力してください\n");
 }else{
 sum=0;
 for(i=m;i<=n;i++)sum+=i;
 printf("%dから%dまでの整数の総和は%dです",m,n,sum);
 }

 return 0;
 }

コード:

C:\workC>a.exe
mからnまでの総和を求めます。mとnの値を入力してください1
10
1から10までの整数の総和は55です

ビルド

Re: アセンブリのソートについての質問

#22

投稿記事 by ビルド » 6年前

sml3でやってみてもエラーになりました。

コード:

C:\workC>sml3.exe ex2.txt
   0:  nop    -1
   1:  read   -1
load error

かずま

Re: アセンブリのソートについての質問

#23

投稿記事 by かずま » 6年前

ビルド\ さんが書きました: キーボードから入力された mと nに対して,0から m+nまでの総和を求め表示するプログラム ex02.txtを作成せよ
ビルド さんが書きました:

コード:

 printf("mからnまでの総和を求めます。mとnの値を入力してください",n);
問題の意味が分からないのですか?

かずま

Re: アセンブリのソートについての質問

#24

投稿記事 by かずま » 6年前

ビルド さんが書きました:sml3でやってみてもエラーになりました。

コード:

C:\workC>sml3.exe ex2.txt
   0:  nop    -1
   1:  read   -1
load error
2, preac, 1 がおかしいということが分かりませんか?

ビルド

Re: アセンブリのソートについての質問

#25

投稿記事 by ビルド » 6年前

コード:

C:\workC>sml3.exe ex2.txt
   0:  nop    -1
   1:  read   -1
   2:  prec   1
   3:  call   8
   4:  store  0
   5:  load   0
   6:  print  -1
   7:  halt   -1
   8:  dclv   1
   9:  lodf   0
load error
それでもエラーになりました。おそらく10番以降が問題だと思います。
また、(C言語)問題の意味ちがいました?どういうところが違うのですか?C言語だけでもお願いします。

かずま

Re: アセンブリのソートについての質問

#26

投稿記事 by かずま » 6年前

ビルド さんが書きました: それでもエラーになりました。おそらく10番以降が問題だと思います。
10, id, 7 って何ですか?
ビルド さんが書きました: また、(C言語)問題の意味ちがいました?どういうところが違うのですか?
問題は、0 から m+n まで。
Cプログラムは、m から n まで。
ビルド さんが書きました: C言語だけでもお願いします。

コード:

#include <stdio.h>

int read(void) { int x; printf("? "); scanf("%d", &x); return x; }
void print(int x) { printf(" %d\n", x); }

int sum(int n);

int main(void)
{
    int m, n, i, j;
    m = read();
    n = read();
    i = m + n;
    j = sum(i);
    print(j);
}

int sum(int n)
{
    if (n == 0)
        return 0;
    else
        return n + sum(n-1);
}

ビルド

Re: アセンブリのソートについての質問

#27

投稿記事 by ビルド » 6年前

実行うまくいけたらしいですが、果たして正解でしょうか?

コード:

C:\workC>sml3.exe ex02a.txt
   0:  nop    -1
   1:  read   -1
   2:  read   -1
   3:  prec   2
   4:  call   8
   5:  load   0
   6:  print  -1
   7:  halt   -1
   8:  dclv   1
   9:  cjump  3
  10:  jump   1
  11:  opr2   add
  12:  stof   2
  13:  lodf   2
  14:  rtrn   -1
  15:  nop    -1
Executing program...
? 1
? 2
[pc:10, sp:0, fsp:5] stack empty

コード:

//アセンブリ表現です。(自分の予想)
#include <stdio.h>
 
int read(void) { 
	int x;
	printf("? "); 
	scanf("%d", &x); 
	return x; 
}
void print(int x) { 
	printf(" %d\n", x); // print,-1
}
 
int sum(int n);
 
int main(void)
{
    int m, n, i, j;
    m = read(); //1,read,-1
    n = read(); //2,read,-1
    i = m + n;  // ,opr2, add
    j = sum(i);  // 
    print(j);
}
 
int sum(int n) //lodf,0
{
    if (n == 0) //jump
        return 0;
    else
        return n + sum(n-1);//cjump
}

かずま

Re: アセンブリのソートについての質問

#28

投稿記事 by かずま » 6年前

ビルド さんが書きました:実行うまくいけたらしいですが、果たして正解でしょうか?
次の質問にすべて答えてください。

(1) 1 と 2 を入力すると、結果として表示される値が何かわからないのですか?

(2) fstack pointer が 0 になっていていないのを変だと思わないんですか?

(3) Execution terminated の代わりに stack empry というエラーメッセージが
 出ているのはおかしくないですか?

(4) program counter が 10 なのは、アドレス 9 の命令で止まったということで、
 これは、halt ではなく、途中で止まっていると考えなかったのですか?
ビルド さんが書きました:

コード:

//アセンブリ表現です。(自分の予想)
(5) No.11 のプログラムで、高級言語とアセンブリ言語の関係を理解していない
 のですか?

ビルド

Re: アセンブリのソートについての質問

#29

投稿記事 by ビルド » 6年前

(1)本来なら、例1と2を入力すると、6になると思います。
なのに、ちがう答えになりました。

(2)確かに変ですね。

(3)cjump,jumpあたりから怪しいと思うので、それでstack empryというエラーメッセージが表示されたと思います。

(4)(3)と同様比較するところ(C言語ではelse)っていう部分がいまいちわからなかった。とくにreturn n + sum(n-1)っていう部分でアセンブリ表現で考えてみたら、複雑になり、結局わかりませんでした。

質問外ですが、prec.call,dclv,lodfに関して理解できました。簡単にいうと prec 引数 call 関数呼び出し dclv ローカル変数 lodf 引数ですね。

ビルド

Re: アセンブリのソートについての質問

#30

投稿記事 by ビルド » 6年前

5番かくの忘れていたので、追加します。
高級言語とアセンブリ言語は基礎的な所は理解できます。しかし、応用力が苦手です。

かずま

Re: アセンブリのソートについての質問

#31

投稿記事 by かずま » 6年前

関数 sum だけ書いてみました。main のほうを書いてください。

コード:

int main(void)
{
    int m, n, i, j;  // m:mem[0], n:mem[1], i:mem[2], j:mem[3]
    m = read();  // read; store 0
    n = read();  // 
    i = m + n;   // 
    j = sum(i);  // 
    print(j);    // 
}                //  halt

          // <sum>:
int sum(int n)   // n:fstack[+0]
{
    if (n == 0)  // lodf 0; ldi 0; opr2 equ; cjump <else>
        return 0;    // ldi 0; rtrn
    else         // <else>:
        return n + sum(n-1);  // lodf 0; lodf 0; ldi 1; opr2 sub; 
                              // prec 1; call <sum>; opr2 add; rtrn
}
あとは、完全なアセンブリ言語に書き換えて実行してみてください。

返信

“C言語何でも質問掲示板” へ戻る