sum.asm # print sum of input numbers (terminated by zero) sum.asm sum.asm ld zero # initialize sum to zero sum.asm st sum sum.asm loop get # read a number sum.asm jz done # no more input if number is zero sum.asm add sum # add in accumulated sum sum.asm st sum # store new value back in sum sum.asm j loop # go back and read another number sum.asm sum.asm done ld sum # print sum sum.asm put sum.asm halt sum.asm sum.asm zero const 0 sum.asm sum const asm # asm - assembler and interpreter for simple computer asm # usage: awk -f asm program-file data-files... asm asm BEGIN { asm srcfile = ARGV[1] asm ARGV[1] = "" # remaining files are data asm tempfile = "asm.temp" asm n = split("const get put ld st add sub jpos jz j halt", x) asm for (i = 1; i <= n; i++) # create table of op codes asm op[x[i]] = i-1 asm asm # ASSEMBLER PASS 1 asm FS = "[ \t]+" asm while (getline 0) { asm sub(/#.*/, "") # strip comments asm symtab[$1] = nextmem # remember label location asm if ($2 != "") { # save op, addr if present asm print $2 "\t" $3 >tempfile asm nextmem++ asm } asm } asm close(tempfile) asm asm # ASSEMBLER PASS 2 asm nextmem = 0 asm while (getline 0) { asm if ($2 !~ /^[0-9]*$/) # if symbolic addr, asm $2 = symtab[$2] # replace by numeric value asm mem[nextmem++] = 1000 * op[$1] + $2 # pack into word asm } asm asm # INTERPRETER asm for (pc = 0; pc >= 0; ) { asm addr = mem[pc] % 1000 asm code = int(mem[pc++] / 1000) asm if (code == op["get"]) { getline acc } asm else if (code == op["put"]) { print acc } asm else if (code == op["st"]) { mem[addr] = acc } asm else if (code == op["ld"]) { acc = mem[addr] } asm else if (code == op["add"]) { acc += mem[addr] } asm else if (code == op["sub"]) { acc -= mem[addr] } asm else if (code == op["jpos"]) { if (acc > 0) pc = addr } asm else if (code == op["jz"]) { if (acc == 0) pc = addr } asm else if (code == op["j"]) { pc = addr } asm else if (code == op["halt"]) { pc = -1 } asm else { pc = -1 } asm } asm } asm.print # asm - assembler and interpreter for simple computer asm.print # usage: awk -f asm program-file data-files... asm.print asm.print # this is a special version to produce a listing asm.print asm.print BEGIN { asm.print srcfile = ARGV[1] asm.print ARGV[1] = "" # remaining files are data asm.print tempfile = "asm.temp" asm.print n = split("const get put ld st add sub jpos jz j halt", x) asm.print for (i = 1; i <= n; i++) # create table of op codes asm.print op[x[i]] = i-1 asm.print asm.print # ASSEMBLER PASS 1 asm.print nextmem = 0 # new asm.print FS = "[ \t]+" asm.print while (getline 0) { asm.print input[nextmem] = $0 # new: remember source line asm.print sub(/#.*/, "") # strip comments asm.print symtab[$1] = nextmem # remember label location asm.print if ($2 != "") { # save op, addr if present asm.print print $2 "\t" $3 >tempfile asm.print nextmem++ asm.print } asm.print } asm.print close(tempfile) asm.print asm.print # ASSEMBLER PASS 2 asm.print nextmem = 0 asm.print while (getline 0) { asm.print if ($2 !~ /^[0-9]*$/) # if symbolic addr, asm.print $2 = symtab[$2] # replace by numeric value asm.print mem[nextmem++] = 1000 * op[$1] + $2 # pack into word asm.print } asm.print for (i = 0; i < nextmem; i++) # new: print memory asm.print printf("%3d: %05d %s\n", i, mem[i], input[i]) # new asm.print } graph # graph - processor for a graph-drawing language graph # input: data and specification of a graph graph # output: data plotted in specified area graph graph BEGIN { # set frame dimensions... graph ht = 24; wid = 80 # height and width graph ox = 6; oy = 2 # offset for x and y axes graph number = "^[-+]?([0-9]+[.]?[0-9]*|[.][0-9]+)" \ graph "([eE][-+]?[0-9]+)?$" graph } graph $1 == "label" { # for bottom graph sub(/^ *label */, "") graph botlab = $0 graph next graph } graph $1 == "bottom" && $2 == "ticks" { # ticks for x-axis graph for (i = 3; i <= NF; i++) bticks[++nb] = $i graph next graph } graph $1 == "left" && $2 == "ticks" { # ticks for y-axis graph for (i = 3; i <= NF; i++) lticks[++nl] = $i graph next graph } graph $1 == "range" { # xmin ymin xmax ymax graph xmin = $2; ymin = $3; xmax = $4; ymax = $5 graph next graph } graph $1 == "height" { ht = $2; next } graph $1 == "width" { wid = $2; next } graph $1 ~ number && $2 ~ number { # pair of numbers graph nd++ # count number of data points graph x[nd] = $1; y[nd] = $2 graph ch[nd] = $3 # optional plotting character graph next graph } graph $1 ~ number && $2 !~ number { # single number graph nd++ # count number of data points graph x[nd] = nd; y[nd] = $1; ch[nd] = $2 graph next graph } graph END { # draw graph graph if (xmin == "") { # no range was given graph xmin = xmax = x[1] # so compute it graph ymin = ymax = y[1] graph for (i = 2; i <= nd; i++) { graph if (x[i] < xmin) xmin = x[i] graph if (x[i] > xmax) xmax = x[i] graph if (y[i] < ymin) ymin = y[i] graph if (y[i] > ymax) ymax = y[i] graph } graph } graph frame(); ticks(); label(); data(); draw() graph } graph function frame() { # create frame for graph graph for (i = ox; i < wid; i++) plot(i, oy, "-") # bottom graph for (i = ox; i < wid; i++) plot(i, ht-1, "-") # top graph for (i = oy; i < ht; i++) plot(ox, i, "|") # left graph for (i = oy; i < ht; i++) plot(wid-1, i, "|") # right graph } graph function ticks( i) { # create tick marks for both axes graph for (i = 1; i <= nb; i++) { graph plot(xscale(bticks[i]), oy, "|") graph splot(xscale(bticks[i])-1, 1, bticks[i]) graph } graph for (i = 1; i <= nl; i++) { graph plot(ox, yscale(lticks[i]), "-") graph splot(0, yscale(lticks[i]), lticks[i]) graph } graph } graph function label() { # center label under x-axis graph splot(int((wid + ox - length(botlab))/2), 0, botlab) graph } graph function data( i) { # create data points graph for (i = 1; i <= nd; i++) graph plot(xscale(x[i]),yscale(y[i]),ch[i]=="" ? "*" : ch[i]) graph } graph function draw( i, j) { # print graph from array graph for (i = ht-1; i >= 0; i--) { graph for (j = 0; j < wid; j++) graph printf((j,i) in array ? array[j,i] : " ") graph printf("\n") graph } graph } graph function xscale(x) { # scale x-value graph return int((x-xmin)/(xmax-xmin) * (wid-1-ox) + ox + 0.5) graph } graph function yscale(y) { # scale y-value graph return int((y-ymin)/(ymax-ymin) * (ht-1-oy) + oy + 0.5) graph } graph function plot(x, y, c) { # put character c in array graph array[x,y] = c graph } graph function splot(x, y, s, i, n) { # put string s in array graph n = length(s) graph for (i = 0; i < n; i++) graph array[x+i, y] = substr(s, i+1, 1) graph } transpose # transpose - input and output suitable for graph transpose # input: data and specification of a graph transpose # output: data and specification for the transposed graph transpose transpose BEGIN { transpose number = "^[-+]?([0-9]+[.]?[0-9]*|[.][0-9]+)" \ transpose "([eE][-+]?[0-9]+)?$" transpose } transpose $1 == "bottom" && $2 == "ticks" { # ticks for x-axis transpose $1 = "left" transpose print transpose next transpose } transpose $1 == "left" && $2 == "ticks" { # ticks for y-axis transpose $1 = "bottom" transpose print transpose next transpose } transpose $1 == "range" { # xmin ymin xmax ymax transpose print $1, $3, $2, $5, $4 transpose next transpose } transpose $1 == "height" { $1 = "width"; print; next } transpose $1 == "width" { $1 = "height"; print; next } transpose $1 ~ number && $2 ~ number { nd++; print $2, $1, $3; next } transpose $1 ~ number && $2 !~ number { # single number: transpose nd++ # count data points transpose print $1, nd, $2 # fill in both x and y transpose next transpose } transpose { print } sortgen0.in descending numeric order sortgen.in field separator is : sortgen.in primary key is field 1 sortgen.in increasing alphabetic sortgen.in secondary key is field 5 sortgen.in reverse numeric sortgen # sortgen - generate sort command sortgen # input: sequence of lines describing sorting options sortgen # output: Unix sort command with appropriate arguments sortgen sortgen BEGIN { key = 0 } sortgen sortgen /no |not |n't / { print "error: can't do negatives:", $0; ok = 1 } sortgen sortgen # rules for global options sortgen { ok = 0 } sortgen /uniq|discard.*(iden|dupl)/ { uniq = " -u"; ok = 1 } sortgen /separ.*tab|tab.*sep/ { sep = "t'\t'"; ok = 1 } sortgen /separ/ { for (i = 1; i <= NF; i++) sortgen if (length($i) == 1) sortgen sep = "t'" $i "'" sortgen ok = 1 sortgen } sortgen /key/ { key++; dokey(); ok = 1 } # new key; must come in order sortgen sortgen # rules for each key sortgen sortgen /dict/ { dict[key] = "d"; ok = 1 } sortgen /ignore.*(space|blank)/ { blank[key] = "b"; ok = 1 } sortgen /fold|case/ { fold[key] = "f"; ok = 1 } sortgen /num/ { num[key] = "n"; ok = 1 } sortgen /rev|descend|decreas|down|oppos/ { rev[key] = "r"; ok = 1 } sortgen /forward|ascend|increas|up|alpha/ { next } # this is sort's default sortgen !ok { print "error: can't understand:", $0 } sortgen sortgen END { # print flags for each key sortgen cmd = "sort" uniq sortgen flag = dict[0] blank[0] fold[0] rev[0] num[0] sep sortgen if (flag) cmd = cmd " -" flag sortgen for (i = 1; i <= key; i++) sortgen if (pos[i] != "") { sortgen flag = pos[i] dict[i] blank[i] fold[i] rev[i] num[i] sortgen if (flag) cmd = cmd " +" flag sortgen if (pos2[i]) cmd = cmd " -" pos2[i] sortgen } sortgen print cmd sortgen } sortgen sortgen function dokey( i) { # determine position of key sortgen for (i = 1; i <= NF; i++) sortgen if ($i ~ /^[0-9]+$/) { sortgen pos[key] = $i - 1 # sort uses 0-origin sortgen break sortgen } sortgen for (i++; i <= NF; i++) sortgen if ($i ~ /^[0-9]+$/) { sortgen pos2[key] = $i sortgen break sortgen } sortgen if (pos[key] == "") sortgen printf("error: invalid key specification: %s\n", $0) sortgen if (pos2[key] == "") sortgen pos2[key] = pos[key] + 1 sortgen } calc1 # calc1 - reverse-Polish calculator, version 1 calc1 # input: arithmetic expressions in reverse Polish calc1 # output: values of expressions calc1 calc1 { for (i = 1; i <= NF; i++) calc1 if ($i ~ /^[+-]?([0-9]+[.]?[0-9]*|[.][0-9]+)$/) { calc1 stack[++top] = $i calc1 } else if ($i == "+" && top > 1) { calc1 stack[top-1] += stack[top]; top-- calc1 } else if ($i == "-" && top > 1) { calc1 stack[top-1] -= stack[top]; top-- calc1 } else if ($i == "*" && top > 1) { calc1 stack[top-1] *= stack[top]; top-- calc1 } else if ($i == "/" && top > 1) { calc1 stack[top-1] /= stack[top]; top-- calc1 } else if ($i == "^" && top > 1) { calc1 stack[top-1] ^= stack[top]; top-- calc1 } else { calc1 printf("error: cannot evaluate %s\n", $i) calc1 top = 0 calc1 next calc1 } calc1 if (top == 1) calc1 printf("\t%.8g\n", stack[top--]) calc1 else if (top > 1) { calc1 printf("error: too many operands\n") calc1 top = 0 calc1 } calc1 } calc2 # calc2 - reverse-Polish calculator, version 2 calc2 # input: expressions in reverse Polish calc2 # output: value of each expression calc2 calc2 { for (i = 1; i <= NF; i++) calc2 if ($i ~ /^[+-]?([0-9]+[.]?[0-9]*|[.][0-9]+)$/) { calc2 stack[++top] = $i calc2 } else if ($i == "+" && top > 1) { calc2 stack[top-1] += stack[top]; top-- calc2 } else if ($i == "-" && top > 1) { calc2 stack[top-1] -= stack[top]; top-- calc2 } else if ($i == "*" && top > 1) { calc2 stack[top-1] *= stack[top]; top-- calc2 } else if ($i == "/" && top > 1) { calc2 stack[top-1] /= stack[top]; top-- calc2 } else if ($i == "^" && top > 1) { calc2 stack[top-1] ^= stack[top]; top-- calc2 } else if ($i == "sin" && top > 0) { calc2 stack[top] = sin(stack[top]) calc2 } else if ($i == "cos" && top > 0) { calc2 stack[top] = cos(stack[top]) calc2 } else if ($i == "atan2" && top > 1) { calc2 stack[top-1] = atan2(stack[top-1],stack[top]); top-- calc2 } else if ($i == "log" && top > 0) { calc2 stack[top] = log(stack[top]) calc2 } else if ($i == "exp" && top > 0) { calc2 stack[top] = exp(stack[top]) calc2 } else if ($i == "sqrt" && top > 0) { calc2 stack[top] = sqrt(stack[top]) calc2 } else if ($i == "int" && top > 0) { calc2 stack[top] = int(stack[top]) calc2 } else if ($i in vars) { calc2 stack[++top] = vars[$i] calc2 } else if ($i ~ /^[a-zA-Z][a-zA-Z0-9]*=$/ && top > 0) { calc2 vars[substr($i, 1, length($i)-1)] = stack[top--] calc2 } else { calc2 printf("error: cannot evaluate %s\n", $i) calc2 top = 0 calc2 next calc2 } calc2 if (top == 1 && $NF !~ /\=$/) calc2 printf("\t%.8g\n", stack[top--]) calc2 else if (top > 1) { calc2 printf("error: too many operands\n") calc2 top = 0 calc2 } calc2 } calc3 # calc3 - infix calculator calc3 calc3 NF > 0 { calc3 f = 1 calc3 e = expr() calc3 if (f <= NF) printf("error at %s\n", $f) calc3 else printf("\t%.8g\n", e) calc3 } calc3 calc3 function expr( e) { # term | term [+-] term calc3 e = term() calc3 while ($f == "+" || $f == "-") calc3 e = $(f++) == "+" ? e + term() : e - term() calc3 return e calc3 } calc3 calc3 function term( e) { # factor | factor [*/] factor calc3 e = factor() calc3 while ($f == "*" || $f == "/") calc3 e = $(f++) == "*" ? e * factor() : e / factor() calc3 return e calc3 } calc3 calc3 function factor( e) { # number | (expr) calc3 if ($f ~ /^[+-]?([0-9]+[.]?[0-9]*|[.][0-9]+)$/) { calc3 return $(f++) calc3 } else if ($f == "(") { calc3 f++ calc3 e = expr() calc3 if ($(f++) != ")") calc3 printf("error: missing ) at %s\n", $f) calc3 return e calc3 } else { calc3 printf("error: expected number or ( at %s\n", $f) calc3 return 0 calc3 } calc3 } parser.in BEGIN { x = 0; y = 1 } parser.in parser.in $1 > x { if (x == y+1) { parser.in x = 1 parser.in y = x * 2 parser.in } else parser.in print x, z[x] parser.in } parser.in parser.in NR > 1 { print $1 } parser.in parser.in END { print NR } parser.in awk.parser # awk.parser - recursive-descent translator for part of awk awk.parser # input: awk program (very restricted subset) awk.parser # output: C code to implement the awk program awk.parser awk.parser BEGIN { program() } awk.parser awk.parser function advance() { # lexical analyzer; returns next token awk.parser if (tok == "(eof)") return "(eof)" awk.parser while (length(line) == 0) awk.parser if (getline line == 0) awk.parser return tok = "(eof)" awk.parser sub(/^[ \t]+/, "", line) # remove white space awk.parser if (match(line, /^[A-Za-z_][A-Za-z_0-9]*/) || # identifier awk.parser match(line, /^-?([0-9]+\.?[0-9]*|\.[0-9]+)/) || # number awk.parser match(line, /^(<|<=|==|!=|>=|>)/) || # relational awk.parser match(line, /^./)) { # everything else awk.parser tok = substr(line, 1, RLENGTH) awk.parser line = substr(line, RLENGTH+1) awk.parser return tok awk.parser } awk.parser error("line " NR " incomprehensible at " line) awk.parser } awk.parser function gen(s) { # print s with nt leading tabs awk.parser printf("%s%s\n", substr("\t\t\t\t\t\t\t\t\t", 1, nt), s) awk.parser } awk.parser function eat(s) { # read next token if s == tok awk.parser if (tok != s) error("line " NF ": saw " tok ", expected " s) awk.parser advance() awk.parser } awk.parser function nl() { # absorb newlines and semicolons awk.parser while (tok == "\n" || tok == ";") awk.parser advance() awk.parser } awk.parser function error(s) { print "Error: " s | "cat 1>&2"; exit 1 } awk.parser awk.parser function program() { awk.parser advance() awk.parser if (tok == "BEGIN") { eat("BEGIN"); statlist() } awk.parser pastats() awk.parser if (tok == "END") { eat("END"); statlist() } awk.parser if (tok != "(eof)") error("program continues after END") awk.parser } awk.parser function pastats() { awk.parser gen("while (getrec()) {"); nt++ awk.parser while (tok != "END" && tok != "(eof)") pastat() awk.parser nt--; gen("}") awk.parser } awk.parser function pastat() { # pattern-action statement awk.parser if (tok == "{") # action only awk.parser statlist() awk.parser else { # pattern-action awk.parser gen("if (" pattern() ") {"); nt++ awk.parser if (tok == "{") statlist() awk.parser else # default action is print $0 awk.parser gen("print(field(0));") awk.parser nt--; gen("}") awk.parser } awk.parser } awk.parser function pattern() { return expr() } awk.parser awk.parser function statlist() { awk.parser eat("{"); nl(); while (tok != "}") stat(); eat("}"); nl() awk.parser } awk.parser awk.parser function stat() { awk.parser if (tok == "print") { eat("print"); gen("print(" exprlist() ");") } awk.parser else if (tok == "if") ifstat() awk.parser else if (tok == "while") whilestat() awk.parser else if (tok == "{") statlist() awk.parser else gen(simplestat() ";") awk.parser nl() awk.parser } awk.parser awk.parser function ifstat() { awk.parser eat("if"); eat("("); gen("if (" expr() ") {"); eat(")"); nl(); nt++ awk.parser stat() awk.parser if (tok == "else") { # optional else awk.parser eat("else") awk.parser nl(); nt--; gen("} else {"); nt++ awk.parser stat() awk.parser } awk.parser nt--; gen("}") awk.parser } awk.parser awk.parser function whilestat() { awk.parser eat("while"); eat("("); gen("while (" expr() ") {"); eat(")"); nl() awk.parser nt++; stat(); nt--; gen("}") awk.parser } awk.parser awk.parser function simplestat( lhs) { # ident = expr | name(exprlist) awk.parser lhs = ident() awk.parser if (tok == "=") { awk.parser eat("=") awk.parser return "assign(" lhs ", " expr() ")" awk.parser } else return lhs awk.parser } awk.parser awk.parser function exprlist( n, e) { # expr , expr , ... awk.parser e = expr() # has to be at least one awk.parser for (n = 1; tok == ","; n++) { awk.parser advance() awk.parser e = e ", " expr() awk.parser } awk.parser return e awk.parser } awk.parser awk.parser function expr(e) { # rel | rel relop rel awk.parser e = rel() awk.parser while (tok ~ /<|<=|==|!=|>=|>/) { awk.parser op = tok awk.parser advance() awk.parser e = sprintf("eval(\"%s\", %s, %s)", op, e, rel()) awk.parser } awk.parser return e awk.parser } awk.parser awk.parser function rel(op, e) { # term | term [+-] term awk.parser e = term() awk.parser while (tok == "+" || tok == "-") { awk.parser op = tok awk.parser advance() awk.parser e = sprintf("eval(\"%s\", %s, %s)", op, e, term()) awk.parser } awk.parser return e awk.parser } awk.parser awk.parser function term(op, e) { # fact | fact [*/%] fact awk.parser e = fact() awk.parser while (tok == "*" || tok == "/" || tok == "%") { awk.parser op = tok awk.parser advance() awk.parser e = sprintf("eval(\"%s\", %s, %s)", op, e, fact()) awk.parser } awk.parser return e awk.parser } awk.parser awk.parser function fact( e) { # (expr) | $fact | ident | number awk.parser if (tok == "(") { awk.parser eat("("); e = expr(); eat(")") awk.parser return "(" e ")" awk.parser } else if (tok == "$") { awk.parser eat("$") awk.parser return "field(" fact() ")" awk.parser } else if (tok ~ /^[A-Za-z][A-Za-z0-9]*/) { awk.parser return ident() awk.parser } else if (tok ~ /^-?([0-9]+\.?[0-9]*|\.[0-9]+)/) { awk.parser e = tok awk.parser advance() awk.parser return "num((float)" e ")" awk.parser } else awk.parser error("unexpected " tok " at line " NR) awk.parser } awk.parser awk.parser function ident( id, e) { # name | name[expr] | name(exprlist) awk.parser if (!match(tok, /^[A-Za-z_][A-Za-z_0-9]*/)) awk.parser error("unexpected " tok " at line " NR) awk.parser id = tok awk.parser advance() awk.parser if (tok == "[") { # array awk.parser eat("["); e = expr(); eat("]") awk.parser return "array(" id ", " e ")" awk.parser } else if (tok == "(") { # function call awk.parser eat("(") awk.parser if (tok != ")") { awk.parser e = exprlist() awk.parser eat(")") awk.parser } else eat(")") awk.parser return id "(" e ")" # calls are statements awk.parser } else awk.parser return id # variable awk.parser }