合計 昨日 今日

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

[このトピックは解決済みです]

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

Name: ビルド
[URL]
Date: 2017年12月26日(火) 13:28
No: 1
(OFFLINE)

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

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

今わかる範囲でコードを書いてみました。
ソートするプログラム
コード[C++]: 全て選択
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
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 についてよくわかりません。多分わたしとしてはどこかの番地に付け加えいいと思う。

コード[C++]: 全て選択
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
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などについて詳しく解説をお願いします。(解説つき)

Name: ビルド
[URL]
Date: 2017年12月26日(火) 13:32
No: 2
(OFFLINE)

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

補足で、
今わかる範囲の実行結果です。
コード[C++]: 全て選択
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
$ ./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.

Name: かずま
[URL]
Date: 2017年12月27日(水) 22:37
No: 3
(OFFLINE)

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

ビルド さんが書きました:今までのやつは沢山あり、ややこしいので、新しい質問項目にしました。

何度も言っていますが、前の質問にリンクを張らないと、
初めてこの質問を読む人には何もわかりません。

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

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

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

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

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

sml2.c
コード[C]: 全て選択
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
#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
コード[Text]: 全て選択
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
;    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  : 戻る

実行例
コード[Text]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
   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 などを使ったプログラムを実行して、
それが正しいのかを、どうか教えてください。
解説はそれからします。

Name: かずま
[URL]
Date: 2017年12月27日(水) 22:50
No: 4
(OFFLINE)

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

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

Name: かずま
[URL]
Date: 2017年12月28日(木) 00:08
No: 5
(OFFLINE)

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

すみません。93行目も間違っていました。
今、動いている sml2.c は、次のものです。
コード[C]: 全て選択
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
#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);
}

Name: かずま
[URL]
Date: 2017年12月28日(木) 05:25
No: 6
(OFFLINE)

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

ビルド さんが書きました:ソートするプログラム
コード[C++]: 全て選択
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
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

そのプログラムは、次のものと等価です。
コード[Text]: 全て選択
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
    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 で、配列を使った挿入ソートを示したら、
ビルド さんが書きました:参考になりました。ありがとうございます。

と答えていましたよね。
全然参考になっていないのではありませんか?

Name: ビルド
[URL]
Date: 2017年12月28日(木) 08:55
No: 7
(OFFLINE)

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

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

Name: ビルド
[URL]
Date: 2017年12月28日(木) 09:50
No: 8
(OFFLINE)

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

コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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

実行画面です。

Name: かずま
[URL]
Date: 2017年12月28日(木) 10:03
No: 9
(OFFLINE)

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

ビルド さんが書きました: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!
  となっているのはなぜだか分かりますか?

Name: ビルド
[URL]
Date: 2017年12月28日(木) 15:49
No: 10
(OFFLINE)

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

(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以外の場合、何かが間違っている!
実行が終了しましたと思います。

Name: かずま
[URL]
Date: 2017年12月28日(木) 17:49
No: 11
(OFFLINE)

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

コード[Text]: 全て選択
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
(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 を使ったバブルソートのプログラムです。
まずは、高級言語でプログラムを書きます。
コード[Text]: 全て選択
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
    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

アセンブリ言語に変換します。
コード[Text]: 全て選択
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
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[i] = x は、load i; load x; ass a になりますが、
私は、この ass命令の仕様が不満です。
a と i の結びつきが強いので、
load x; load i; ass a のように i と a が近いほうが
コードを書きやすい/読みやすいと思います。

Name: ビルド
[URL]
Date: 2017年12月28日(木) 21:11
No: 12
(OFFLINE)

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

[解決!]

おかげさまで、実行結果うまくいきました。ありがとうございます。
コード[C++]: 全て選択
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
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

Name: かずま
[URL]
Date: 2017年12月28日(木) 22:18
No: 13
(OFFLINE)

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

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

うまくいくのは当たり前です。
私の作った 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[i] は load i; val a となり、
  a[i-1] は load i; ldi 1; opr2 sub; val a となりそうですが、
  load i; val (a-1) で参照しているのに気づきましたか?

Name: あたっしゅ
[URL]
中級者(10,959 ポイント)
Date: 2017年12月30日(土) 20:41
No: 14
(OFFLINE)

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

 わしには、uni くんより、ビルドくんの方が、悪質に思えます、という個人の感想。
 なんか、「個人の感想」と付け加えるのが、はやっているから付けました。
わしは、いつも、個人の感想なので、あらためて付ける必要性を感じないのですが...
手提鞄あたっしゅ、[MrAtassyu]

Name: ビルド
[URL]
Date: 2017年12月31日(日) 18:03
No: 15
(OFFLINE)

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

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

Name: ビルド
[URL]
Date: 2018年1月09日(火) 13:44
No: 16
(OFFLINE)

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

おそくなりました。ソートプログラムの実行画面です。
コード[C++]: 全て選択
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
./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~のコードは省略です。
うまく実行結果ができたと思います。
ありがとうございます。

Name: ビルド\\
[URL]
Date: 2018年1月09日(火) 15:57
No: 17
(OFFLINE)

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

すみませんけど、問(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言語

コード[C++]: 全て選択
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
#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++]: 全て選択
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
C:\workC>a.exe
10
110までの総和は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
[/code]
 
[code]
./sml2 ex02.txt
Segmentation fault (コアダンプ)

Name: ビルド
[URL]
Date: 2018年1月10日(水) 09:13
No: 18
(OFFLINE)

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

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

Name: かずま
[URL]
Date: 2018年1月10日(水) 09:32
No: 19
(OFFLINE)

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

ビルド さんが書きました:
コード[C++]: 全て選択
1
2
3
4
5
./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 になっていません。

Name: かずま
[URL]
Date: 2018年1月10日(水) 09:36
No: 20
(OFFLINE)

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

ビルド\\ さんが書きました:その関数を用い,キーボードから入力された mと nに対して,

キーボードから m と n が入力されていません。

ビルド\\ さんが書きました:c言語ではうまくいけたのですが、

1から 10までの総和は 56 ではありません。

ビルド\\ さんが書きました:アセンブリコードでやってみたら、エラーになっていて、困っています。

sml3 で試してみましたか?

Name: ビルド
[URL]
Date: 2018年1月10日(水) 10:00
No: 21
(OFFLINE)

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

訂正でこんな感じですか。(C言語)
コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#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++]: 全て選択
1
2
3
4
C:\workC>a.exe
mからnまでの総和を求めます。mとnの値を入力してください1
10
1から10までの整数の総和は55です

Name: ビルド
[URL]
Date: 2018年1月10日(水) 10:09
No: 22
(OFFLINE)

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

sml3でやってみてもエラーになりました。
コード[C++]: 全て選択
1
2
3
4
C:\workC>sml3.exe ex2.txt
   0:  nop    -1
   1:  read   -1
load error

Name: かずま
[URL]
Date: 2018年1月10日(水) 10:42
No: 23
(OFFLINE)

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

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

ビルド さんが書きました:
コード[C++]: 全て選択
1
 printf("mからnまでの総和を求めます。mとnの値を入力してください",n);

問題の意味が分からないのですか?

Name: かずま
[URL]
Date: 2018年1月10日(水) 10:44
No: 24
(OFFLINE)

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

ビルド さんが書きました:sml3でやってみてもエラーになりました。
コード[C++]: 全て選択
1
2
3
4
C:\workC>sml3.exe ex2.txt
   0:  nop    -1
   1:  read   -1
load error

2, preac, 1 がおかしいということが分かりませんか?

Name: ビルド
[URL]
Date: 2018年1月10日(水) 14:25
No: 25
(OFFLINE)

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

コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
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言語だけでもお願いします。

Name: かずま
[URL]
Date: 2018年1月10日(水) 15:23
No: 26
(OFFLINE)

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

ビルド さんが書きました:それでもエラーになりました。おそらく10番以降が問題だと思います。

10, id, 7 って何ですか?

ビルド さんが書きました:また、(C言語)問題の意味ちがいました?どういうところが違うのですか?

問題は、0 から m+n まで。
Cプログラムは、m から n まで。

ビルド さんが書きました:C言語だけでもお願いします。

コード[C]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#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);
}

Name: ビルド
[URL]
Date: 2018年1月10日(水) 18:57
No: 27
(OFFLINE)

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

実行うまくいけたらしいですが、果たして正解でしょうか?
コード[C++]: 全て選択
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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


コード[C++]: 全て選択
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
//アセンブリ表現です。(自分の予想)
#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
}

Name: かずま
[URL]
Date: 2018年1月10日(水) 20:57
No: 28
(OFFLINE)

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

ビルド さんが書きました:実行うまくいけたらしいですが、果たして正解でしょうか?

次の質問にすべて答えてください。

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

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

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

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

ビルド さんが書きました:
コード[C++]: 全て選択
1
//アセンブリ表現です。(自分の予想)

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

Name: ビルド
[URL]
Date: 2018年1月10日(水) 21:38
No: 29
(OFFLINE)

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

(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 引数ですね。

Name: ビルド
[URL]
Date: 2018年1月10日(水) 21:44
No: 30
(OFFLINE)

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

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

次へ

Return to C言語何でも質問掲示板

オンラインデータ

このフォーラムを閲覧中のユーザー: なし & ゲスト[15人]