I challenge DNH to

1. Viết một trình biên dịch (compiler) cho ngôn ngữ brainfuck sang ngôn ngữ tùy thích
Bonus: Code sinh ra phải được tối ưu hóa (optimized)
Test case: https://ideone.com/SjZwJj
Test case 2: https://ideone.com/D3WAOU

2. Viết một trình thông dịch (interpreter) cho ngôn ngữ brainfuck (không cần cú pháp lặp)
Bonus: Cho phép dùng cú pháp lặp
Test case: https://ideone.com/oRDXuk
Test case bonus: https://ideone.com/SjZwJj
Test case bonus 2: https://ideone.com/D3WAOU

Note:

  • Chương trình không cần xử lý các ký tự không nằm trong ngôn ngữ brainfuck (kể cả khoảng cách, tab, xuống hàng, …)
  • Ngôn ngữ được dùng tùy thích
  • Bonus không bắt buộc
  • Chỉ cần làm 1 trong 2 câu
  • Vui là chính :))

Tài liệu tham khảo:

Online compiler:

Happy Brainf*cking! :dark_sunglasses:

13 Likes

Em vẫn chưa hiểu cái brain nó hoạt động thì làm sao làm đây?

Trình cùi chỉ chuyển sang C thôi :pensive:

Result:

3 Likes

Nay nhận ra mình cùi thiệt :joy: mấy ngày mới xong cái trình thông dịch, người ta viết đơn giản mà mình làm dài ơi là dài với phải ngồi sửa lỗi đâu đâu không nên mất thời gian.
Viết trên Rust :crab: có giai đoạn compile để gom mấy lệnh gần nhau rồi cộng trừ 1 lượt rồi mới thực thi, cũng chưa tối ưu gì hết.
Về Rust thì các bạn có thể đọc ở đây: https://thefullsnack.com/posts/rust-intro.html?t=1508797552961 của anh huytd (có bài y chang trên techtalk nhưng mình tin page đó đạo nhái nên không up link ;)).

use std::io::{self, Read};
use std::fs::File;
use std::env;

const OP_INCR: u32 = 0;
const OP_DECR: u32 = 1;
const OP_NEXT: u32 = 2;
const OP_PREV: u32 = 3;
const OP_BGNL: u32 = 4;
const OP_ENDL: u32 = 5;
const OP_PRNT: u32 = 6;
const OP_INPT: u32 = 7;

fn bfi_u8_add(var: &mut u8, value: u32) {
	*var = (*var as u32 + value) as u8;
}

fn bfi_u8_sub(var: &mut u8, value: u32) {
	*var = (*var as i64 - value as i64) as u8;
}

fn bfi_next_cell(current_cell: u32, step: u32, max_cells: u32) -> u32 {
	if current_cell as u64 + step as u64 >= max_cells as u64 {
		return step - (max_cells - current_cell);
	}
	else {
		return current_cell + step;
	}
}

fn bfi_prev_cell(current_cell: u32, step: u32, max_cells: u32) -> u32 {
	if current_cell < step {
		return max_cells + 1 - (step - current_cell);
	}
	else {
		return current_cell - step;
	}
}

fn bfi_compile(filename: &String) -> Vec<Vec<u32>> {
	let mut filehandle = File::open(filename)
				.expect(format!("error: file `{}` not found!\n", filename).as_str());
	let mut raw_contents = String::new();
	let mut compiled_code = Vec::<Vec<u32>>::new();

	match filehandle.read_to_string(&mut raw_contents) {
		Ok(_) => {},
		Err(e) => panic!(e)
	}

	let raw_contents_len: u32 = raw_contents.len() as u32;
	let raw_contents_slice: Vec<u8> = raw_contents.into();
	let mut loop_stack = Vec::<u32>::new();
	let mut raw_contents_index: u32 = 0;
	let mut stacked_char_num: u32 = 1;
	let mut current_char: char;
	let mut previous_char: char = '\0';
	let mut offset: i32 = 0;

	while raw_contents_index <= raw_contents_len {
		current_char = if raw_contents_index < raw_contents_len
			{raw_contents_slice[raw_contents_index as usize] as char}
			else {'\0'};

		if previous_char == current_char && current_char != '[' && current_char != ']' {
			stacked_char_num += 1;
		}
		else {
			match previous_char {
				'+' => {
					compiled_code.push(vec![OP_INCR, stacked_char_num]);
				},
				'-' => {
					compiled_code.push(vec![OP_DECR, stacked_char_num]);
				},
				'<' => {
					compiled_code.push(vec![OP_PREV, stacked_char_num]);
				},
				'>' => {
					compiled_code.push(vec![OP_NEXT, stacked_char_num]);
				},
				'.' => {
					compiled_code.push(vec![OP_PRNT, stacked_char_num]);
				},
				',' => {
					compiled_code.push(vec![OP_INPT, 0]);
				},
				'[' => {
					loop_stack.push(compiled_code.len() as u32);
					compiled_code.push(vec![OP_BGNL, 0]);
					
				},
				']' => {
					match loop_stack.pop() {
						Some(ls_v) => {
							compiled_code.push(vec![OP_ENDL, ls_v]);
							compiled_code[ls_v as usize][1] = compiled_code.len() as u32 - 1;
						},
						None => {
							panic!(format!("{}:{}: incorrect close delimiter ']'", 
								filename, raw_contents_index));
						}
					}
				},
				_ => {
					offset -= 1;  // 'offset' will never increase if not bf syntax.
				}
			}
			stacked_char_num = 1;
		}

	    offset += 1;
	    raw_contents_index += 1;
	    previous_char = current_char;
	}

	if !loop_stack.is_empty() {
		panic!(format!("{}:{}: missing close delimiter ']'", 
			filename, loop_stack.pop().unwrap()));
	}

	compiled_code
}

fn bfi_exectute(code: Vec<Vec<u32>>, max_pointers: u32)  {
	let mut pointers: Vec<u8> = vec![0; max_pointers as usize];
	let mut current_cell: usize = 0;
	let mut offset: usize = 0;
	let code_size = code.len();

	while offset < code_size {
		match code[offset][0] {
			OP_INCR => {
				bfi_u8_add(&mut pointers[current_cell], code[offset][1]);
			},
			OP_DECR => {
				bfi_u8_sub(&mut pointers[current_cell], code[offset][1]);
			},
			OP_NEXT => {
				current_cell = bfi_next_cell(current_cell as u32, code[offset][1], max_pointers) as usize;
			},
			OP_PREV => {
				current_cell = bfi_prev_cell(current_cell as u32, code[offset][1], max_pointers) as usize;
			},
			OP_BGNL => {
				if pointers[current_cell] == 0 {
					offset = code[offset][1] as usize;
				}
			},
			OP_ENDL => {
				if pointers[current_cell] == 0 {}
				else {offset = code[offset][1] as usize}
			},
			OP_PRNT => {
				for _ in 0..code[offset][1] {
					print!("{}", pointers[current_cell] as char)
				}
			},
			OP_INPT => {
				for character in io::stdin().bytes() {
					pointers[current_cell] = match character {
						Ok(c) => c ,
						Err(e) => 
							panic!(format!("bfi-runtime: system error {}", e.to_string()))
					};
					break;
				}
			}
			_ => {
				panic!(format!("bfi-runtime: invalid opcode {}@{}",
					code[offset][0], code[offset][1]));
			}
		}
		offset += 1;
	}
}

fn main() {
	const POINTER_NUMBER: u32 = 30_000;

	if let Some(filename) = env::args().nth(1) {
		bfi_exectute(bfi_compile(&filename), POINTER_NUMBER);
	}
	else {
		println!("Br**nfuck Interpreter version 0.1");
		println!("usage: {} file.bf", env::args().nth(0).unwrap());
	}
}
3 Likes

Chờ mãi có 2 mống :unamused:
Thui chắc t7 này cho cái nhẹ nhàng hơn. \ OvO /

5 Likes

Cuối tuần mới làm được, viết bài xong vào tuần rồi nên chẳng ai có time :joy:

2 Likes

Biện hộ vote ban nick :unamused:

4 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?