%% %% This is file `langsci-avm.sty', %% generated with the docstrip utility. %% %% The original source files were: %% %% langsci-avm.dtx (with options: `package') %% ------------------------------------------------------------------------------ %% %% A package for typesetting feature structures, also known as attribute-value %% matrices (AVMs), for use in linguistics. %% %% The package provides a minimal and easy to read syntax. It depends only on the %% array package and can be placed almost everywhere, in particular in footnotes or %% graphs and tree structures. The package serves the same purpose as, Christopher %% Manning’s avm package, but shares no code base with that package. %% %% Copyright (C) 2023 by Felix Kopecky, Language Science Press %% %% This work consists of the file langsci-avm.dtx %% and the derived file langsci-avm.pdf. %% %% It may be distributed and/or modified under the conditions of the %% LaTeX Project Public License (LPPL), either version 1.3c of this %% license or (at your option) any later version. The latest version %% of this license is at . %% %% This work is ``maintained'' (per LPPL maintenance status) by %% Felix Kopecky . %% %% The development version can be found at %% %% https://github.com/langsci/langsci-avm %% %% for those people who are interested. Pull requests are welcome. %% %% Please report any bugs or feature requests to %% %% https://github.com/langsci/langsci-avm/issues %% %% ------------------------------------------------------------------------------ \RequirePackage{xparse}[2022/03/26] \RequirePackage{array} \ProvidesExplPackage {langsci-avm} {2023-02-20} {0.3.0} {AVMs and feature structures} \msg_new:nnnn {avm} {lfgoptionmissing} { Missing~package~option~lfg~at~line~\msg_line_number: } { You~issued~a~command~in~line~\msg_line_number:~that~is~only~available~when~ the~lfg~package~option~is~enabled. } \msg_new:nnnn {avm} {idpositionunknown} { Unkown~value~for~option~`id~position`~near~line~\msg_line_number:. } { You~specified~an~unknown~value~for~option~`id~position`.~The~content~of~ the~id~could~not~be~output.~Please~see~the~manual~for~a~list~of~valid~ settings. } \bool_new:N \l__avm_lfg_bool \bool_new:N \l__avm_tikz_bool \DeclareOption{tikz}{ \bool_set_true:N \l__avm_tikz_bool } \DeclareOption{lfg}{ \bool_set_true:N \l__avm_lfg_bool } \ProcessOptions\relax \bool_if:NT \l__avm_tikz_bool { \RequirePackage{tikz} \newcounter{l__avm_picture_counter} \tl_new:N \l__avm_picture_name_prefix_tl } \bool_if:NT \l__avm_lfg_bool { \cs_if_exist:NF \lBrack { \RequirePackage{etoolbox} \AtEndPreamble { \RequirePackage{unicode-math} } } } \NewDocumentCommand{\avm}{ O{} +m } { \c_group_begin_token \keys_set:nn { avm } { #1 } \__avm_initialise_document_commands: \__avm_initialise_custom_commands: \tl_use:N \l__avm_defined_commands_tl \__avm_mode_switch: \__avm_parse:n { #2 } \c_group_end_token } \bool_new:N \l__avm_mode_bool \seq_new:N \l__avm_parens_tracker \tl_new:N \l__avm_defined_commands_tl \box_new:N \l__avm_fillmore_kay_box \tl_new:N \l__avm_parsed_tl \int_new:N \l__avm_mode_switch_character_int \NewDocumentCommand{\avmsetup}{ m } { \keys_set:nn { avm } { #1 } } \keys_define:nn { avm } { align .bool_set:N = \l__avm_align_bool, align .initial:n = {true}, stretch .tl_set:N = \l__avm_arraystretch_tl, stretch .initial:n = {0.9}, columnsep .dim_set:N = \l__avm_tabcolsep_dim, columnsep .initial:n = {.5ex}, vectorsep .dim_set:N = \l__avm_singlesep_dim, vectorsep .initial:n = {1em}, delimfactor .int_set:N = \l__avm_delimfactor_int, delimfactor .initial:n = {1000}, delimfall .dim_set:N = \l__avm_delimshortfall_dim, delimfall .initial:n = {0pt}, framewidth .dim_set:N = \l__avm_fillmore_kay_boxrule_dim, framewidth .initial:n = {1pt}, framesep .dim_set:N = \l__avm_fillmore_kay_boxsep_dim, framesep .initial:n = {3pt}, attributes .code:n = {\cs_set:Nn \__avm_font_attribute: {#1}}, attributes .initial:n = {\scshape}, types .code:n = {\cs_set:Nn \__avm_font_type: {#1}}, types .initial:n = {\itshape}, values .code:n = {\cs_set:Nn \__avm_font_value: {#1}}, values .initial:n = {\itshape}, tags .code:n = {\cs_set:Nn \__avm_font_tag: {#1}}, tags .initial:n = {\footnotesize}, singleton .code:n = {\cs_set:Nn \__avm_font_singleton: {#1}}, singleton .initial:n = {\normalfont}, switch .code:n = { \tl_set:Nn \l__avm_mode_switch_character {#1} \exp_args:NNx \int_set:Nn \l__avm_mode_switch_character_int {`\tl_use:N \l__avm_mode_switch_character} }, switch .initial:n = { ! }, extraskip .dim_set:N = \l__avm_extra_skip_dim, extraskip .initial:n = {\smallskipamount}, extraskip~in~every~row .bool_set:N = \l__avm_extraskip_bool, customise .code:n = {\cs_set:Nn \__avm_initialise_custom_commands: {#1}}, customise .initial:n = { }, pic .bool_set:N = \l__avm_picture_bool, pic .default:n = { true }, picname .tl_set:N = \l__avm_picture_name_tl, picname .initial:n = {automatic}, id~align .code:n = { \newcolumntype{i}{#1} }, id~align .initial:n = {l}, id~position .tl_set:N = \l__avm_id_position_tl, id~position .initial:n = {south-west}, style .choice:, style / narrow .code:n = {\int_set:Nn \l__avm_delimfactor_int {997} \dim_set:Nn \l__avm_delimshortfall_dim {5pt}}, } \NewDocumentCommand{\avmdefinestyle}{ m m } { \keys_define:nn { avm } { style / #1 .code:n = { \keys_set:nn { avm } { #2 } } } } \NewDocumentCommand{\avmdefinecommand}{ m O{} m } { \tl_put_right:Nn \l__avm_defined_commands_tl { \exp_args:Nc \DeclareDocumentCommand { #1 } { s } { #2 \IfBooleanF { ##1 } { & } \avmsetup{ #3 } } } } \cs_generate_variant:Nn \tl_if_eq:nnTF {VnTF} \bool_new:N \l__avm_in_first_column \cs_new:Nn \__avm_init_first_column: { \bool_set_true:N \l__avm_in_first_column \normalfont\__avm_font_attribute: } \cs_new:Nn \__avm_init_second_column: { \bool_set_false:N \l__avm_in_first_column \normalfont\__avm_font_value: } \cs_new:Nn \__avm_init_single_column: { \normalfont\__avm_font_attribute: } \tl_const:Nn \l__avm_italics_tl {it} \cs_new:Nn \__avm_deinit_first_column: { \tl_if_eq:NNT \f@shape \l__avm_italics_tl {\/} } \cs_new:Nn \__avm_deinit_second_column: { \tl_if_eq:NNT \f@shape \l__avm_italics_tl {\/} } \cs_new:Nn \__avm_deinit_single_column: { \tl_if_eq:NNT \f@shape \l__avm_italics_tl {\/} } \cs_new:Nn \__avm_kern_unused_columns: { \bool_if:NTF \l__avm_in_first_column { \span\hspace*{-2\tabcolsep} } { } } \cs_new:Nn \__avm_extra_skip: { \peek_meaning_ignore_spaces:NTF \\ {\vspace*{\l__avm_extra_skip_dim}} {} } \cs_new:Nn \__avm_module_begin: { \bool_if:NTF \l__avm_align_bool { \begin{tabular}{@{} >{\__avm_init_first_column:}l <{\__avm_deinit_first_column:} >{\__avm_init_second_column:}l <{\__avm_deinit_second_column:} @{}} } { \begin{tabular}{@{} >{\__avm_init_single_column:}l <{\__avm_deinit_single_column:} @{}} } } \cs_new:Nn \__avm_module_end: { \__avm_kern_unused_columns: \end{tabular} } \cs_new:Nn \__avm_replace_ampersand: { \bool_if:NTF \l__avm_align_bool { \tl_build_put_right:Nn \l__avm_parsed_tl { & } } { \tl_build_put_right:Nn \l__avm_parsed_tl { \exp_not:n { \__avm_deinit_first_column:\skip_horizontal:N \dim_use:N \l__avm_singlesep_dim \__avm_init_second_column: } } } } \cs_new:Nn \__avm_replace_lbrace: { \c_math_toggle_token\left\lbrace\__avm_module_begin: } \cs_new:Nn \__avm_replace_rbrace: { \__avm_module_end:\right\rbrace\c_math_toggle_token\__avm_extra_skip: } \cs_new:Nn \__avm_replace_lbrack: { \tl_build_put_right:Nn \l__avm_parsed_tl { \exp_not:n { \bool_if:NTF \l__avm_mode_bool { \c_math_toggle_token\left\lbrack\__avm_module_begin: } { [ } } } } \cs_new:Nn \__avm_replace_rbrack: { \tl_build_put_right:Nn \l__avm_parsed_tl { \exp_not:n { \bool_if:NTF \l__avm_mode_bool { \__avm_module_end:\right\rbrack\c_math_toggle_token% \__avm_extra_skip: } { ] } } } } \bool_if:NTF \l__avm_lfg_bool { \cs_new:Nn \__avm_replace_llbrack: { \c_math_toggle_token\left\lBrack\__avm_module_begin: } \cs_new:Nn \__avm_replace_rrbrack: { \__avm_module_end:\right\rBrack\c_math_toggle_token\__avm_extra_skip: } } { \cs_new:Nn \__avm_replace_llbrack: { \tl_build_put_right:Nn \l__avm_parsed_tl { \exp_not:n { \msg_warning:nn {avm}{lfgoptionmissing} \c_math_toggle_token\left.\__avm_module_begin: } } } \cs_new:Nn \__avm_replace_rrbrack: { \tl_build_put_right:Nn \l__avm_parsed_tl { \exp_not:n { \msg_warning:nn {avm}{lfgoptionmissing} \__avm_module_end:\right.\c_math_toggle_token\__avm_extra_skip: } } } } \cs_new:Nn \__avm_replace_lparen: { \tl_build_put_right:Nn \l__avm_parsed_tl { \exp_not:n { \bool_if:NTF \l__avm_mode_bool { \c_math_toggle_token\left(\__avm_module_begin: } { ( } } } } \cs_new:Nn \__avm_replace_rparen: { \tl_build_put_right:Nn \l__avm_parsed_tl { \exp_not:n { \bool_if:NTF \l__avm_mode_bool { \__avm_module_end:\right)\c_math_toggle_token\__avm_extra_skip: } { ) } } } } \cs_new:Nn \__avm_replace_langle: { \tl_build_put_right:Nn \l__avm_parsed_tl { \exp_not:n { \bool_if:NTF \l__avm_mode_bool { \c_math_toggle_token\left<\__avm_module_begin: } { < } } } } \cs_new:Nn \__avm_replace_rangle: { \tl_build_put_right:Nn \l__avm_parsed_tl { \exp_not:n { \bool_if:NTF \l__avm_mode_bool { \__avm_module_end:\right>\c_math_toggle_token\__avm_extra_skip: } { > } } } } \cs_new:Nn \__avm_replace_lframe: { \hbox_set:Nw \l__avm_fillmore_kay_box \group_begin: \c_math_toggle_token\__avm_module_begin: } \cs_new:Nn \__avm_replace_rframe: { \__avm_module_end:\c_math_toggle_token\group_end:\hbox_set_end: \group_begin: \dim_set_eq:NN \fboxrule \l__avm_fillmore_kay_boxrule_dim \dim_set_eq:NN \fboxsep \l__avm_fillmore_kay_boxsep_dim \fbox{\box_use:N \l__avm_fillmore_kay_box} \group_end: \__avm_extra_skip: } \cs_new:Nn \__avm_replace_plus: { \leavevmode\unskip\hbox{${}\oplus{}$}\ignorespaces } \cs_new:Nn \__avm_replace_minus: { \leavevmode\unskip\hbox{${}\ominus{}$}\ignorespaces } \cs_new:Nn \__avm_replace_circle: { \leavevmode\unskip\hbox{${}\bigcirc{}$}\ignorespaces } \cs_new:Npn \__avm_controls_tag:n #1 { \fboxsep.25ex\fboxrule.4pt\fbox{\normalfont\__avm_font_tag: #1} } \cs_new:Npn \__avm_controls_type:n #1 { \c_group_begin_token\normalfont\__avm_font_type: #1\c_group_end_token } \cs_new_protected:Npn \__avm_controls_type_starred:n #1 { \bool_set_false:N \l__avm_in_first_column \normalfont\__avm_font_type: #1 \bool_if:NTF \l__avm_align_bool { \__avm_deinit_second_column:\span\hspace*{-2\tabcolsep} } { \__avm_deinit_single_column:} \peek_meaning_ignore_spaces:NTF \\ {} {\\} } \cs_new_protected:Npn \__avm_controls_punk:nn #1 #2 { \bool_set_false:N \l__avm_in_first_column \normalfont\c_group_begin_token\__avm_font_attribute:#1% \c_group_end_token\hspace{2\tabcolsep}% \c_group_begin_token\__avm_font_value: #2\c_group_end_token% \__avm_deinit_second_column:\span\hspace*{-2\tabcolsep} \peek_charcode_ignore_spaces:NTF \\ {} {\\} } \cs_new:Nn \__avm_mode_switch: { \bool_set_inverse:N \l__avm_mode_bool \bool_if:NTF \l__avm_mode_bool { \DeclareDocumentCommand{\{}{}{ \__avm_replace_lbrace: } \DeclareDocumentCommand{\}}{}{ \__avm_replace_rbrace: } \DeclareDocumentCommand{\[}{}{ \__avm_replace_llbrack: } \DeclareDocumentCommand{\]}{}{ \__avm_replace_rrbrack: } \DeclareDocumentCommand{\+}{}{ \__avm_replace_plus: } \DeclareDocumentCommand{\-}{}{ \__avm_replace_minus: } } { \DeclareCommandCopy{\{}{\__avm_old_lbrace_store:} \DeclareCommandCopy{\}}{\__avm_old_rbrace_store:} \DeclareCommandCopy{\[}{\__avm_old_llbrack_store:} \DeclareCommandCopy{\]}{\__avm_old_rrbrack_store:} \DeclareCommandCopy{\+}{\__avm_old_plus_store:} \DeclareCommandCopy{\-}{\__avm_old_minus_store:} } } \cs_new:Nn \__avm_initialise_document_commands: { \DeclareCommandCopy{\__avm_old_lbrace_store:}{\{} \DeclareCommandCopy{\__avm_old_rbrace_store:}{\}} \DeclareCommandCopy{\__avm_old_llbrack_store:}{\[} \DeclareCommandCopy{\__avm_old_rrbrack_store:}{\]} \DeclareCommandCopy{\__avm_old_plus_store:}{\+} \DeclareCommandCopy{\__avm_old_minus_store:}{\-} \def\arraystretch{\tl_use:N \l__avm_arraystretch_tl} \dim_set_eq:NN \tabcolsep \l__avm_tabcolsep_dim \int_set_eq:NN \delimiterfactor \l__avm_delimfactor_int \dim_set_eq:NN \delimitershortfall \l__avm_delimshortfall_dim \DeclareDocumentCommand{\shuffle}{}{ \__avm_replace_shuffle: } \DeclareDocumentCommand{\lframe}{}{ \__avm_replace_lframe: } \DeclareDocumentCommand{\rframe}{}{ \__avm_replace_rframe: } \DeclareDocumentCommand{\tag}{m}{ \__avm_controls_tag:n {##1} } \DeclareDocumentCommand{\0}{}{ \__avm_controls_tag:n {0} } \DeclareDocumentCommand{\1}{}{ \__avm_controls_tag:n {1} } \DeclareDocumentCommand{\2}{}{ \__avm_controls_tag:n {2} } \DeclareDocumentCommand{\3}{}{ \__avm_controls_tag:n {3} } \DeclareDocumentCommand{\4}{}{ \__avm_controls_tag:n {4} } \DeclareDocumentCommand{\5}{}{ \__avm_controls_tag:n {5} } \DeclareDocumentCommand{\6}{}{ \__avm_controls_tag:n {6} } \DeclareDocumentCommand{\7}{}{ \__avm_controls_tag:n {7} } \DeclareDocumentCommand{\8}{}{ \__avm_controls_tag:n {8} } \DeclareDocumentCommand{\9}{}{ \__avm_controls_tag:n {9} } \DeclareDocumentCommand{\type}{s m} { \IfBooleanTF { ##1 } { \__avm_controls_type_starred:n {##2} } { \__avm_controls_type:n {##2} } } \DeclareDocumentCommand{\punk}{m m}{ \__avm_controls_punk:nn {##1}{##2} } \DeclareDocumentCommand{\id}{m m} {% \hcoffin_set:Nw \l_tmpa_coffin \bgroup \def\arraystretch{.5} \begin{tabular}[b]{@{}>{$\scriptstyle}i<{$}@{}} ##1 \end{tabular} \egroup \hcoffin_set_end: \hcoffin_set:Nw \l_tmpb_coffin ##2 \hcoffin_set_end: \tl_if_eq:VnTF \l__avm_id_position_tl {south-west} {% \coffin_join:NnnNnnnn \l_tmpb_coffin {l}{H} \l_tmpa_coffin {r}{H}{ 0pt }{ -\coffin_dp:N \l_tmpb_coffin } } {% \tl_if_eq:VnTF \l__avm_id_position_tl {south-east} {% \coffin_join:NnnNnnnn \l_tmpb_coffin {l}{H} \l_tmpa_coffin {l}{H}{ \coffin_wd:N \l_tmpb_coffin } { -\coffin_dp:N \l_tmpb_coffin } } { \msg_error:nn {avm}{idpositionunknown} } } \coffin_typeset:Nnnnn \l_tmpb_coffin {l}{vc}{0pt}{0pt} } \DeclareDocumentEnvironment{scope}{ +m } { \group_begin: \keys_set:nn { avm } { ##1 } \ignorespaces } { \group_end: } \bool_if:NT \l__avm_tikz_bool { \tl_if_eq:VnTF \l__avm_picture_name_tl {automatic} { \stepcounter{l__avm_picture_counter} \tl_set:Nn \l__avm_picture_name_prefix_tl {avm-\tl_use:N \thel__avm_picture_counter} } { \tl_set_eq:NN \l__avm_picture_name_prefix_tl \l__avm_picture_name_tl } \DeclareDocumentCommand{\node}{m m} { \tikz [remember~picture, baseline=(\l__avm_picture_name_prefix_tl-##1.base)] \node [inner~sep=0pt] (\l__avm_picture_name_prefix_tl-##1) {\strut ##2}; } } } \cs_new:Npn \__avm_parse:n #1 { \group_align_safe_begin: \tl_build_begin:N \l__avm_parsed_tl \tl_build_put_right:Nn \l__avm_parsed_tl { \exp_not:n {\ignorespaces} } \tl_analysis_map_inline:nn { #1 } { \int_case:nnF { ##2 } { { `& }{ \__avm_replace_ampersand: } { `[ }{ \__avm_replace_lbrack: } { `] }{ \__avm_replace_rbrack: } { `( }{ \__avm_replace_lparen: } { `) }{ \__avm_replace_rparen: } { `< }{ \__avm_replace_langle: } { `> }{ \__avm_replace_rangle: } { \l__avm_mode_switch_character_int } { \tl_build_put_right:Nn \l__avm_parsed_tl { \exp_not:n { \__avm_mode_switch: } } } } { \tl_build_put_right:Nn \l__avm_parsed_tl { ##1 } } } \tl_build_end:N \l__avm_parsed_tl \tl_set:Nx \l__avm_parsed_tl {\l__avm_parsed_tl} \tl_use:N \l__avm_parsed_tl \group_align_safe_end: } %% %% %% End of file `langsci-avm.sty'.