| 目的 | LaTeXコマンドをまったく入力することなしに、LaTeX文書を書けたらいいな |
| 対象言語 | pLaTeX2ε 2.1.8(たぶん) |
| 記述言語 | Awk |
LaTeX(TeX)が超強力な組版言語でありプログラミング言語であること
は、コンピューター
言語研究所の他のページで紹介した本を見てもらえればお判りかと
思います。
超強力なのはうれしいのですが、(プログラミング)言語の弱点は、 したいことをするのにプログラムしなければならないというと ころです。これをある人は次のように言っています。「LaTeX(TeX)は確 かに強力だが、いちいちLaTeX(TeX)のソースを書くのは愚かである」。
その頃、仕事場にはPC9801も極めて少なく、従って○太郎なんてワー
ドプロセッサーもなく、親会社製のワードプロセッサー専用機はあった
もののやはり台数も少なく、マッキントッシュはかろうじて一台か二台
といったありさまで、文書の整形・印刷にはとても厳しい状況でした。
そんな中、MC68030を積んだUNIXワークステーションは元気で強力で、
一部の人たちはLaTeXを使って設計文書を作成していました。このパワー
をみんなに解放してあげたい。そうすれば、この「ワープロ日照り」は
ちょっとは解消されるだろう。
しかし問題は、そのためにはみんなLaTeXを使えるようにならなけれ ばならない、ということでした。慣れてくれば自由自在に書けるし、雛 形を拵えておいて使い回すこともできるでしょうが、鬱陶しいものは鬱 陶しい。みんながみんなLaTeXに興味を持っているわけではないし、ま していちいち言語を学びたいわけじゃありません。(なんと、当時は ぼくも、LaTeXには対して興味のない人間でした)
そこで、入力はできるだけ省いて、いわば「最小の労力でそこそこの
LaTeX文書を生成する」ことができるようになればいいな。
と思って作ったのが、この「報告書生成マクロ」です。
当時ぼくが入れ込んでいたAwkという言語を使って、マクロ処理系を 書きました。
マクロの仕様は、troffという植字言語に似せることにしました。
深い考えがあってのことではありません。ホントはこのマクロの仕様も
載せなければなりませんが、もうかなり昔の話で忘れているので、
ズルを決め込みます。
マクロ処理系のソースから想像してください(ひどいなあ)。
それから、何分ずいぶん昔に書いたものなので、若書きです。 悪しからずご了承ください(永遠に若書きという話はさておき)。
また、解説はちょっと勘弁してください。m(_ _)m
プログラムコードの各行の行頭についている行番号(": "まで)は参 考のためのものであり、実際のプログラムにはつきません。
1: #! /usr/local/bin/jgawk -f
2: #
3: # repgen: 報告書作成マクロプロセッサ
4: #
5: # Yukinoshin Saitoh
6: #######################################################################
7: #
8: # 【概要】
9: # 報告書などの(特に枠線のある)定型文書は
10: # LaTeXを使うときれいだけれど、
11: # LaTeXのコマンドをいちいち書き連ねるのはかったるいし、
12: # 知らない人には望むべくもない。そこで、
13: # 「簡単にLaTeXで報告書が書ける」ようにマクロを拵える。
14: # マクロはRoffのような感じになっている。
15: # また、この手法は報告書以外にも適用可能である。
16: # 【方針】
17: # ●「指令」を一切含まない文書が与えられても、
18: # 筋の通った出力を吐くこと。
19: # ●日本語LaTeX(jlatex)を利用する。
20: # ●スタイルファイルはすでに誰かが創ってくれた
21: # 報告書用のものを利用することにする。
22: # 創ってくれた人に、感謝。
23: # ●おきらくごくらく。(……)
24: #
25: # 【注意】
26: # ・このマクロプロセッサで吐き出されるTeXコマンドは、
27: # スタイルファイルに依存する部分もある(のだと思う)
28: #
29: # 【TeX特殊文字のクォート】
30: # repgenは、利用者がLaTeXを知らないものと決めつける。
31: # そのままLaTeXに送り込むと、特殊文字やコマンドと解釈される
32: # 危険のある文字(列)を(LaTeXのために)クォートする。
33: # 逆に、LaTeXコマンドを書く場合は、そのコマンドシークエンス全体を
34: # 予めrepgenとしてクォートしておく必要がある。(複雑だね)
35: # クォートには '(...)という由緒正しい表記を用いる:-)
36: #
37: # 【仕様】
38: # 三つの<モード>と、後述するマクロから構成される。
39: # ○主モード……ごく普通のモード
40: # ○字下げモード……インデントする。
41: # 行頭のタブは、“字下げのモード”と見なされる。
42: # この状態では、行揃えはなされない。
43: # 空白行か、行頭にコマンドでない文字を含む行が
44: # 現れたときに終わる。
45: # ○箇条書モード……箇条書する。
46: # 「・」で始まる行が現れると、“箇条書モード”になる。
47: # 行頭にタブを0個以上含み、
48: # 「・」か全角スペースで始まる行が続く間続く。
49: # 行頭がタブでも「・」でも全角スペースでもない文字を
50: # 含む行が現れたときに終わる。
51: #
52: # 【マクロ】
53: # マクロは行頭に書くこと。また、引数とは空白文字で区切られる。
54: # <>は必須引数を、[]は省略可能な引数を示す
55: # ●ヘッダ:これらは本文より前に現れていなければならない
56: # .ti (.title) <標題> 報告書の標題。ない場合は空白
57: # .da (.date) [日付] 発行日。ない場合はその日の日付
58: # .au (.author) <作成者> 作成者名。ない場合は空白
59: # ●文書の構成
60: # .se (.section) [題] 大見出し
61: # .ss (.subsection) [題] 小見出し
62: # ●段落、ページの制御
63: # .pp (.paragraph) [行数]
64: # 新しい段落(字下げが起こる)
65: # 行数を指定すると、その分空けて段落を始める
66: # .nl (.newline) [行数]
67: # 改行。段落は変わらない。行数の意味は段落と同じ
68: # .np (.newpage) 改ページ
69: # ●“字下げモード”
70: # 行頭のタブ “字下げモード”に入る
71: # ●書体、文字サイズ、修飾:これらはグループ化される
72: # .bo (.bold) 強調(太字)
73: # .go (.gothic) ゴシック体
74: # .la (.large) 大きい字(\Large)。書体は既定値に戻る
75: # .ul (.uline) 下線
76: # ●作表
77: # .ta (.table) [欄の幅,...]
78: # 表を作る。.zzで終わる
79: # 引数に、欄の数分、欄幅を書く
80: # ●箇条書
81: # 行頭の・ “箇条書モード”に入る
82: # ●“あるがまま”モード
83: # .as (.asis) 半角の書体をモノスペースにし、
84: # タブをスペースに展開する。.zzで終わる
85: # キャラクタで図が書ける。
86: # ソースリストや疑似コードも書ける。
87: # タイプライタ体の幅≠明朝の文字幅/2 なので、
88: # 半角と全角を混ぜるとおかしな具合になる.
89: # 日本語は、行の終わりに寄せるようにして解決
90: # ホントは、figureをマクロにするべきなんだろうな……
91: # ●コメント
92: # .;; (.comment) コメント。その行をLaTeXのコメントとして出力。
93: # ●その他
94: # .zz .go, .ul, .la, .taの終わりの目印
95: # "以上"だけの行 右寄せで出力される。(やりすぎ)
96: #
97: # 【バグ】
98: # “字下げモード”、作表の中では、マクロが使えない……
99: # マクロのエラー処理はどうしよう
100: #
101: # 【Globals】
102: # gVersion バージョン番号
103: # gTextProcessed テキストを処理したかどうか
104: # gIndentDepth 字下げの深さ
105: # gInTexQuote TeXコマンドのクォート処理
106: #
107:
108: #
109: # 初期の設定と出力. 何かしら決めておかないといけないデータを設定する
110: #
111: BEGIN{
112: gVersion = "1.01"
113: gTextProcessed = -1
114: if(ARGC == 1){
115: printf("repgen: version %s\n", gVersion);
116: exit;
117: # このexitは、けっこう危険なトリック.
118: # Awkでは、END以外の場所でexitを実行すると、
119: # (あれば)ENDアクションが実行される.
120: # そこで、「テキストを処理したよ」変数を用意して
121: # ENDアクションを制御する...
122: }
123: gTextProcessed = 0
124:
125: FS = "[ \t]+" # 欄はひとつ以上の空白またはタブで区切られる
126: date = "\\today" # 日付の既定値は、今日の日付
127: title = "\\ " # 標題の既定値は、空白(TeXコマンド)
128: author = "" # 作成者の既定値は、なし
129:
130: gIndentDepth = 0
131: gInTexQuote = 0
132:
133: # TeX文書の最初の呪文
134: # [ ]の中はスタイルファイルのオプションで、場合によって異なる
135: printf("\\documentstyle{jarticle}\n");
136: printf("\\begin{document}\n");
137: printf("\n");
138: # 初期値の出力
139: printf("\\date{%s}\n", date);
140: printf("\\title{%s}\n", title);
141: printf("\\author{%s}\n", author);
142: # インデント定義. これはスタイルファイルに書いておきたい……
143: print "";
144: printf("\\newenvironment{indentation}[1]{\\par\n");
145: printf("\\addtolength{\\leftskip}{#1}\n");
146: printf("\\begingroup}{\\endgroup\\par}\n");
147: print "";
148: ## printf("\\tt\n"); # 欧文書体をタイプライタ体にする(不要)
149: }
150:
151: #######################################################################
152: # 主モードのアクション. すべての入力行はこのアクションを通過する
153: {
154: if($0 ~ /^(\t)/){
155: new_indent_mode($0);
156: }
157: else if($0 ~ /^・/){
158: itemize_mode($0);
159: }
160: else if($0 ~ /^以上$/){
161: allover($0);
162: }
163: else if($0 ~ /^\./){ # it seems to be some macro...
164: evalcommand($0);
165: }
166: else if($0 == ""){
167: print "";
168: }
169: else{
170: normaltext($0); # 指令行でない、普通の文書行
171: }
172: }
173:
174: # 文書行を印字する
175: function normaltext(text, tmpdepth)
176: {
177: if(gIndentDepth > 0){ # something wrong
178: resetindent(0);
179: }
180: printtext(evaltext(text));
181: }
182:
183: function printtext(text)
184: {
185: print text;
186: }
187:
188: # 行頭に「.」があるものをrepgenマクロとして評価する
189: # マクロでないものはそのまま透過される
190: function evalcommand(text)
191: {
192: # $1を比較に持ち出すのは危険. textがよろしい(筈)
193: # textを配列に分解すればよろしい
194: if($1 ~ /^(\.da)|(\.date)/) {
195: macro_date(text);
196: }
197: else if($1 ~ /^(\.ti)|(\.title)/) {
198: macro_title(text);
199: }
200: else if($1 ~ /^(\.au)|(\.author)/) {
201: macro_author(text);
202: }
203: else if($1 ~ /^(\.se)|(\.section)/) {
204: macro_section(text);
205: }
206: else if($1 ~ /^(\.ss)|(\.subsection)/) {
207: macro_subsec(text);
208: }
209: else if($1 ~ /^(\.nl)|(\.newline)/) {
210: macro_newline(text);
211: }
212: else if($1 ~ /^(\.pp)|(\.paragraph)/) {
213: macro_paragraph(text);
214: }
215: else if($1 ~ /^(\.np)|(\.newpage)/) {
216: macro_newpage(text);
217: }
218: else if($1 ~ /^(\.go)|(\.gothic)/) {
219: macro_gothic(text);
220: }
221: else if($1 ~ /^(\.bo)|(\.bold)/) {
222: macro_bold(text);
223: }
224: else if($1 ~ /^(\.la)|(\.large)/) {
225: macro_large(text);
226: }
227: else if($1 ~ /^(\.ul)|(\.uline)/) {
228: macro_uline(text);
229: }
230: else if($1 ~ /^(\.ta)|(\.table)/) {
231: macro_table(text);
232: }
233: else if($1 ~ /^(\.as)|(\.asis)/) {
234: macro_asis(text);
235: }
236: # 次の三行を追加したらjgawkのSyntax Errorで
237: # yacc stack overflowと言われた. yaccの限界……?
238: # 今はもう使わないからいいけど
239: # else if($1 ~ /^(\.so)|(\.source)/) {
240: # macro_draft(text);
241: # }
242: else if($1 ~ /^(\.;;)|(\.comment)/) {
243: macro_comment(text);
244: }
245: else if($1 ~ /^(\.zz)/) {
246: macro_zz(text);
247: }
248: else{
249: printtext(evaltext(text));
250: }
251: }
252:
253: # 日付
254: function macro_date(text)
255: {
256: # 関数の中で$2とか参照しておかしくならない?
257: if(NF > 1 && $2 != ""){
258: date = $2;
259: }
260: else{
261: date = "\\today"; # TeX command
262: }
263: printf("\\date{%s}\n", date);
264: }
265:
266: # 標題. 重複してもよいらしい(TeXは気にしないようだ)ので、気にせずやる
267: function macro_title(text)
268: {
269: if(NF > 1){
270: sub(/^(\.ti)|(\.title)[ \t]+/, "", text)
271: title = evaltext(text);
272: }
273: for(getline; $0 ~ /^\t/; getline){
274: sub(/^\t+/, "");
275: title = title "\\\\" evaltext($0);
276: }
277: printf("\\title{{\\bf %s}}\n", title); # 強調体で書いてあげよう
278: # 先読みしている
279: if(ismacro($0)){
280: evalcommand($0);
281: }
282: }
283:
284: # 作成者
285: function macro_author(text)
286: {
287: if(NF > 1){
288: author = evaltext($2);
289: }
290: printf("\\author{%s}\n", author);
291: }
292:
293: # 節
294: function macro_section(text, section)
295: {
296: if(gIndentDepth > 0){
297: resetindent(0);
298: }
299: if(NF > 1){
300: sub(/^(\.se)|(\.section)[ \t]+/, "", text)
301: section = evaltext(text);
302: }
303: else{
304: section = "";
305: }
306: printf("\\section{%s}\n", section);
307: }
308:
309: # 小節
310: function macro_subsec(text, subsection)
311: {
312: if(gIndentDepth > 0){
313: resetindent(0);
314: }
315: if(NF > 1){
316: sub(/^(\.ss)|(\.subsection)[ \t]+/, "", text)
317: subsection = evaltext(text);
318: }
319: else{
320: subsection = "";
321: }
322: print "";
323: printf("\\subsection{%s}\n", subsection);
324: }
325:
326: # 改行
327: function macro_newline(text, nlines)
328: {
329: if(NF > 1 && $2 ~ /^[1-9][0-9]*$/){
330: nlines = $2;
331: }
332: else{
333: nlines = 1;
334: }
335: for(; nlines > 0; nlines--){
336: printf("\\ \\\\ \n"); # TeX command
337: }
338: }
339:
340: # 段落
341: function macro_paragraph(text, nlines)
342: {
343: if(gIndentDepth > 0){
344: resetindent(0);
345: }
346: if(NF > 1 && $2 ~ /^[1-9][0-9]*$/){
347: nlines = $2;
348: }
349: else{
350: nlines = 0;
351: }
352: for(; nlines > 0; nlines--){
353: printf("\\ \\\\ \n"); # TeX command
354: }
355: print ""; # TeX command; new paragraph
356: }
357:
358: # 改ページ
359: function macro_newpage(text)
360: {
361: if(gIndentDepth > 0){
362: resetindent(0);
363: }
364: print "";
365: printf("\\clearpage\n"); # TeX command
366: print "";
367: }
368:
369: # ゴシック体
370: function macro_gothic(target)
371: {
372: if(NF > 1){
373: sub(/^(\.go)|(\.gothic)[ \t]+/, "", target)
374: printf("{\\gt %s}\n", evaltext(target));
375: }
376: else{
377: printf("{\\gt\n");
378: }
379: }
380:
381: # 強調体
382: function macro_bold(target)
383: {
384: if(NF > 1){
385: sub(/^(\.bo)|(\.bold)[ \t]+/, "", target)
386: printf("{\\bf %s}\n", evaltext(target));
387: }
388: else{
389: printf("{\\bf\n");
390: }
391: }
392:
393: # 大きな字
394: function macro_large(target)
395: {
396: if(NF > 1){
397: sub(/^(\.la)|(\.large)[ \t]+/, "", target)
398: #printf("{\\Large\\tt %s}\n", target);
399: printf("{\\Large %s}\n", evaltext(target));
400: }
401: else{
402: #printf("{\\Large\\tt\n");
403: printf("{\\Large\n");
404: }
405: }
406:
407: # 下線
408: function macro_uline(target)
409: {
410: if(NF > 1){
411: sub(/^(\.ul)|(\.uline)[ \t]+/, "", target)
412: printf("\\underline{%s}\n", evaltext(target));
413: }
414: else{
415: printf("\\underline{\n");
416: }
417: }
418:
419: # その行をTeXのコメントとして出力. ここではクォート処理は行なわない
420: function macro_comment(text)
421: {
422: sub(/^(\.;;)|(\.comment)/, "", text)
423: printf("%%%s\n", text);
424: #for(ret = getline; ret > 0 && $1 != ".zz"; ret = getline){
425: # sub(/^(\.;;)|(\.comment)/, "", $0)
426: # printf("%%%s\n", $0);
427: #}
428: }
429:
430: # マクロの作用対象終わり
431: function macro_zz(text)
432: {
433: printf("}\n");
434: }
435:
436: #作表. これはむしろモードと呼ぶべきだね
437: function macro_table(text, tabular, ret, i, savedFS)
438: {
439: if(NF < 2){
440: tabular = "\\begin{tabular}{p{4cm}p{4cm}p{4cm}}";
441: }
442: else{
443: tabular = "\\begin{tabular}{";
444: for(i = 2; i <= NF; i++){
445: tabular = tabular sprintf("p{%dcm}", $i);
446: }
447: tabular = tabular "}";
448: }
449: printf("\\begin{center}\n");
450: printf("%s \\hline\n", tabular);
451: savedFS = FS;
452: FS = "\t+";
453: # .zzが現れるまで、テキストを吐き出す
454: # これのおかげで、コマンドを埋め込めない
455: for(ret = getline; ret > 0 && $1 != ".zz"; ret = getline){
456: #if($1 ~ /^\./){
457: # evalcommand($0);
458: #}
459: #else
460: if($1 == ""){
461: i = 2;
462: }
463: else{
464: i = 1;
465: }
466: text = "";
467: for(; i <= NF; i++){
468: # クォートした上で、連結
469: text = text evaltext($i) " & ";
470: }
471: sub(/ \& $/, "\\\\", text); # 最後の&を\\に
472: printtext(text);
473: }
474: printf(" \\hline\n");
475: printf("\\end{tabular}\n");
476: printf("\\end{center}\n\n");
477: FS = savedFS;
478: }
479:
480: #テキストを“あるがまま”に扱う. これもモードだね
481: function macro_asis(text, tabular)
482: {
483: printf("\\begin{verbatim}\n");
484: # .zzが現れるまで、テキストを吐き出す
485: for(ret = getline; ret > 0 && $1 != ".zz"; ret = getline){
486: # タブを空白に変換して出力
487: text = tab2spc($0, 8);
488: printtext(text);
489: }
490: printf("\\end{verbatim}\n");
491: }
492:
493: # 一行まるごとタブをスペースに変換
494: function tab2spc(inText, tabWidth, outText, len, iPos, oPos, spcNum)
495: {
496: outText = "";
497: oPos = 1;
498: len = length(inText);
499: for(iPos = 1; iPos <= len; iPos++){
500: if((c = jsubstr(inText, iPos, 1)) == "\t"){
501: spcNum = tabWidth - (oPos % tabWidth) + 1;
502: while(spcNum--){
503: outText = outText " ";
504: oPos++;
505: }
506: }
507: else{
508: outText = outText c;
509: oPos += length(c);
510: }
511: }
512: return outText;
513: }
514:
515: #######################################################################
516: function new_indent_mode(text)
517: {
518: printf("\\begin{verbatim}\n");
519: printtext(tab2spc(text, 8));
520: # 行頭にタブでもコマンドでもない文字が現れたときに終わる
521: for(ret = getline; ret > 0 && $0 ~ /^(\t)/; ret = getline){
522: # タブを空白に変換して出力
523: text = tab2spc($0, 8);
524: printtext(text);
525: }
526: printf("\\end{verbatim}\n");
527: # 一行先読みしている.
528: if(ismacro($0)){
529: evalcommand($0);
530: }
531: else{
532: normaltext($0);
533: }
534: }
535:
536: # “字下げ”モード
537: function indent_mode(text, tmpdepth)
538: {
539: # タブの個数を数える。一個がひとつのインデントに相当……
540: # ここには主モードからしか来ない。最初は必ず字下げが起こる
541: # だから、字下げの深さは局所変数でよい
542: tmpdepth = countdepth(text);
543: setindent(tmpdepth);
544: gIndentDepth = tmpdepth;
545: #sub(/^\t+/, "", text);
546: printf("%s\n", text);
547: # 行頭にタブでもコマンドでもない文字が現れたときに終わる
548: for(ret = getline; ret > 0 && $0 ~ /^(\t)/; ret = getline){
549: tmpdepth = countdepth($0);
550: if(tmpdepth == gIndentDepth){
551: printf("\\ \\\\\n");
552: }
553: else if(tmpdepth > gIndentDepth){
554: setindent(tmpdepth);
555: gIndentDepth = tmpdepth;
556: }
557: else if(tmpdepth < gIndentDepth){
558: resetindent(tmpdepth);
559: gIndentDepth = tmpdepth;
560: }
561: #sub(/^\t+/, "", $0);
562: printf("%s\n", evaltext($0)); # クォートする
563: }
564: # 一行先読みしている.
565: if(ismacro($0)){
566: evalcommand($0);
567: }
568: else{
569: normaltext($0);
570: }
571: }
572:
573: # 字下げをする. 【副作用】gIndentDepthがtmpdepthに等しくなる
574: function setindent(tmpdepth)
575: {
576: for(; gIndentDepth < tmpdepth; gIndentDepth++){
577: printf("\\begin{indentation}{40pt}\n");
578: printf("\\noindent\n");
579: }
580: }
581:
582: # 字下げを取り止める. 【副作用】gIndentDepthがtmpdepthに等しくなる
583: function resetindent(tmpdepth)
584: {
585: for(; gIndentDepth > tmpdepth; gIndentDepth--){
586: printf("\\end{indentation}\n");
587: printf("\\noindent\n");
588: }
589: }
590:
591: # 先頭のタブの個数(字下げの深さ)を数える
592: function countdepth(text, len, count, n)
593: {
594: len = length(text);
595: count = 0;
596: for(n = 1; n < len; n++){
597: # 93.07.30 debug. タブでないものが現れたらおしまい
598: if(substr(text, n, 1) != "\t"){
599: break;
600: }
601: count++;
602: }
603: return count;
604: }
605:
606: #######################################################################
607: #箇条書モード
608: function itemize_mode(text, itemdepth, depth, ret)
609: {
610: itemdepth = 0;
611: printf("\\begin{itemize}\n");
612: # この先、再帰プロセス
613: sub(/^・/, "", text);
614: printtext(sprintf("\\item\t%s", text));
615: # タブか「・」か「 」が続く間、、テキストを吐き出す
616: # この仕様のおかげで、コマンドを埋め込むことができる……
617: ret = getline;
618: for(; ret > 0 && $0 ~ /^(\t)|・| |(\.)/; ret = getline){
619: if(ismacro($0)){
620: evalcommand($0);
621: continue;
622: }
623: depth = countdepth($0);
624: if(itemdepth < depth && $0 ~ /^\t*・/){
625: printf("\\begin{itemize}\n");
626: # 自分を呼ぶ
627: itemdepth++;
628: }
629: else if(itemdepth > depth && $0 ~ /^\t*・/){
630: for(; itemdepth > depth; itemdepth--){
631: printf("\\end{itemize}\n");
632: }
633: }
634: # タブを取り去り、先頭文字を見て決める
635: sub(/^\t+/, "", $0);
636: if($0 ~ /^・/){
637: sub(/^・/, "", $0);
638: text = $0;
639: printtext(sprintf("\\item\t%s", evaltext(text)));
640: }
641: else{ # if($0 ~ /^ /)
642: sub(/^ /, "", $0);
643: text = $0;
644: printtext(sprintf("\t%s", evaltext(text)));
645: }
646: }
647: for(; itemdepth > 0; itemdepth--){
648: printf("\\end{itemize}\n");
649: }
650: printf("\\end{itemize}\n\n");
651: # 一行先読みしている. が、それがマクロである可能性はない
652: if(ismacro($0)){
653: evalcommand($0);
654: }
655: else{
656: normaltext($0);
657: }
658: }
659:
660: #######################################################################
661: # テキストに現れるTeXコマンド、メタキャラクタをクォートする
662: # また、クォートされた文字列を評価しないようにする
663: function evaltext(text, otext, len, n, c)
664: {
665: # メタキャラクタは以下のとおり
666: # # コマンドや環境の引数 -> \#
667: # $ 数式モードと他のモードの区切り -> \$
668: # & 表の要素の区切り -> \&
669: # ~ 改行しない単語間スペース -> \tt\symbol{"7e}
670: # _ 数式モードでの下つき添え字 -> \_
671: # ^ 数式モードでの上つき添え字 -> \tt\symbol{"5e}
672: # \ コマンドの先頭 -> \tt\symbol{"5c}
673: # % コメントの開始 -> \%
674: # { グループ化または引数の開始 -> \{
675: # } グループ化または引数の終了 -> \}
676: #
677: # ほかに、次の文字も危ない
678: # < さかさまの!(\tt\symbol{"3c}でクォート……)
679: # > さかさまの?(\tt\symbol{"3e}でクォート……)
680: #
681: # また、'(..maybe TeX command..)という文字列を見つけると、
682: # 上のような評価をせず、そのまま送り出す
683:
684: len = length(text);
685: otext = "";
686: for(n = 1; n <= len; n++){
687: c = jsubstr(text, n, 1);
688: if(gInTexQuote){
689: if(c == "("){
690: gInTexQuote++;
691: }
692: else if(c == ")"){
693: gInTexQuote--;
694: if(gInTexQuote == 0){
695: c = ""; # 閉じ括弧を取り除く
696: }
697: }
698: otext = otext c;
699: }
700: else if(c == "'" && jsubstr(text, n+1, 1) == "("){
701: # クォート記号の2バイトを取り除く
702: n ++;
703: gInTexQuote = 1;
704: }
705: else{
706: otext = otext quote(c);
707: }
708: }
709:
710: return otext;
711: }
712:
713: # 文字をクォートする. クォートしない
714: function quote(c, q)
715: {
716: if(c == "#"){
717: q = "\\#";
718: }
719: else if(c == "$"){
720: q = "\\$";
721: }
722: else if(c == "%"){
723: q = "\\%";
724: }
725: else if(c == "^"){
726: q = "{\\tt \\symbol{94}}";
727: }
728: else if(c == "&"){
729: q = "\\&";
730: }
731: else if(c == "_"){
732: q = "\\_";
733: }
734: else if(c == "~"){
735: q = "{\\tt \\symbol{112}}";
736: }
737: else if(c == "\\"){
738: q = "{\\tt \\symbol{92}}";
739: }
740: else if(c == "{"){
741: q = "\\{";
742: }
743: else if(c == "}"){
744: q = "\\}";
745: }
746: else if(c == "<"){
747: q = "{\\tt \\symbol{60}}";
748: }
749: else if(c == ">"){
750: q = "{\\tt \\symbol{62}}";
751: }
752: else{
753: q = c;
754: }
755: return q;
756: }
757:
758: # 行頭に現れる「以上」を右寄せで印刷させる
759: function allover(text)
760: {
761: print "";
762: printf("\\begin{flushright}\n");
763: print text;
764: printf("\\end{flushright}\n");
765: }
766:
767: # マクロかどうか?
768: function ismacro(text)
769: {
770: if(text ~ /^\./){
771: return 1;
772: }
773: return 0;
774: }
775:
776: # 後始末
777: END{
778: if(gTextProcessed == -1){
779: exit;
780: }
781: # もし字下げがされたままだったら、直す
782: if(gIndentDepth > 0){
783: print "";
784: resetindent(0);
785: }
786: # TeX文書の最後の呪文
787: print "";
788: printf("\\end{document}\n");
789: }
790:
791: # end of repgen
(2000.08.10)
(C) ©Copyright Noboru HIWAMATA (nulpleno). All rights reserved.